C++测试中的模拟对象和测试夹具:如何无忧编写代码

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么没有模拟和夹具的测试就像抽奖

\n\n

想象一下,你在为宇宙飞船编写代码。你的函数通过调用引擎控制模块来计算轨迹。如何在不启动真实引擎的情况下验证轨迹是否正确?在现实世界中,这将是灾难。在C++的世界里,这是模拟对象和测试夹具的任务。

\n\n

如果你曾经用C++编写过单元测试,你肯定遇到过这些问题:测试因网络、数据库或文件系统而失败。或者你为了每次检查而花费10行代码来准备数据。熟悉吗?那么这篇文章就是为你准备的。

\n\n

我们将探讨C++中的模拟对象如何帮助将代码与外部世界隔离,而测试夹具则帮助重用测试设置。没有废话,只有代码和实践。开始吧!

\n\n

什么是模拟对象以及为什么在C++中需要它们

\n\n

模拟对象(或简称模拟)是真实对象的替代品,它模仿真实对象的行为。你告诉模拟:“当调用getData()方法时,返回42”。然后它乖乖地返回42,而不去访问数据库、API或文件。

\n\n

在C++中,模拟尤其重要,因为这种语言不容忍错误。如果你的类依赖于网络,而网络宕机了——测试就会失败,尽管你的代码是完美的。模拟解决了这个问题:它们隔离了被测试的代码。

\n\n

C++中模拟对象的主要使用场景:

\n
    \n
  • 外部服务(数据库、REST API、文件)。
  • \n
  • 复杂计算,会拖慢测试速度(加密、渲染)。
  • \n
  • 非确定性函数(rand()、time())。
  • \n
  • 交互验证:方法是否被调用、调用次数、以及调用参数。
  • \n
\n\n

在C++中创建模拟的事实标准是Google Mock库(也称为gmock),它与Google Test捆绑在一起。但对于小型项目,手动编写模拟甚至更简单。

\n\n

测试夹具:为测试搭建舞台

\n\n

测试夹具是一组执行测试所需的对象和数据。与其每次都写:

\n\n
MyClass obj;\nobj.init("data");\nobj.connect();
\n\n

……不如将其提取到夹具中。Google Test通过继承::testing::Test来支持夹具。这不仅方便——更是C++测试的最佳实践。

\n\n

测试夹具解决三个问题:

\n
    \n
  1. 代码重用——一次设置,所有测试使用。
  2. \n
  3. 测试清洁性——每个测试从相同的状态开始。
  4. \n
  5. 自动清理——如果需要释放资源,可以在夹具的析构函数中完成。
  6. \n
\n\n

现在,让我们在一个例子中将模拟和夹具结合起来。

\n\n

编写包含模拟对象和测试夹具的测试:真实示例

\n\n

假设我们有一个WeatherReporter类,它通过API获取天气数据。我们想测试getTemperature()方法,而不访问真实服务器。

\n\n

步骤1. 定义接口

\n\n

为了插入模拟,我们需要一个抽象类。这是关键点:模拟通过多态性工作。

\n\n
// weather_api.h\nclass WeatherAPI {\npublic:\n    virtual ~WeatherAPI() = default;\n    virtual double getTemperature(const std::string& city) = 0;\n    virtual bool isAvailable() = 0;\n};
\n\n

步骤2. 使用Google Mock实现模拟

\n\n
// mock_weather_api.h\n#include <gmock/gmock.h>\n#include "weather_api.h"\n\nclass MockWeatherAPI : public WeatherAPI {\npublic:\n    MOCK_METHOD(double, getTemperature, (const std::string& city), (override));\n    MOCK_METHOD(bool, isAvailable, (), (override                

博客

书籍推荐