wxWidgets:如何在不使用宏且不进入主应用程序循环的情况下初始化wxApp?

28
我们需要使用Google测试框架为一个wxWidgets应用编写单元测试。问题在于,wxWidgets使用宏IMPLEMENT_APP(MyApp)来初始化并进入应用程序主循环。这个宏创建了一些函数,包括int main()。Google测试框架也为每个测试使用宏定义。
其中一个问题是无法从测试宏中调用wxWidgets宏,因为第一个宏会创建函数。所以,我们发现可以用以下代码替换宏:
wxApp* pApp = new MyApp(); 
wxApp::SetInstance(pApp);
wxEntry(argc, argv);

这是个不错的替代方案,但 wxEntry() 调用会进入原应用程序循环。如果我们不调用 wxEntry() ,仍然有一些应用程序没有初始化的部分。

问题是如何在不实际运行 wxApp 的情况下初始化运行所需的所有内容,以便我们能够对其进行单元测试?

6个回答

17

我自己也刚刚经历完这个问题,使用的是2.8.10版本。神奇的解决方法如下:

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

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

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

您可以直接创建wxApp实例,而不是使用上述技术派生自己的类。

我不确定您如何在不进入主循环的情况下进行应用程序的单元测试,因为许多wxWidgets组件需要传递事件才能正常工作。通常的做法是在进入主循环后运行单元测试。


9
IMPLEMENT_APP_NO_MAIN(MyApp);
IMPLEMENT_WX_THEME_SUPPORT;

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

    return 0;
}

5
您想使用这个函数:
bool wxEntryStart(int& argc, wxChar **argv)

使用wxEntry()的替代方法是wxEntryStart()。它不会调用您应用程序的OnInit()或运行主循环。

在测试中,您可以调用wxTheApp->CallOnInit()来调用OnInit()。

您需要使用

void wxEntryCleanup()

当你完成时。

实际上,这并不起作用。应用程序仍未初始化。 - m_pGladiator
你能否更具体地说明“未初始化”是什么意思?如果你看了源代码,你会发现wxEntry实际上并没有做比调用wxEntryStart()、然后调用“OnInit()”和“OnRun()”更多的事情。我认为在测试中你应该手动调用OnInit()。 - kbluck
好的,这是我错过的 - OnInit()。我会尝试一下。 - m_pGladiator
通过初始化,我可以创建一个主窗口,而不显示它并保持控制在UT中,这使得UT能够创建需要此主窗口才能工作的类。 - m_pGladiator
主窗口通常在OnInit()中创建。您可以调用wxTheApp->CallOnInit()手动调用它。但是,如果消息泵未运行,则窗口的大多数与事件相关的部分将无法工作。也许这个话题正在转向一个新的、不同的问题,关于如何对GUI进行单元测试? - kbluck

1

看起来在wxApp :: OnRun()函数中进行测试可能有效。以下是使用cppUnitLite2测试对话框标题的代码。

#include "wx/wxprec.h"
#ifdef __BORLANDC__ #pragma hdrstop #endif
#ifndef WX_PRECOMP #include "wx/wx.h" #endif
#include "wx/app.h" // wx 包含文件使用方括号,我在引用时使用了双引号以避免 HTML 渲染问题 #include "wx/Frame.h" #include "../CppUnitLite2\src/CppUnitLite2.h" #include "../CppUnitLite2\src/TestResultStdErr.h" #include "../theAppToBeTested/MyDialog.h"
TEST(MyFirstTest) { // 测试系统的“Hello World” int a = 102; CHECK_EQUAL(102, a); }
TEST(MySecondTest) { MyDialog dlg(NULL); // 实例化一个派生自 wxDialog 的类 CHECK_EQUAL("HELLO", dlg.GetTitle()); // 预期此测试失败:标题应为“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(); }

-1

你可能可以扭转局面:

初始化并启动wxPython应用程序,包括主循环,然后在应用程序内运行单元测试。我认为有一个函数在主循环入口处调用,完成所有初始化工作后。


目标是使用单元测试来测试应用程序,而不是使用应用程序进行单元测试。 - m_pGladiator
除非你找到一种完成初始化的方法(迄今为止没有人提出可行的解决方案),否则无法实现上述评论中所述的目标。我已经在wxPython中做过类似的事情了。 - Ber
+1 给我自己,这是我在尝试解决问题后在 wxWidgets 中进行测试的方式。 - SteveL

-1

你尝试过使用IMPLEMENT_APP_NO_MAIN宏吗?在该宏定义上方提供的注释建议它可以实现你所需的功能。

从\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()); }

1
这个宏实际上被简化为问题中的前两行代码。问题在于在调用wxEntry()之前,wxApp的某些部分仍未初始化。wxEntry()进入应用程序循环,并将控制权传递给wxWidgets。我想初始化wxApp,而不运行它。 - m_pGladiator

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接