jeudi 28 avril 2016

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

I am new with the idea of 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. 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.

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 project wizard has generated the main function and have created a CWinApp object. In the main function I have added the boilerplate code for google test. 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. 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. But, I can't find a way to mock CWnd as it has some non-virtual member functions that depend on HWND. HWND is valid only if I create a window. 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.

Aucun commentaire:

Enregistrer un commentaire