wxWidgets:マクロを使用せずに、メインアプリケーションループに入らずにwxAppを初期化する方法
-
03-07-2019 - |
質問
Google Test Framework を使用して、 wxWidgets アプリケーションの単体テストを作成する必要があります。 問題は、 wxWidgets がマクロ IMPLEMENT_APP(MyApp)を使用して初期化し、アプリケーションのメインループに入ることです。このマクロは、 int main()を含むいくつかの関数を作成します。 Googleテストフレームワークは、各テストのマクロ定義も使用します。
問題の1つは、最初のマクロが関数を作成するため、テストマクロ内からwxWidgetsマクロを呼び出すことができないことです。したがって、マクロを次のコードに置き換えることができることがわかりました。
wxApp* pApp = new MyApp();
wxApp::SetInstance(pApp);
wxEntry(argc, argv);
これは適切な代替品ですが、wxEntry()呼び出しは元のアプリケーションループに入ります。 wxEntry()を呼び出さないと、アプリケーションの一部がまだ初期化されていません。
問題は、wxAppを実際に実行せずに実行するために必要なすべてを初期化する方法であるため、その一部を単体テストできますか?
解決
次の関数を使用します:
bool wxEntryStart(int& argc, wxChar **argv)
wxEntryの代わり。アプリのOnInit()を呼び出したり、メインループを実行したりしません。
テストで必要なときにwxTheApp->CallOnInit()
を呼び出してOnInit()を呼び出すことができます。
使用する必要があります
void wxEntryCleanup()
完了したら。
他のヒント
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インスタンスを作成するだけです。
多くのwxWidgetsコンポーネントが機能するためにイベントの配信を必要とするため、メインループに入ることなくアプリケーションの単体テストをどのように行うかはわかりません。通常のアプローチは、メインループに入った後に単体テストを実行することです。
IMPLEMENT_APP_NO_MAIN(MyApp);
IMPLEMENT_WX_THEME_SUPPORT;
int main(int argc, char *argv[])
{
wxEntryStart( argc, argv );
wxTheApp->CallOnInit();
wxTheApp->OnRun();
return 0;
}
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(); }
状況を変えることができます:
メインループを含むwxPythonアプリを初期化して起動し、アプリ内からユニットテストを実行します。すべての初期化が完了した後、メインループエントリで呼び出される関数があると思います。
IMPLEMENT_APP_NO_MAIN
マクロを試しましたか?マクロ定義の上にあるコメントは、必要なことを行う可能性があることを示唆しています。
<!> lt; wxWidgetsのソースディレクトリ<!> gt; \ 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()); }