How to use Google Mock with CppUnitTestFramework

前端 未结 1 1323
不思量自难忘°
不思量自难忘° 2021-01-24 11:03

TL;DR: You can use GMock to add mocking capability to your Microsoft native c++ unit tests. See my answer below for details.


I want to st

相关标签:
1条回答
  • 2021-01-24 11:33

    I was able to get GMock working correctly with the CppUnitTestFramework by creating a custom TestEventListener. I then created a simple set of interface functions to make it easier to work with.

    I used the gmock 1.7.0 NuGet package to install the GMock framework into my project, and added the two files shown below.

    GMockUtils.h

    #pragma once
    
    #include <CppUnitTest.h>
    #include <gmock/gmock.h>
    
    namespace testing { 
        namespace GMockUtils {
    
            // Call once per test class or module to set up everything needed by GoogleMock.
            void InitGoogleMock();
    
            // Call once per test method to check for GoogleMock messages.
            void CheckGoogleMock();
        }
    }
    

    GMockUtils.cpp

    #include "stdafx.h"
    #include "GMockUtils.h"
    
    using namespace Microsoft::VisualStudio::CppUnitTestFramework;
    
    namespace testing {
        namespace GMockUtils {
            namespace {
    
                // Test event listener for use with CppUnitTestFramework
                class CppUnitTestReporter : public EmptyTestEventListener
                {
                public:
                    CppUnitTestReporter() : _failed(false) 
                    {
                    }
    
                    // Helper for converting std::string to std::wstring
                    std::wstring to_wstring(const std::string& str) const
                    {
                        std::wstring output;
                        std::copy(str.begin(), str.end(), std::back_inserter(output));
                        return output;
                    }
    
                    // Called after a failed assertion or a SUCCEED() invocation.
                    void OnTestPartResult(const ::testing::TestPartResult& result) override
                    {
                        // Log this result to the CppUnitTestFramework output
                        Logger::WriteMessage(result.summary());
    
                        // Note: You cannot do an Assert directly from a listener, so we
                        // just store the messages until CheckGoogleMock() is called.
                        if (result.failed())
                        {
                            _failed = true;
    
                            // Append this result to the running summary
                            _failedSummary += result.message();
                            _failedSummary += "\n";
                        }
                    }
    
                    // Clear any previous failures
                    void ResetFailures()
                    {
                        _failed = false;
                        _failedSummary.clear();
                    }
    
                    // Assert if any failures have been detected. Also resets failures.
                    void CheckFailures()
                    {
                        auto failed = _failed;
                        auto failedSummary = _failedSummary;
                        ResetFailures();
                        Assert::IsFalse(failed, to_wstring(failedSummary).c_str());
                    }
    
                protected:
                    bool _failed;
                    std::string _failedSummary;
    
                } *_listener;
            }
    
            // Initialize the Google Mock framework for use with CppUnitTestFramework
            void InitGoogleMock()
            {
                // Avoids calling the function unnecessarily
                if (_listener != nullptr)
                    return;
    
                // Dummy command line parameters (could pass exe path here)
                int argc = 0;
                char** argv = nullptr;
    
                // Initialize the framework
                ::testing::InitGoogleMock(&argc, argv);
    
                // We don't want exceptions thrown, regardless what the doc says
                GTEST_FLAG(throw_on_failure) = false;
    
                // Remove default listener
                auto &listeners = UnitTest::GetInstance()->listeners();
                delete listeners.Release(listeners.default_result_printer());
    
                // Create and install the new listener
                _listener = new CppUnitTestReporter();
                listeners.Append(_listener);
            }
    
            // Reset any previous failures detected by the listener
            void ResetGoogleMock()
            {
                _listener->ResetFailures();
            }
    
            // Prints messages and asserts if any Google Mock messages are found.
            void CheckGoogleMock()
            {
                Assert::IsNotNull(_listener, L"Google Mock framework not initialized by InitGoogleMock()");
                _listener->CheckFailures();
            }
        }
    }
    

    I use the GMockUtils functions in unit test classes like this:

    #include "GMockUtils.h"
    
    using namespace Microsoft::VisualStudio::CppUnitTestFramework;
    using namespace ::testing;
    
    namespace GMockUtilsDemo
    {
        TEST_CLASS(GMockUtilTests)
        {
        public:
    
            TEST_CLASS_INITIALIZE(ClassInitializer)
            {
                // IMPORTANT: This must be called before any mock object constructors
                GMockUtils::InitGoogleMock();
            }
    
            TEST_METHOD_CLEANUP(MethodCleanup)
            {
                // Checks for GoogleMock messages. Asserts if found.
                GMockUtils::CheckGoogleMock();
            }
    
            TEST_METHOD(Method1_ParamIsOne_Method2CalledWithOne)
            {
                MockTestClass mockObj;
                EXPECT_CALL(mockObj, Method2(1)).Times(1); // Expectation will be met
                mockObj.Method1(1);
            }
    
            TEST_METHOD(Method1_ParamIsZero_IntentionallyFail)
            {
                MockTestClass mockObj;
                EXPECT_CALL(mockObj, Method2(1)).Times(1); // Expectation will not be met
                mockObj.Method1(0);
            }
        };
    }
    


    The Console Output

    The console output now shows all GMock messages, and the run does not abort on the first test failure.

    [3/27/2019 12:23:46 PM Informational] ------ Run test started ------
    [3/27/2019 12:23:46 PM Informational] 
    Unexpected mock function call - returning directly.
        Function call: Method2(0)
    Google Mock tried the following 1 expectation, but it didn't match:
    
    c:\...\gmockutilsdemo.cpp(64): EXPECT_CALL(_mockObj, Method2(1))...
      Expected arg #0: is equal to 1
               Actual: 0
             Expected: to be called once
               Actual: never called - unsatisfied and active
    [3/27/2019 12:23:46 PM Informational] Actual function call count doesn't match EXPECT_CALL(_mockObj, Method2(1))...
             Expected: to be called once
               Actual: never called - unsatisfied and active
    [3/27/2019 12:23:46 PM Informational] ========== Run test finished: 2 run (0:00:00.8631468) ==========
    


    Test Explorer View

    If I run the tests via Visual Studio Test Explorer, I can also see all GMock messages related to a particular test. It also works with the VsTest task on Azure DevOps.

    Hopefully this will be useful to anyone who finds themselves in the same situation.

    0 讨论(0)
提交回复
热议问题