简体   繁体   English

如何使用谷歌测试/模拟测试基于 MFC CWnd 的类?

[英]How to test MFC CWnd based classes using google test/mock?

I am new with the idea of TDD.我对 TDD 的想法很陌生。 I have not used any testing framework before.我之前没有使用过任何测试框架。 Recently I have started reading about it and practicing with google test.最近我开始阅读它并用谷歌测试练习。 My goal is to start TDD in a legacy code base developed in MFC.我的目标是在 MFC 开发的遗留代码库中启动 TDD。 Most of the time I have to work with GUI controls - developing new custom controls, adding features to existing custom controls etc. So, I want to automate the testing of GUI classes which are mostly derived from CWnd class.大多数时候我必须使用 GUI 控件 - 开发新的自定义控件,向现有的自定义控件添加功能等。所以,我想自动测试主要从 CWnd 类派生的 GUI 类。

I have created a win32 console project in Visual Studio for testing, while creating the project I have ticked MFC in 'Add common header files for' option.我在 Visual Studio 中创建了一个 win32 控制台项目进行测试,在创建项目时,我在“添加通用头文件”选项中勾选了 MFC。 Visual Studio project wizard has generated the main function and have created a CWinApp object. Visual Studio 项目向导生成了 main 函数并创建了一个 CWinApp 对象。 In the main function I have added the boilerplate code for google test.在主函数中,我添加了用于 google 测试的样板代码。 I have compiled the actual project (that is to be tested) and google test (and mock) library as .lib and linked it to the test project.我已经将实际项目(即要测试的)和 google 测试(和模拟)库编译为 .lib 并将其链接到测试项目。 I have successfully build the test project.我已经成功构建了测试项目。 I can test simple things from the projects.我可以从项目中测试简单的东西。

Here is wizard generated code (google test boilerplate code included)-这是向导生成的代码(包括谷歌测试样板代码)-

#include "stdafx.h"
#include "TestMFC.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// The one and only application object
CWinApp theApp;
using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;

    HMODULE hModule = ::GetModuleHandle(NULL);

    if (hModule != NULL)
    {
        // initialize MFC and print and error on failure
        if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
        {
            // TODO: change error code to suit your needs
            _tprintf(_T("Fatal Error: MFC initialization failed\n"));
            nRetCode = 1;
        }
        else
        {
            // TODO: code your application's behavior here.
              testing::InitGoogleMock(&argc, argv);
              nRetCode = RUN_ALL_TESTS();
        }
    }
    else
    {
        // TODO: change error code to suit your needs
        _tprintf(_T("Fatal Error: GetModuleHandle failed\n"));
        nRetCode = 1;
    }
    return nRetCode;
}

The challenge I am facing is I can't create actual window as that will require to have message loop.我面临的挑战是我无法创建实际的窗口,因为这需要有消息循环。 I wanted to mock CWnd so that I can test features based on know assumptions.我想模拟 CWnd,以便我可以根据已知的假设测试功能。 But, I can't find a way to mock CWnd as it has some non-virtual member functions that depend on HWND.但是,我找不到模拟 CWnd 的方法,因为它有一些依赖于 HWND 的非虚拟成员函数。 HWND is valid only if I create a window. HWND 仅在我创建窗口时有效。 Another challenge is message handlers are not virtual functions.另一个挑战是消息处理程序不是虚函数。 So I can't mock message handlers and without creating a window it is not possible to route a message to its handler.所以我不能模拟消息处理程序,如果不创建窗口,就不可能将消息路由到它的处理程序。

I need thoughts on how can I approach to solve the problem.我需要思考如何解决问题。 Can I do it without creating actual window with mock or something else?我可以在不使用模拟或其他方式创建实际窗口的情况下做到这一点吗? Or I can create window and route messages?或者我可以创建窗口和路由消息?

Thanks in advance.提前致谢。

I'd suggest using Visual Studio Coded UI Test Automation suite.我建议使用Visual Studio Coded UI 测试自动化套件。 It is much better than Google Mock.它比 Google Mock 好得多。 The Visual Studio Coded UI Test natively supports MFC/Win32 GUI stuff. Visual Studio 编码的 UI 测试本身支持 MFC/Win32 GUI 内容。

There is a problem with testing MFC application as most of the functions are not exported.测试 MFC 应用程序存在问题,因为大多数功能未导出。 So we should include our sources with GTEST project and link it with MFC runtime.所以我们应该将我们的源代码包含在 GTEST 项目中,并将它与 MFC 运行时链接起来。 And this is the tricky part.这是棘手的部分。 I've used VS2017 "Test Adapter For Google Test" with NuGet package: "googletest.v140.windesktop.static.rt-dyn" in my project and it finally works.我在我的项目中使用了 VS2017“Google 测试的测试适配器”和 NuGet 包:“googletest.v140.windesktop.static.rt-dyn”,它终于工作了。

Chances are you need mfc and the message loop.您可能需要 mfc 和消息循环。 It's easier to start with a Visual Studio wizard generated application and override the InitInstance, OnIdle and ExitInstance virtual functions of CWinApp.从 Visual Studio 向导生成的应用程序开始并覆盖 CWinApp 的 InitInstance、OnIdle 和 ExitInstance 虚拟函数更容易。

You will probably need to allow windows messages to be carried via the MainWindow, so this gives you the ability to have a finite state machine (FST) running the tests.您可能需要允许通过 MainWindow 传送 Windows 消息,因此这使您能够使用有限状态机 (FST) 运行测试。 I initialised my environment in InitInstance and reported test results from ExitInstance.我在 InitInstance 中初始化了我的环境并从 ExitInstance 报告了测试结果。 I used the FST mainly to setup the next test validator (a function pointer) (to be called from whatever was being actioned by the tested subject) and to call a test initiator function to send a message to initiate the next action.我主要使用 FST 来设置下一个测试验证器(一个函数指针)(从测试对象正在执行的任何操作中调用)并调用测试启动器函数来发送消息以启动下一个操作。

I used OnIdle to start the testing as it was only consistently called when the MFC system had stabilised and setup.我使用 OnIdle 开始测试,因为它只在 MFC 系统稳定和设置后才被一致调用。

The disadvantage of using googletest or Boost test or older versions of Visual Studio is that the unit test framework expects to drive the tests.使用 googletest 或 Boost test 或更旧版本的 Visual Studio 的缺点是单元测试框架需要驱动测试。 They don't allow you to provide a FST to run the tests.它们不允许您提供 FST 来运行测试。 I had issues with having my code in a DLL (global functions don't look at the same global address space in different DLLs - re Singleton pattern issues in DLLs).我在 DLL 中使用我的代码时遇到了问题(全局函数不会查看不同 DLL 中的相同全局地址空间 - DLL 中的单例模式问题)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM