Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo

Close

MFC or Text/XML depending on command line

Help
2012-12-28
2013-04-22
  • John McCabe
    John McCabe
    2012-12-28

    Hi

    I inherited a unit test system using VS.NET and CppUnit 1.10.2. It looks like one of our developers had set this up and customised the CppUnit code so that, when a command line argument, i.e. a file name, was passed in it would run the  MFC Test Runner showing the GUI but also populating the file with the XML output.

    I'd like to do something similar with CppUnit 1.12.x and VS2010 so that we can either use the MFC GUI for development runs or the XML output for use in our Jenkins CI system.

    I've got it kind of working by making it so that a file name on the command line swaps between either the MFCTestRunner or the TextTestRunner with an XMLOutputter. I've done this within the InitInstance() function of a dialog.

    While it kind of appears to work, I've noticed that, when running it from the command line with a filename argument, the program appears to 'complete' (i.e. the command prompt reappears) quite some time before the XML file is created! I've only tried this a couple of times so maybe i'm mistaken, but if anyone knows anything about trying to use the text/xml output in an MFC app I'd appreciate the benefit of their experience. It may just be that InitInstance() is the wrong place for the command line argument check but it's been a while since I used VS/MFC so it'll take me time to work that one out!

    Thank you
    John

     
  • Bitwise
    Bitwise
    2012-12-29

    I'm not really authoritative here but, as minor points:

    • InitInstance()

    is the initialization stream for the dialog, and your CppUnit code is not really part of the dlg initialization … so make sure that it is at or towards the end of the function.

    • There are details missing from how your code works.  Are you interfacing to the CppUnit callback or writing your own file? If you are writing your own file, are you closing the file after writing the desired contents?
     
  • John McCabe
    John McCabe
    2012-12-29

    Thanks for your reply. I think the best thing is for me to post my code so I've done it below. FWIW - when I run with the MFC GUI it takes around 14 seconds. Using the xml outputter the program returns control to the command line immediately, but the XML file is generated around 14 seconds later. Should I return FALSE from InitInstance?

    Thanks
    John

    ===

    BOOL CHostAppApp::InitInstance()
    {
        // Standard initialization
        // If you are not using these features and wish to reduce the size
        //  of your final executable, you should remove from the following
        //  the specific initialization routines you do not need.
    #ifdef _AFXDLL
    # if _MSC_VER < 1300   // vc6
        Enable3dControls();         // Call this when using MFC in a shared DLL
    # endif
    #else
        Enable3dControlsStatic();   // Call this when linking to MFC statically
    #endif
        // Change the registry key under which our settings are stored.
        // You should modify this string to be something appropriate
        // such as the name of your company or organization.
        SetRegistryKey(_T("Local AppWizard-Generated Applications"));
        LoadStdProfileSettings();  // Load standard INI file options (including MRU)
        // Register the application's document templates.  Document templates
        //  serve as the connection between documents, frame windows and views.
        CSingleDocTemplate* pDocTemplate;
        pDocTemplate = new CSingleDocTemplate(
            IDR_MAINFRAME,
            RUNTIME_CLASS(CHostAppDoc),
            RUNTIME_CLASS(CMainFrame),       // main SDI frame window
            RUNTIME_CLASS(CHostAppView));
        AddDocTemplate(pDocTemplate);
        RunUnitTests();
        return TRUE;
    }
    void
    CHostAppApp::RunUnitTests()
    {
    // This #ifdef is to allow the code to compile both both the legacy system and the
    // new system.  The legacy system is Windows XP, MS VS2003, and an older version
    // of cppunit, and the new system is Windows 7, MS VS2010 and cppunit 1.12.1 (with
    // VS 2010 tweaks). On Windows 7, the #define _WIN32_WINNT is set to 0x0601, so we
    // use this to decide if this is being compiled for the legacy system
    #if (_WIN32_WINNT == 0x601)
        LPCTSTR commandline = GetCommandLine();
        LPCTSTR filename = strrchr(commandline, ' ');             // look for last space
        // If a space was found, use the subsequent string as the file name but
        // make sure we haven't just found a space character at the end of the line
        if (filename && (strlen(filename) > 1))
        {
            // Use the text/xml outputter
            ++filename;                                             // move to next character
            // Create the test runner
            CppUnit::TextUi::TestRunner runner;
            // Create an event manager and test controller
            CppUnit::TestResult testResult;
            // Add a listener that collect test results
            CppUnit::TestResultCollector collectedResults;
            testResult.addListener(&collectedResults);
            runner.addTest(CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest());
            runner.run(testResult);
            std::ofstream xmlOutput(filename);
            CppUnit::XmlOutputter xmlOutputter(&collectedResults, xmlOutput);
            xmlOutputter.write();
        }
        else
        {
            // Use the MFC Test Runner
            CPPUNIT_NS::MfcUi::TestRunner runner;
            runner.addTest( CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest() );
            runner.run();
        }
    #else
        LPCTSTR commandline = GetCommandLine();
        LPCTSTR filename = strrchr( commandline, ' ' );             // look for last space
        if( filename )
        {
            ++filename;                                             // move to next character
        }
        CPPUNIT_NS::MfcUi::TestRunner runner;
        runner.addTest( CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest() );
        if( filename )
        {
            runner.run( filename );
        }
        else
        {
            runner.run();
        }
    #endif
    }
    
     
  • Bitwise
    Bitwise
    2012-12-31

    You don't want to return FALSE from InitInstance() - this indicates failure of the API and you won't get what you want from your app.

    I don't know the specific answer to your question about latent file creation but I suspect the original code came from

    http://www.codeproject.com/Articles/5660/Unit-testing-with-CPPUnit

    which might be helpful…