WxWidgets: Как инициализировать wxApp без использования макросов и без ввода основного цикла приложения?
Нам нужно написать модульные тесты для приложения wxWidgets с помощью Google Test Framework.
Проблема заключается в том, что wxWidgets использует макрос IMPLEMENT_APP (MyApp) для инициализации и ввода основного цикла приложения. Этот макрос создает несколько функций, включая int main(). В тестовой среде Google также используются определения макросов для каждого теста.
Одна из проблем заключается в том, что макрос wxWidgets нельзя вызывать из тестового макроса, потому что первый создает функции. Итак, мы обнаружили, что мы можем заменить макрос следующим кодом:
wxApp* pApp = new MyApp();
wxApp::SetInstance(pApp);
wxEntry(argc, argv);
Что хорошая замена, но вызов wxEntry() входит в исходный цикл приложения. Если мы не называем wxEntry(), все еще некоторые части приложения не инициализируются.
Вопрос заключается в том, как инициализировать все, что требуется для запуска wxApp, без фактического запуска, поэтому мы можем unit test его части?
Ответы
Ответ 1
Вы хотите использовать функцию:
bool wxEntryStart(int& argc, wxChar **argv)
вместо wxEntry. Он не вызывает ваше приложение OnInit() или запускает основной цикл.
Вы можете вызвать wxTheApp->CallOnInit()
для вызова OnInit(), когда это необходимо в ваших тестах.
Вам нужно будет использовать
void wxEntryCleanup()
когда вы закончите.
Ответ 2
Просто прошел через это сам с 2.8.10. Магия такова:
// 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();
Вы можете просто создать экземпляр wxApp, а не выводить свой собственный класс, используя вышеприведенную технику.
Я не уверен, как вы планируете выполнять модульное тестирование вашего приложения, не входя в mainloop, так как многие компоненты wxWidgets требуют доставки событий для работы. Обычным подходом было бы запустить модульные тесты после ввода основного цикла.
Ответ 3
IMPLEMENT_APP_NO_MAIN(MyApp);
IMPLEMENT_WX_THEME_SUPPORT;
int main(int argc, char *argv[])
{
wxEntryStart( argc, argv );
wxTheApp->CallOnInit();
wxTheApp->OnRun();
return 0;
}
Ответ 4
Похоже, что выполнение тестов в функции wxApp:: OnRun() может работать.
Здесь код, который проверяет заголовок диалога с помощью 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();
}
Ответ 5
Вы можете изменить ситуацию:
Инициализируйте и запустите приложение wxPython, включая основной цикл, затем запустите модульные тесты из приложения. Я думаю, что есть функция, вызванная записью основного цикла, после того, как все файлы инициализации сделаны.
Ответ 6
Вы пробовали макрос IMPLEMENT_APP_NO_MAIN
? Комментарий, приведенный выше определения макроса, предполагает, что он может сделать то, что вам нужно.
Из исходного источника < wxWidgets ' > \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()); }