当前位置: 首页 > article >正文

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

引言

        在现代软件开发中,单元测试是保证代码质量的重要工具之一。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.kler.cn/a/446633.html

相关文章:

  • Hutool工具包的常用工具类的使用介绍
  • 【k8s集群应用】K8S二进制安装大致步骤(简略版)
  • Android详解——ConstraintLayout约束布局
  • linux java 查看异常堆栈
  • C05S07-Tomcat服务架设
  • 【STM32 Modbus编程】-作为主设备写入多个线圈和寄存器
  • Spring(三)-SpringWeb-概述、特点、搭建、运行流程、组件、接受请求、获取请求数据、特殊处理、拦截器
  • python实现word转html
  • AI大模型进一步推动了AI在处理图片、视频、音频、文本的等数据应用
  • 【新教程】非root用户给Ubuntu server设置开机自启服务-root用户给Ubuntu server设置开机自启服务
  • ArcGIS计算土地转移矩阵
  • 详细解释爬虫中的异常处理机制?
  • Rabbitmq实现延迟队列
  • Leetcode2545:根据第 K 场考试的分数排序
  • 26、基于SpringBoot的在线文档管理系统的设计与实现
  • R 基础运算
  • 基于卷积神经网络(CNN)和ResNet50的水果与蔬菜图像分类系统
  • 机器视觉检测相机基础知识 | 颜色 | 光源 | 镜头 | 分辨率 / 精度 / 公差
  • Leetcode 串联所有单词的子串
  • 【windows】sonarqube起不来的问题解决
  • 人脸修复与增强腾讯开源项目GFPGAN介绍
  • python rabbitmq实现简单/持久/广播/组播/topic/rpc消息异步发送可配置Django
  • Java爬虫实战:深度解析Lazada商品详情
  • 解决ubuntu22.04常见问题
  • Qt之串口设计-线程实现(十二)
  • 深入浅出:内网黄金票据与白银票据