如何将 Google Mock 与 CppUnitTestFramework 结合使用

2023-12-04

TL;DR: 您可以使用 GMock 向 Microsoft 本机 C++ 单元测试添加模拟功能。看我的答案请参阅下文了解详细信息。


我想开始向我现有的一组本机单元测试添加模拟。这些测试是使用 Microsoft 编写的CppUnitTestFramework框架,不支持模拟。我真的不想将整个测试套件转换为另一个框架只是为了添加一些模拟。

谷歌的GMock框架似乎提供了我需要的一切,并且文档表明它可以与除gtest。因此,请使用博客文章中的建议,例如this one,我创建了几个单元测试。

    TEST_MODULE_INITIALIZE(ModuleInitialize)
    {
        // Enable google mock
        GTEST_FLAG(throw_on_failure) = true;
        int argc = 0;
        TCHAR **argv = nullptr;
        InitGoogleMock(&argc, argv);
    }

    TEST_CLASS(GMockTests)
    {
    public:
        MockTestClass _mockObj;

        TEST_METHOD(Method1_ParamIsOne_Method2CalledWithOne)
        {
            EXPECT_CALL(_mockObj, Method2(1)).Times(1);
            _mockObj.Method1(1);
        }

        TEST_METHOD(Method1_ParamIsZero_IntentionallyFail)
        {
            // Expectation will fail
            EXPECT_CALL(_mockObj, Method2(1)).Times(1);
            _mockObj.Method1(0);
        }

    };

结果并不令人满意。期望确实有效(第一个方法通过),但如果任何期望失败,则整个运行将中止,测试输出中仅显示以下无用消息:

[3/27/2019 11:39:17 AM Error] The active test run was aborted. Reason: 
[3/27/2019 11:39:17 AM Informational] ========== Run test finished: 0 run (0:00:22.3042194) ==========

Visual Studio 测试资源管理器窗口也没有指出问题所在。它只是显示一个测试成功,而另一个测试未运行:

Test Explorer screen snip

所以我从这个集成中寻找的是:

  1. GMock 测试失败不会中止整个运行。
  2. 未达到 GMock 预期的测试将显示为失败。
  3. 所有 GMock 消息都应显示在测试输出中。

我能够得到GMock正确工作CppUnitTestFramework通过创建自定义TestEventListener。然后,我创建了一组简单的接口函数,以使其更易于使用。

我用的是gmock 1.7.0 NuGet 包将 GMock 框架安装到我的项目中,并添加如下所示的两个文件。

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

我在单元测试类中使用 GMockUtils 函数,如下所示:

#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);
        }
    };
}


控制台输出

控制台输出现在显示所有 GMock 消息,并且运行不会在第一次测试失败时中止。

[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) ==========


测试资源管理器视图

如果我通过 Visual Studio 测试资源管理器运行测试,我还可以看到与特定测试相关的所有 GMock 消息。它还可以与 Azure DevOps 上的 VsTest 任务配合使用。

Test Explorer screen snippet

希望这对任何遇到同样情况的人都有用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将 Google Mock 与 CppUnitTestFramework 结合使用 的相关文章

