单元测试(C++)——gmock通用测试模版(个人总结)

news/2024/12/22 17:59:02 标签: 单元测试, c++, log4j

引言

        在现代软件开发中,单元测试是保证代码质量的重要工具之一。Google Mock(简称gMock)是谷歌提供的一个强大的C++框架,用于创建mock对象。它允许开发者模拟复杂的行为,从而简化了单元测试的编写。

        本文将介绍如何构建一个通用的gMock测试模板,该模板可以轻松地应用于不同的项目和函数,特别是那些与外部依赖或接口交互的函数。

准备工作

        在开始之前,请确保环境中已经安装并配置好了Google Test和Google Mock。

设计通用Mock接口

        首先定义一个MockInterface类,这个类会包含所有需要模拟的方法。对于每个想要模拟的方法,我们都使用MOCK_METHOD宏来声明。

#include <gmock/gmock.h>

class MockInterface {
public:
    MOCK_METHOD(int, exampleMethod, (int arg1, const std::string& arg2), ());
};

实现全局调用机制

        为了让外部C函数能够访问mock对象,需要一个全局指针g_mock_interface,并且提供一个call_mock模板函数来转发调用。

static MockInterface* g_mock_interface = nullptr;

template <typename Ret, typename Class, typename... Args>
Ret call_mock(Ret (Class::*method)(Args...), Args... args) {
    return g_mock_interface ? (g_mock_interface->*method)(args...) : Ret{};
}

编写外部C函数的包装器

        对于每一个想要模拟的外部C函数,都需要编写一个包装器函数,它通过call_mock调用mock对象的方法。

extern "C" {
int external_function_example(int arg1, const char* arg2) {
    return call_mock<int, MockInterface, int, const char*>(
        &MockInterface::exampleMethod, arg1, arg2);
}
}

创建测试类

        接下来,创建一个继承自::testing::Test的测试类,在其中实现SetUpTearDown方法来初始化和清理测试环境。

class GeneralTest : public ::testing::Test {
protected:
    void SetUp() override {
        g_mock_interface = nullptr;
    }

    void TearDown() override {
        if (/* condition to check resource */) {
            /* cleanup code */
        }
    }
};

编写具体的测试用例

        最后,编写具体的测试用例,设置期望行为,并执行测试逻辑。

TEST_F(GeneralTest, ExampleTest) {
    auto mock = new ::testing::NiceMock<MockInterface>();
    g_mock_interface = mock;

    EXPECT_CALL(*mock, exampleMethod(::testing::_, ::testing::_))
        .Times(3)
        .WillOnce(::testing::Return(-1))
        .WillOnce(::testing::Return(0))
        .WillOnce(::testing::Return(1));

    // 执行测试逻辑。
    // ...

    // 验证结果。
    // ...

    g_mock_interface = nullptr;
    delete mock;
}

结论

        通过上述步骤,我们创建了一个通用的gMock测试模板,它可以被复用在不同的项目中。此模板不仅简化了mock对象的管理,还提高了测试代码的可读性和维护性。

附录 

        完整汇总gmock代码模版如下,包含了创建通用的mock接口、全局调用机制、外部C函数包装器、测试类以及具体的测试用例:

#include <gmock/gmock.h>
#include <gtest/gtest.h>

// 定义您的接口或类的mock版本。
class MockInterface {
public:
    // 模拟方法应该根据实际接口定义。这里我们仅提供一个示例。
    MOCK_METHOD(int, exampleMethod, (int arg1, const std::string& arg2), ());
};

// 用于全局访问的mock对象指针。
static MockInterface* g_mock_interface = nullptr;

// 通用的函数调用mock对象的方法。
template <typename Ret, typename Class, typename... Args>
Ret call_mock(Ret (Class::*method)(Args...), Args... args) {
    return g_mock_interface ? (g_mock_interface->*method)(args...) : Ret{};
}

// 外部C函数调用mock方法的例子。
extern "C" {
int external_function_example(int arg1, const char* arg2) {
    return call_mock<int, MockInterface, int, const char*>(
        &MockInterface::exampleMethod, arg1, arg2);
}
}

