wxWidgets: Como inicializar wxApp sem usar macros e sem entrar no loop principal da aplicação?
-
03-07-2019 - |
Pergunta
Precisamos de escrever testes de unidade para um wxWidgets aplicativo usando Google framework de teste . O problema é que wxWidgets usa a macro IMPLEMENT_APP (MyApp) para inicializar e entrar no ciclo principal do aplicativo. Esta macro cria várias funções, incluindo int main () . O framework de teste do Google também usa definições de macro para cada teste.
Um dos problemas é que não é possível chamar os wxWidgets macro de dentro do macro teste, porque o primeiro cria funções .. Então, descobrimos que poderíamos substituir a macro com o seguinte código:
wxApp* pApp = new MyApp();
wxApp::SetInstance(pApp);
wxEntry(argc, argv);
Isso é um bom substituto, mas wxEntry () chamada entra no loop de aplicação original. Se não chamar wxEntry () ainda existem algumas partes do aplicativo não inicializado.
A questão é como inicializar tudo o necessário para uma wxApp a prazo, sem realmente executá-lo, por isso somos capazes de porções de teste de unidade de ele?
Solução
Você quer usar a função:
bool wxEntryStart(int& argc, wxChar **argv)
em vez de wxEntry. Ele não chama OnInit do seu aplicativo () ou executar o loop principal.
Você pode chamar wxTheApp->CallOnInit()
para invocar OnInit () quando necessário em seus testes.
Você vai precisar usar
void wxEntryCleanup()
quando tiver terminado.
Outras dicas
Apenas passado por isso mesmo com 2.8.10. A magia é esta:
// 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();
Você pode apenas criar uma instância wxApp vez de derivar sua própria classe usando a técnica acima.
Eu não sei como você espera fazer o teste de unidade de sua aplicação, sem entrar no mainloop como componentes muitas wxWidgets requerem a entrega de eventos para a função. A abordagem usual seria para executar testes de unidade depois de entrar no circuito principal.
IMPLEMENT_APP_NO_MAIN(MyApp);
IMPLEMENT_WX_THEME_SUPPORT;
int main(int argc, char *argv[])
{
wxEntryStart( argc, argv );
wxTheApp->CallOnInit();
wxTheApp->OnRun();
return 0;
}
Parece que fazer os testes na função wxApp :: OnRun () pode, talvez, o trabalho. código de aqui que testa o título de uma caixa de diálogo com 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(); }
Você poderia reverter a situação:
Inicializar e iniciar o aplicativo wxPython incluindo o loop principal, em seguida, executar os testes de unidade de dentro do aplicativo. Acho que há uma função chamada na entrada loop principal, depois de todas as coisas init é feito.
Você já tentou a macro IMPLEMENT_APP_NO_MAIN
? O comentário acima, desde a definição de macro sugere que ele pode fazer o que você precisa que ele.
De
// 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()); }