随机推荐

  • CSS 字体 Unicode 范围

    font face font family Nanum Barun Gothic src url NanumBarunGothic ttf unicode range U AC00 D7A3 U 1100 11FF U 3130 318F
  • 将新的拟合阶段添加到现有 PipelineModel 中,无需再次拟合

    我想将几个经过训练的管道连接到一个 这类似于 Spark 将新的拟合阶段添加到现有 PipelineModel 中 无需再次拟合 但是下面的解决方案适用于 PySpark gt pipe model new PipelineModel st
  • 火花笛卡尔积

    我必须比较坐标才能获得距离 因此 我使用 sc textFile 加载数据并制作笛卡尔积 文本文件中大约有 2 000 000 行 因此需要比较 2 000 000 x 2 000 000 坐标 我用大约 2000 个坐标测试了代码 几秒钟
  • fetchone() 正在将 int 变量设置为元组

    我有一个使用 Python 2 7 和 SQLite3 的项目 我正在尝试将整数变量存储在 SQLite3 数据库列中 然后能够将变量设置为 SQLite 列的值 连接正常 列存在 并且类型为 int 我正在使用此代码来提取数据 Trail
  • 有没有办法从以前的 apk 发布文件中获取私有签名的密钥库文件?

    我已经使用 eclipse 创建了私有签名的密钥库文件 并且我已经在 android market 网站上发布了 apk 文件 几天后 我们从用户那里收到了一些问题 我们已经解决了这些问题 但我没有私人签名的密钥库文件 在制作 apk 文件
  • 使用 VSTO 创建 UDF,而不使用 VBA

    与此类似question 但在我的情况下不是 VSTO SE 但是 我只是想确认不可能在 Visual Studio 2005 和 Excel 2003 中使用纯 VSTO 创建 UDF 所以 为了绝对清楚 我的问题是 是否可以使用 Vis
  • 从sql查询中的所有可用列中仅删除一列值的重复值

    我有一个包含三列的sql查询 我想删除beam current列中的任何重复值退出 如何做到这一点 我在sql server2012中工作 我使用了 Distinct 但我也得到了 beam current 的重复值 我的 sql 查询是
  • 如何将旧版构建系统与 Xcode 10 的“xcodebuild”一起使用?

    我想使用 Xcode 10 的新构建系统进行开发 但是我们在持续集成系统中的构建失败了 因为xcarchive制作有一个问题 Info plist in the xcarchive缺少ApplicationProperties密钥及其中的信
  • Select2-rails 无法与 ActiveAdmin 一起使用

    我在将 select2 rails 与 ActiveAdmin 集成时遇到困难 我按照设置步骤操作 Select2 rails Github 页面 https github com argerim select2 rails我添加了一行 r
  • c#编译的应用程序可以在未安装.net的机器上运行吗?

    我想为 Windows 开发一个小型实用程序 我更喜欢用 C 来做 因为它更容易 我是一名 Java 开发人员 该实用程序可供许多人下载 我假设其中一些人没有安装 net 框架 这个假设是否正确 假设我的目标是 win xp 及以上版本 我
  • 在Matlab中保存全局变量

    在 Matlab 中 当将变量声明为全局变量并使用 save 命令保存它时 在新会话中加载 mat 文件后 该变量也是全局变量 以下代码显示了此行为 一开始 我没有变量 gt gt who gt gt who global 然后 我创建全局
  • 更新间隔时间时警报管理器不工作

    阅读所有质量检查后 我没有得到任何正确的解决方案 我有 2 个问题1 即使我仅在清单中注册接收器 警报也会触发两次 不是通过代码 2 当我更新闹钟的间隔时间时 它会随机触发 这是我设置闹钟的方法 public void AlarmCall
  • 如何在java中扫描屏幕上的特定颜色/图像?

    我需要扫描屏幕上的特定图像 颜色 并返回该颜色出现位置的 x 和 y 坐标 我知道这可能包括使用 Robot 类截取屏幕截图 但不知道如何正确扫描该图像 如果您使用 Robot 类进行屏幕截图 您将获得 BuffereImage 类的对象
  • 使用 MIPS 的双重递归

    我正在尝试为该函数实现双重递归f n 2f n 1 3f n 2 1 我能够找出奇异递归并实现2f n 1 1它的一部分 但我不知道如何实现第二部分 这是我的奇异递归的工作代码 data prompt1 asciiz Enter the v
  • iPhone如何隐藏导航栏?

    目前我正在iPhone应用程序中工作 我有两个屏幕 如A和B A没有导航栏 但B有导航栏 所以我这样设置 Class A void viewDidLoad super viewDidLoad self title A self naviga
  • 将数据从部分视图提交到控制器 MVC

    我有一个就业记录列表 您还可以使用部分视图从同一页面添加就业记录 这里是雇佣 cshtml 它有一个记录列表的部分视图和一个用于添加出现在模式弹出窗口中的新记录的部分视图 h2 Employment Records h2 Html Rend
  • timedelta64 和日期时间转换

    我的数据框中有两个日期时间 时间戳 格式的列 df start df end 我想知道两个日期之间的持续时间 所以我创建了持续时间列 df duration df start df end 然而 现在duration列的格式为numpy t
  • Xcode 首选项 -> 帐户未保存

    一般在Xcode我们可以在偏好设置中保存不同的苹果帐户 它之前在之前的所有版本中都可以工作 上周我更新了Xcode并安装了Xcode version 10 0然后我添加了 3 4 个 Apple ID Xcode gt 首选项 gt 帐户
  • Swift:多个目标处理:宏不起作用[重复]

    这个问题在这里已经有答案了 从参考如何使用 swift 语言处理 XCode 中的多个目标 and https www appcoda com using xcode targets 我创建了三个目标 每个目标都有不同的包 ID 和应用程序
  • 如何将 Google Mock 与 CppUnitTestFramework 结合使用

    TL DR 您可以使用 GMock 向 Microsoft 本机 C 单元测试添加模拟功能 看我的答案请参阅下文了解详细信息 我想开始向我现有的一组本机单元测试添加模拟 这些测试是使用 Microsoft 编写的CppUnitTestFra