2008-10-16 6 views
23

Musimy napisać testy jednostkowe dla aplikacji wxWidgets przy użyciu Google Test Framework. Problem polega na tym, że wxWidgets używa makra IMPLEMENT_APP (MyApp), aby zainicjować i wprowadzić główną pętlę aplikacji. To makro tworzy kilka funkcji, w tym int main(). Struktura testowa Google używa również definicji makr dla każdego testu.wxWidgets: Jak zainicjować wxApp bez użycia makr i bez wprowadzania głównej pętli aplikacji?

Jednym z problemów jest to, że nie jest możliwe wywołanie makra wxWidgets od wewnątrz makra testu, ponieważ pierwszy z nich tworzy funkcje .. Tak, okazało się, że możemy wymienić makro z następującego kodu:

wxApp* pApp = new MyApp(); 
wxApp::SetInstance(pApp); 
wxEntry(argc, argv); 

Jest to dobry zamiennik, ale wywołanie wxEntry() wchodzi do oryginalnej pętli aplikacji. Jeśli nie wywołasz metody wxEntry(), niektóre części aplikacji nie zostaną zainicjalizowane.

Pytanie, w jaki sposób zainicjować wszystko, co wymagane do uruchomienia wxApp, bez faktycznego uruchamiania go, abyśmy mogli przetestować jego część?

Odpowiedz

4

Chcesz skorzystać z funkcji:

bool wxEntryStart(int& argc, wxChar **argv) 

zamiast wxEntry. Nie wywołuje OnInit() ani nie uruchamia głównej pętli.

Możesz zadzwonić pod numer wxTheApp->CallOnInit(), aby wywołać funkcję OnInit() w razie potrzeby w testach.

Musisz użyć

void wxEntryCleanup() 

kiedy skończysz.

+0

Właściwie to nie działa. Aplikacja nie została jeszcze zainicjowana. –

+0

Czy możesz dokładniej określić, co oznacza "nie zainicjowany"? Jeśli przeczytasz kod źródłowy, zobaczysz, że wxEntry naprawdę nie robi nic więcej niż wywołanie wxEntryStart(), a następnie wywołanie "OnInit()" i "OnRun()". Sądzę, że chciałbyś wywołać OnInit() ręcznie w twoich testach. – kbluck

+0

OK, to coś, czego mi brakowało - OnInit(). Spróbuję tego. –

-1

Można ewentualnie zmienić tę sytuację:

przygotować i uruchomić aplikację wxPython tym pętli głównej, a następnie uruchomić testy jednostkowe od wewnątrz aplikacji. Myślę, że jest funkcja wywoływana po wejściu do pętli głównej, po zakończeniu wszystkich czynności init.

+0

Celem jest, aby przetestować aplikację z UT, nie UT z aplikacji –

+0

Chyba, że ​​znajdzie sposób, aby wykonać kompletną init (i do tej pory nikt nie zaproponował praktyczne rozwiązanie) cel, który był w powyższym komentarzu można równie dobrze osiągnąć. Podobne rzeczy robiłem już w wxPythonie. – Ber

+0

+1 ode mnie, tak właśnie zrobiłem moje testy w wxWidgets po próbie rozwiązania problemu samemu. – SteveL

-2

Czy próbowałeś makro IMPLEMENT_APP_NO_MAIN? Komentarz umieszczony powyżej definicji makra sugeruje, że może zrobić to, czego potrzebujesz. źródło

z < wxWidgets' reż > \ include \ wx.h:

// Use this macro if you want to define your own main() or WinMain() function 
// and call wxEntry() from there. 
#define IMPLEMENT_APP_NO_MAIN(appname)          \ 
    wxAppConsole *wxCreateApp()            \ 
    {                  \ 
     wxAppConsole::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE,   \ 
             "your program");     \ 
     return new appname;             \ 
    }                  \ 
    wxAppInitializer              \ 
     wxTheAppInitializer((wxAppInitializerFunction) wxCreateApp);  \ 
    DECLARE_APP(appname)             \ 
    appname& wxGetApp() { return *wx_static_cast(appname*, wxApp::GetInstance()); } 
+0

To makro jest zredukowane do pierwszych dwóch wierszy kodu w pytaniu. Problem polega na tym, że przed wywołaniem metody wxEntry() niektóre części wxApp nadal nie są inicjowane. wxEntry() wchodzi w pętlę aplikacji, a kontrola jest przekazywana do wxWidgets. Chciałbym zainicjować wxApp, bez uruchamiania go. –

10

Właśnie to przeżyłem z 2.8.10. Magia jest taka:

// MyWxApp derives from wxApp 
wxApp::SetInstance(new MyWxApp()); 
wxEntryStart(argc, argv); 
wxTheApp->OnInit(); 

// you can create top level-windows here or in OnInit() 
... 
// do your testing here 

wxTheApp->OnRun(); 
wxTheApp->OnExit(); 
wxEntryCleanup(); 

Można po prostu utworzyć instancję wxApp aniżeli wynikające własną klasę stosując powyższy technikę.

Nie jestem pewien, w jaki sposób można przeprowadzić testowanie jednostkowe aplikacji bez wchodzenia do głównego poziomu, ponieważ wiele komponentów wxWidgets wymaga dostarczenia zdarzeń do działania. Typowe podejście polegałoby na uruchomieniu testów jednostkowych po wejściu w pętlę główną.

1

Wygląda na to, że wykonanie testów w funkcji wxApp :: OnRun() może działać. Oto kod testujący tytuł okna z cppUnitLite2.

 
#include "wx/wxprec.h" 

#ifdef __BORLANDC__ 
#pragma hdrstop 
#endif 

#ifndef WX_PRECOMP 
    #include "wx/wx.h" 
#endif 
#include "wx/app.h" // use square braces for wx includes: I made quotes to overcome issue in HTML render 
#include "wx/Frame.h" 
#include "../CppUnitLite2\src/CppUnitLite2.h" 
#include "../CppUnitLite2\src/TestResultStdErr.h" 
#include "../theAppToBeTested/MyDialog.h" 
TEST (MyFirstTest) 
{ 
    // The "Hello World" of the test system 
    int a = 102; 
    CHECK_EQUAL (102, a); 
} 

TEST (MySecondTest) 
{ 
    MyDialog dlg(NULL); // instantiate a class derived from wxDialog 
    CHECK_EQUAL ("HELLO", dlg.GetTitle()); // Expecting this to fail: title should be "MY DIALOG" 
} 

class MyApp: public wxApp 
{ 
public: 
    virtual bool OnInit(); 
    virtual int OnRun(); 
}; 

IMPLEMENT_APP(MyApp) 

bool MyApp::OnInit() 
{ 
    return true; 
} 

int MyApp::OnRun() 
{ 
    fprintf(stderr, "====================== Running App Unit Tests =============================\n"); 
    if (!wxApp::OnInit()) 
     return false; 

    TestResultStdErr result; 
    TestRegistry::Instance().Run(result); 
    fprintf(stderr, "====================== Testing end: %ld errors =============================\n", result.FailureCount()); 

    return result.FailureCount(); 
} 
2
IMPLEMENT_APP_NO_MAIN(MyApp); 
IMPLEMENT_WX_THEME_SUPPORT; 

int main(int argc, char *argv[]) 
{ 
    wxEntryStart(argc, argv); 
    wxTheApp->CallOnInit(); 
    wxTheApp->OnRun(); 

    return 0; 
} 
Powiązane problemy