// 测试类继承自::testing::Test。
class GeneralTest : public ::testing::Test {
protected:
    void SetUp() override {
        g_mock_interface = nullptr;
        // 初始化其他测试资源。
    }

    void TearDown() override {
        // 清理测试资源。
        if (/* condition to check resource */) {
            /* cleanup code */
        }
    }

    // 可以在这里声明测试中使用的成员变量。
};

// 实际的测试用例。
TEST_F(GeneralTest, ExampleTest) {
    // 创建NiceMock实例,并设置为全局mock接口。
    auto mock = new ::testing::NiceMock<MockInterface>();
    g_mock_interface = mock;

    // 设置mock行为。
    EXPECT_CALL(*mock, exampleMethod(::testing::_, ::testing::_))
        .Times(3)
        .WillOnce(::testing::Return(-1)) // 第一次调用返回-1
        .WillOnce(::testing::Return(0))  // 第二次调用返回0
        .WillOnce(::testing::Return(1)); // 第三次调用返回1

    // 执行测试逻辑。
    // ...

    // 验证结果。
    // ...

    // 清理。
    g_mock_interface = nullptr;
    delete mock;
}


http://www.niftyadmin.cn/n/5795660.html

相关文章

算法-滑动窗口注意力机制

1、算法流程 1.1 将序列按给定窗口大小和滑动步长进行划分&#xff1b; 1.2 对每个窗口计算自注意力&#xff0c; 首先是计算窗口内每个元素的查询Q、键K和值V&#xff0c;这一步是使用一个线性层实现的&#xff0c;输入和输出的大小都是元素的维度。 其次是Q乘以K的转置计算窗…

python中wb有什么用

‘wb’&#xff1a;表示以二进制写方式打开&#xff0c;只能写文件&#xff0c; 如果文件不存在&#xff0c;创建该文件&#xff1b;如果文件已存在&#xff0c;则覆盖写。 Python文件使用“wb”方式打开&#xff0c;写入字符串会报错&#xff0c;因为这种打开方式为&#xff…

Java开发经验——数据库开发经验

摘要 本文主要介绍了Java开发中的数据库操作规范&#xff0c;包括数据库建表规范、索引规约、SQL规范和ORM规约。强调了在数据库设计和操作中应遵循的最佳实践&#xff0c;如字段命名、数据类型选择、索引创建、SQL语句编写和ORM映射&#xff0c;旨在提高数据库操作的性能和安…

【083】基于51单片机智能烘手器【Proteus仿真+Keil程序+报告+原理图】

☆、设计硬件组成&#xff1a;51单片机最小系统LCD1602液晶显示DS18B20温度传感器TCRT5000红外感应传感器AT24C02存储芯片风扇加热片继电器LED灯按键设置。 1、设计采用STC89C51/52、AT89C51/52、AT89S51/52作为主控芯片&#xff1b; 2、系统采用DS18B20温度传感器感应当前环…

智慧医疗挂号前沿:SSM+Vue 医院预约挂号系统设计与突破

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

maven项目运行时NoSuchMethodError问题排查记录(依赖冲突解决)

控制台异常如下&#xff1a; Handler dispatch failed; nested exception is java.lang.NoSuchMethodError: org.apache.commons.io.input.BoundedInputStream.builder()Lorg/apache/commons/io/input/BoundedInputStream$Builder;问题明显&#xff0c;根据NoSuchMethodError…

【day09】面向对象编程进阶

【day08】重点回顾 在深入本模块之前&#xff0c;让我们回顾一下【day08】中的关键内容&#xff1a; 封装&#xff1a; 隐藏对象内部细节&#xff0c;仅通过公共接口与外界交互。使用private关键字修饰成员变量和方法&#xff0c;限制直接访问。提供get和set方法&#xff0c;以…

大数据机器学习算法和计算机视觉应用07:机器学习

Machine Learning Goal of Machine LearningLinear ClassificationSolutionNumerical output example: linear regressionStochastic Gradient DescentMatrix Acceleration Goal of Machine Learning 机器学习的目标 假设现在有一组数据 x i , y i {x_i,y_i} xi​,yi​&…