欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > gtest 和 gmock讲解

gtest 和 gmock讲解

2025/3/1 15:28:23 来源:https://blog.csdn.net/qq_43559669/article/details/145905609  浏览:    关键词:gtest 和 gmock讲解

Google Test(gtest)和 Google Mock(gmock)是 Google 开发的用于 C++ 的测试框架和模拟框架,以下是对它们的详细讲解:
Google Test(gtest)
简介
Google Test 是一个用于 C++ 的单元测试框架,它提供了一组丰富的功能和工具,帮助开发人员编写和运行单元测试。它具有简洁的语法、强大的断言机制和灵活的测试用例组织方式,广泛应用于 C++ 项目的单元测试中。
主要功能
断言宏:gtest 提供了多种断言宏,用于验证各种条件。如EXPECT_EQ用于判断两个值是否相等,EXPECT_NE用于判断两个值是否不相等,EXPECT_TRUE和EXPECT_FALSE用于判断条件是否为真或假等。
测试用例和测试套件:可以将相关的测试用例组织成测试套件。使用TEST_F宏可以定义一个测试用例,其中F代表 Fixture,允许在测试用例之间共享一些数据和设置。
死亡测试:能够测试程序在特定条件下是否会崩溃或产生错误。例如,可以使用EXPECT_DEATH宏来验证某个函数在特定输入下是否会导致程序异常终止。
参数化测试:支持参数化测试,允许使用不同的参数值来运行同一个测试用例,从而更全面地测试函数的功能。
示例代码
cpp
#include <gtest/gtest.h>

// 加法函数
int Add(int a, int b) {
return a + b;
}

// 测试用例
TEST(AddTest, PositiveNumbers) {
EXPECT_EQ(Add(2, 3), 5);
}

int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Google Mock(gmock)
简介
Google Mock 是一个用于 C++ 的模拟框架,它建立在 Google Test 之上,用于创建和使用模拟对象,以便在单元测试中模拟依赖关系。gmock 使得测试代码更加独立、可维护和可测试,尤其在处理复杂的依赖关系和难以直接测试的组件时非常有用。
主要功能
模拟函数行为:可以使用MOCK_METHOD宏来定义模拟函数,然后通过设置期望(Expectations)来指定模拟函数在被调用时的行为。例如,可以指定模拟函数的返回值、调用次数等。
验证函数调用:gmock 能够验证模拟函数是否按照预期被调用。可以使用EXPECT_CALL宏来设置期望,并在测试结束时自动验证这些期望是否被满足。
匹配器(Matchers):提供了各种匹配器,用于更灵活地验证函数调用的参数。例如,可以使用_匹配任何值,Eq匹配特定的值,Ge匹配大于等于某个值等。
Nice 和 Strict 模式:有两种模式来控制模拟对象的行为。Nice 模式下,模拟对象会对未设置期望的调用给出默认行为;Strict 模式下,未设置期望的调用会导致测试失败。
示例代码
cpp
#include <gtest/gtest.h>
#include <gmock/gmock.h>

// 定义一个接口
class MyInterface {
public:
virtual int DoSomething(int value) = 0;
};

// 测试用例
class MyTest : public ::testing::Test {
public:
// 使用gmock模拟接口
MOCK_METHOD1(DoSomethingMock, int(int));
};

TEST_F(MyTest, TestDoSomething) {
// 设置期望:DoSomethingMock函数被调用时,传入参数5,返回值为10
EXPECT_CALL(DoSomethingMock, DoSomethingMock(5)).WillOnce(Return(10));

// 调用模拟函数
int result = DoSomethingMock(5);// 验证结果
EXPECT_EQ(result, 10);

}

int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
总的来说,gtest 主要用于编写和运行单元测试,而 gmock 则主要用于在单元测试中模拟依赖对象,两者结合使用可以有效地提高 C++ 项目的测试效率和质量,帮助开发人员编写更可靠的代码。
vsscode中怎么使用gtest和gmock
在 VS Code 中使用 Google Test(gtest)和 Google Mock(gmock)进行 C++ 项目的单元测试,可按以下步骤操作:

  1. 安装必要的工具和扩展
    编译器:确保系统中安装了 C++ 编译器,如 GCC(在 Linux 系统中)或 MinGW(在 Windows 系统中)。
    CMake:CMake 是一个跨平台的构建工具,用于生成项目的构建文件。可以从CMake 官网下载并安装。
    VS Code 扩展:安装以下 VS Code 扩展:
    C/C++:提供 C++ 语言支持,包括代码高亮、智能提示等功能。
    CMake Tools:方便在 VS Code 中使用 CMake 进行项目构建。
  2. 下载和配置 gtest 与 gmock
    方法一:使用 CMake 下载
    可以在项目的CMakeLists.txt文件中使用FetchContent模块自动下载和配置 gtest 与 gmock。示例CMakeLists.txt如下:
    cmake
    cmake_minimum_required(VERSION 3.14)
    project(MyProject)

设置C++标准

set(CMAKE_CXX_STANDARD 11)

启用测试

enable_testing()

使用FetchContent下载gtest和gmock

include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/tags/release-1.11.0.zip
)

对于Windows系统,防止gtest覆盖CMake的find_package配置

set(gtest_force_shared_crt ON CACHE BOOL “” FORCE)
FetchContent_MakeAvailable(googletest)

添加可执行文件

add_executable(
my_tests
test.cpp
)

链接gtest和gmock库

target_link_libraries(
my_tests
gtest_main
gmock_main
)

注册测试

include(GoogleTest)
gtest_discover_tests(my_tests)
方法二:手动下载和安装
从Google Test 和 Google Mock 的 GitHub 仓库下载源码。
解压源码后,使用 CMake 构建并安装库。在终端中执行以下命令:
bash
mkdir build
cd build
cmake …
make
sudo make install
3. 编写测试代码
创建一个test.cpp文件,编写测试代码。以下是一个简单的示例:
cpp
#include <gtest/gtest.h>
#include <gmock/gmock.h>

// 示例函数
int Add(int a, int b) {
return a + b;
}

// 测试用例
TEST(AddTest, PositiveNumbers) {
EXPECT_EQ(Add(2, 3), 5);
}

int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
4. 配置 VS Code 进行构建和运行
打开项目文件夹:在 VS Code 中打开包含CMakeLists.txt和test.cpp的项目文件夹。
配置 CMake:按下Ctrl + Shift + P(Windows/Linux)或Cmd + Shift + P(Mac),输入CMake: Configure并选择该命令。VS Code 会根据CMakeLists.txt文件生成构建配置。
选择构建套件:按下Ctrl + Shift + P,输入CMake: Select a Kit,选择合适的编译器套件。
构建项目:按下Ctrl + Shift + P,输入CMake: Build,VS Code 会使用 CMake 构建项目。
运行测试:构建成功后,在终端中运行生成的可执行文件(例如my_tests),或者按下Ctrl + Shift + P,输入CMake: Run Tests来运行测试。
5. 调试测试代码
如果需要调试测试代码,可以按下F5启动调试。在启动调试前,需要在 VS Code 的launch.json文件中配置调试器。可以通过按下Ctrl + Shift + D,选择Create a launch.json file,然后选择合适的调试配置。通常,对于 CMake 项目,可以选择C++ (GDB/LLDB)配置。
通过以上步骤,你就可以在 VS Code 中使用 gtest 和 gmock 进行 C++ 项目的单元测试了。
如何在windows上面安装minGw
在 Windows 上安装 MinGW(Minimalist GNU for Windows),可以按照以下步骤进行:
方法一:使用 MinGW - Installation Manager(旧方法)
下载 MinGW 安装管理器
访问 MinGW 官网 ,在下载列表中找到 mingw-get-setup.exe 并下载。这是 MinGW 的安装管理器程序。
运行安装管理器
双击下载好的 mingw-get-setup.exe 文件,启动安装向导。
在安装过程中,选择安装目录,建议使用默认目录(例如 C:\MinGW ),然后点击 “安装” 按钮,等待安装完成。
选择要安装的组件
安装完成后,会自动打开 MinGW Installation Manager 窗口。
在左侧的树形菜单中展开 Basic Setup 选项。
勾选以下几个必要的组件:
mingw32-base-bin:MinGW 的基础二进制文件,包含 GCC 编译器等核心工具。
mingw32-gcc-g+±bin:C++ 编译器。
msys-base-bin:提供了一些基本的 Unix 工具,如 make 等。
应用更改
选择菜单栏中的 Installation -> Apply Changes ,在弹出的窗口中点击 Apply 按钮,安装管理器会开始下载并安装所选的组件。
配置环境变量
右键点击 “此电脑”,选择 “属性”。
在左侧面板中点击 “高级系统设置”,在弹出的 “系统属性” 窗口中,点击 “环境变量” 按钮。
在 “系统变量” 列表中找到 Path 变量,点击 “编辑”。
点击 “新建”,添加 MinGW 的 bin 目录路径,例如 C:\MinGW\bin ,然后依次点击 “确定” 保存设置。
方法二:使用 MSYS2(推荐)
MSYS2 是一个在 Windows 上的软件分发和构建平台,它集成了 MinGW,安装和更新更为方便。
下载并安装 MSYS2
访问 MSYS2 官网 ,下载适合你系统的安装程序(32 位或 64 位)。
运行下载的安装程序,按照安装向导的提示完成安装,选择合适的安装目录(例如 C:\msys64 )。
更新系统
打开 MSYS2 终端(可以在开始菜单中找到)。
在终端中执行以下命令更新 MSYS2 的基础系统:
bash
pacman -Syu
第一次运行该命令时,可能会提示关闭终端并重新打开,按照提示操作后再次执行 pacman -Syu ,直到系统更新完成。
安装 MinGW 工具链
如果你需要 32 位的 MinGW 工具链,在 MSYS2 终端中执行:
bash
pacman -S mingw-w64-i686-toolchain
如果你需要 64 位的 MinGW 工具链,执行:
bash
pacman -S mingw-w64-x86_64-toolchain
在安装过程中,会提示你选择要安装的组件,直接按回车键选择默认组件即可。
配置环境变量
对于 32 位 MinGW,将 C:\msys64\mingw32\bin 添加到系统的 Path 环境变量中。
对于 64 位 MinGW,将 C:\msys64\mingw64\bin 添加到系统的 Path 环境变量中。
验证安装
安装完成后,打开命令提示符(CMD)或 PowerShell,输入以下命令验证 MinGW 是否安装成功:
bash
gcc --version
g++ --version
如果能正确显示 GCC 和 G++ 的版本信息,则说明 MinGW 安装成功。
怎么知道自己的系统是多少位的、
在不同的操作系统中,查看系统位数的方法有所不同,以下为你详细介绍 Windows、macOS 和 Linux 系统查看系统位数的方式:
Windows 系统
方法一:通过 “此电脑” 属性查看
右键点击桌面上的 “此电脑” 图标,在弹出的菜单中选择 “属性”。
在弹出的 “系统” 窗口中,找到 “系统类型” 一项,显示的 “基于 x64 的系统” 表示 64 位系统,“基于 x86 的系统” 则表示 32 位系统。
方法二:通过系统信息查看
按下 “Win + R” 组合键,打开 “运行” 对话框。
输入 “msinfo32” 并回车,打开 “系统信息” 窗口。
在窗口的 “系统摘要” 部分,找到 “系统类型”,从中可得知系统是 32 位还是 64 位。
macOS 系统
方法一:通过 “关于本机” 查看
点击屏幕左上角的苹果菜单,选择 “关于本机”。
在弹出的窗口中,点击 “系统报告” 按钮。
在左侧列表中选择 “硬件” 下的 “处理器”,在右侧的 “处理器名称” 和 “处理器类型” 信息中,若提及 “64 位”,则表明是 64 位系统。目前,较新的 Mac 电脑基本都是 64 位系统。
方法二:使用终端命令查看
打开 “应用程序” 文件夹,进入 “实用工具” 文件夹,双击打开 “终端”。
在终端中输入命令 uname -m 并回车。
如果输出结果为 x86_64,则是 64 位系统;如果输出 i386 或 i686,则是 32 位系统,但现代 macOS 系统很少有 32 位的了。
Linux 系统
方法一:使用 uname 命令
打开终端(可以通过应用程序菜单找到 “终端” 程序并打开)。
在终端中输入命令 uname -m 并回车。
若输出结果为 x86_64,则系统为 64 位;若输出 i386、i486、i586 或 i686,则为 32 位系统。
方法二:查看 /proc 文件系统信息
在终端中输入命令 file /sbin/init 并回车。
根据输出信息判断,若包含 “x86-64” 字样,则是 64 位系统;若包含 “i386” 等相关内容,则是 32 位系统。
详细讲一下gtest的知识,以及测试代码的输出结果
Google Test(gtest)详细介绍

  1. 概述
    Google Test 是 Google 开发的一个用于 C++ 的单元测试框架,它提供了丰富的功能和工具,能帮助开发者编写和运行单元测试。其优点包括简洁的语法、强大的断言机制、灵活的测试用例组织方式,被广泛应用于 C++ 项目的单元测试中。
  2. 核心概念
    2.1 测试用例(Test Case)和测试套件(Test Suite)
    测试用例:是一个独立的测试单元,用于验证某个特定的功能或行为。在 gtest 中,使用 TEST 或 TEST_F 宏来定义测试用例。
    测试套件:是一组相关测试用例的集合,用于组织和管理测试。TEST 宏定义的测试用例默认属于一个与测试用例名相关的测试套件;TEST_F 宏定义的测试用例属于一个自定义的测试套件(通常基于测试夹具)。
    2.2 测试夹具(Test Fixture)
    测试夹具是一种在多个测试用例之间共享数据和设置的机制。使用 TEST_F 宏时,需要定义一个继承自 ::testing::Test 的类,在该类中可以声明和初始化共享的数据成员,并在 SetUp() 和 TearDown() 方法中进行测试前的准备和测试后的清理工作。
    2.3 断言(Assertions)
    断言是用于验证程序行为是否符合预期的语句。gtest 提供了多种类型的断言宏,主要分为两类:
    非致命断言:以 EXPECT_ 开头,如 EXPECT_EQ、EXPECT_TRUE 等。当非致命断言失败时,测试会继续执行后续的代码。
    致命断言:以 ASSERT_ 开头,如 ASSERT_EQ、ASSERT_TRUE 等。当致命断言失败时,测试会立即终止当前测试用例的执行。
  3. 示例代码及解释
    cpp
    #include <gtest/gtest.h>

// 待测试的函数
int Add(int a, int b) {
return a + b;
}

// 使用 TEST 宏定义测试用例
TEST(AddTest, PositiveNumbers) {
EXPECT_EQ(Add(2, 3), 5);
}

// 定义测试夹具类
class MyTestFixture : public ::testing::Test {
protected:
void SetUp() override {
// 测试前的准备工作
}

void TearDown() override {// 测试后的清理工作
}

};

// 使用 TEST_F 宏定义测试用例,属于 MyTestFixture 测试套件
TEST_F(MyTestFixture, AnotherTest) {
EXPECT_EQ(Add(1, 2), 3);
}

int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
测试代码的输出结果

  1. 测试成功的输出
    当所有测试用例都通过时,输出结果大致如下:
    plaintext
    [==========] Running 2 tests from 2 test suites.
    [----------] Global test environment set-up.
    [----------] 1 test from AddTest
    [ RUN ] AddTest.PositiveNumbers
    [ OK ] AddTest.PositiveNumbers (0 ms)
    [----------] 1 test from AddTest (0 ms total)

[----------] 1 test from MyTestFixture
[ RUN ] MyTestFixture.AnotherTest
[ OK ] MyTestFixture.AnotherTest (0 ms)
[----------] 1 test from MyTestFixture (0 ms total)

[----------] Global test environment tear-down
[] 2 tests from 2 test suites ran. (0 ms total)
[ PASSED ] 2 tests.
解释:
[
] Running 2 tests from 2 test suites.:表示即将运行来自 2 个测试套件的 2 个测试用例。
[ RUN ]:表示开始执行某个测试用例。
[ OK ]:表示该测试用例执行成功。
[ PASSED ] 2 tests.:表示所有 2 个测试用例都通过了测试。
2. 测试失败的输出
假设 Add 函数实现有误,返回值总是 0,修改后的代码如下:
cpp
#include <gtest/gtest.h>

// 错误的 Add 函数实现
int Add(int a, int b) {
return 0;
}

TEST(AddTest, PositiveNumbers) {
EXPECT_EQ(Add(2, 3), 5);
}

int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
输出结果如下:
plaintext
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from AddTest
[ RUN ] AddTest.PositiveNumbers
test.cpp:8: Failure
Expected equality of these values:
Add(2, 3)
Which is: 0
5
[ FAILED ] AddTest.PositiveNumbers (0 ms)
[----------] 1 test from AddTest (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] AddTest.PositiveNumbers

1 FAILED TEST
解释:
test.cpp:8: Failure:指出在 test.cpp 文件的第 8 行断言失败。
Expected equality of these values::提示期望两个值相等,但实际不相等。
Which is: 0:显示 Add(2, 3) 的实际返回值为 0。
5:显示期望的返回值为 5。
[ FAILED ]:表示该测试用例执行失败。
[ FAILED ] 1 test, listed below: 和 1 FAILED TEST:表明有 1 个测试用例失败。
通过这些输出信息,开发者可以快速定位测试失败的位置和原因,从而进行代码的调试和修复。
gtest和gmock可以在嵌入式系统中使用吗
gtest 和 gmock 可以在嵌入式系统中使用,但需要考虑一些特殊的情况和进行相应的调整,以下是详细分析:
可以使用的原因
功能需求匹配
单元测试需求:嵌入式系统的软件部分同样需要保证代码质量和可靠性,gtest 强大的单元测试功能,如丰富的断言机制、灵活的测试用例组织方式等,可以帮助开发者对嵌入式系统中的各个模块进行独立测试,确保每个模块的功能正确性。
模拟依赖需求:嵌入式系统通常会依赖于各种硬件设备、外部接口或其他复杂组件。gmock 可以模拟这些依赖,使得开发者能够在不依赖实际硬件的情况下对软件进行测试,提高测试效率和可重复性。
跨平台特性
gtest 和 gmock 是用 C++ 编写的,具有一定的跨平台特性。只要嵌入式系统的开发环境支持 C++ 编译器,就有可能在该系统上使用 gtest 和 gmock。
使用时面临的挑战及解决办法
资源限制
内存限制:嵌入式系统的内存资源通常比较有限,而 gtest 和 gmock 的运行需要一定的内存空间。解决办法是可以对测试代码进行优化,减少不必要的对象创建和内存分配;或者选择轻量级的测试框架作为补充,只在关键模块使用 gtest 和 gmock。
存储限制:嵌入式设备的存储容量可能较小,gtest 和 gmock 的库文件以及测试代码可能会占用较多的存储空间。可以考虑只编译和使用必要的部分,或者对代码进行压缩和优化。
硬件依赖
运行环境差异:嵌入式系统的硬件平台和运行环境可能与传统的桌面系统有很大差异,例如不同的处理器架构、指令集等。需要确保 gtest 和 gmock 能够在目标嵌入式平台上正确编译和运行,可能需要针对特定的平台进行配置和调整。
硬件交互模拟:在测试涉及硬件交互的代码时,需要使用 gmock 模拟硬件设备的行为。但有些硬件设备的行为非常复杂,模拟起来可能有一定难度,需要开发者深入了解硬件的工作原理,编写准确的模拟代码。
实时性要求
嵌入式系统通常对实时性有较高的要求,而 gtest 和 gmock 的测试过程可能会引入一定的时间开销。在设计测试用例时,需要考虑实时性的影响,避免因测试代码导致系统实时性能下降。
示例步骤(以基于 ARM 架构的嵌入式系统为例)
交叉编译:由于嵌入式系统的硬件平台和开发主机可能不同,需要使用交叉编译工具链来编译 gtest 和 gmock 库以及测试代码。例如,使用 ARM GCC 交叉编译工具链。
移植和配置:将编译好的 gtest 和 gmock 库文件复制到嵌入式系统的目标文件系统中,并在测试代码中正确配置库的路径。
编写测试代码:根据嵌入式系统的具体需求,编写相应的测试用例和模拟对象,使用 gtest 和 gmock 进行单元测试。
运行测试:将测试代码部署到嵌入式系统中运行,查看测试结果。
综上所述,虽然在嵌入式系统中使用 gtest 和 gmock 存在一些挑战,但通过合理的配置和优化,它们可以有效地提高嵌入式系统软件的质量和可靠性。
对于测试夹具类举更详细的例子
测试夹具(Test Fixture)是 Google Test(gtest)中一个重要的概念,它允许你在多个测试用例之间共享数据和设置。以下是一个更详细的测试夹具类的示例,展示了如何使用测试夹具进行单元测试。
示例场景
假设我们要实现一个简单的银行账户类 BankAccount,它支持存款、取款和查询余额的操作。我们将使用测试夹具类来测试这个类的不同功能。
代码实现
cpp
#include <gtest/gtest.h>

// 定义银行账户类
class BankAccount {
public:
BankAccount(double initialBalance = 0.0) : balance(initialBalance) {}

// 存款操作
void deposit(double amount) {if (amount > 0) {balance += amount;}
}// 取款操作
bool withdraw(double amount) {if (amount > 0 && amount <= balance) {balance -= amount;return true;}return false;
}// 查询余额
double getBalance() const {return balance;
}

private:
double balance;
};

// 定义测试夹具类
class BankAccountTestFixture : public ::testing::Test {
protected:
// 在每个测试用例开始前执行,用于初始化测试数据
void SetUp() override {
account = new BankAccount(100.0); // 初始余额为 100
}

// 在每个测试用例结束后执行,用于清理资源
void TearDown() override {delete account;
}BankAccount* account;

};

// 测试存款功能
TEST_F(BankAccountTestFixture, DepositTest) {
account->deposit(50.0);
EXPECT_EQ(account->getBalance(), 150.0);
}

// 测试取款功能(成功取款)
TEST_F(BankAccountTestFixture, WithdrawSuccessTest) {
bool result = account->withdraw(30.0);
EXPECT_TRUE(result);
EXPECT_EQ(account->getBalance(), 70.0);
}

// 测试取款功能(余额不足)
TEST_F(BankAccountTestFixture, WithdrawFailureTest) {
bool result = account->withdraw(200.0);
EXPECT_FALSE(result);
EXPECT_EQ(account->getBalance(), 100.0);
}

int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
代码解释
BankAccount 类:这是我们要测试的目标类,它包含了存款、取款和查询余额的基本功能。
BankAccountTestFixture 类:这是一个测试夹具类,继承自 ::testing::Test。
SetUp() 方法:在每个测试用例开始前执行,用于初始化测试数据。这里创建了一个初始余额为 100 的 BankAccount 对象。
TearDown() 方法:在每个测试用例结束后执行,用于清理资源。这里删除了之前创建的 BankAccount 对象,避免内存泄漏。
account 成员变量:用于存储在 SetUp() 方法中创建的 BankAccount 对象,供测试用例使用。
测试用例:
DepositTest:测试存款功能,向账户中存入 50 元,然后验证账户余额是否变为 150 元。
WithdrawSuccessTest:测试成功取款的情况,从账户中取出 30 元,验证取款操作是否成功,并检查账户余额是否变为 70 元。
WithdrawFailureTest:测试余额不足时的取款情况,尝试从账户中取出 200 元,验证取款操作是否失败,并检查账户余额是否保持不变。
main 函数:初始化 Google Test 框架并运行所有测试用例。
通过使用测试夹具类,我们可以在多个测试用例之间共享 BankAccount 对象的初始化和清理过程,提高了测试代码的可维护性和复用性。
mock_method
MOCK_METHOD 是 Google Mock(gmock)框架中的一个宏,用于定义模拟方法。在单元测试中,当被测试的代码依赖于某些接口或抽象类时,我们可以使用 MOCK_METHOD 来创建这些接口或抽象类的模拟对象,从而模拟这些依赖的行为,使得测试更加独立和可控制。
基本语法
MOCK_METHOD 有不同的版本,根据方法的参数数量和是否为常量方法有不同的使用方式。以下是常见的几种形式:
无参数方法
cpp
MOCK_METHOD(ReturnType, MethodName, (), (const));
ReturnType:方法的返回类型。
MethodName:方法的名称。
括号 () 表示方法没有参数。
(const) 是可选的,如果方法是常量方法则需要加上。
带参数方法
cpp
MOCK_METHOD(ReturnType, MethodName, (ParamType1 param1, ParamType2 param2), (const));
ParamType1、ParamType2 等是方法参数的类型。
param1、param2 等是方法参数的名称。
示例代码

  1. 定义接口
    首先,我们定义一个简单的接口类 IFileReader,它包含一个读取文件内容的方法:
    cpp
    // file_reader.h
    #ifndef FILE_READER_H
    #define FILE_READER_H

#include

class IFileReader {
public:
virtual ~IFileReader() = default;
virtual std::string readFile(const std::string& filename) = 0;
};

#endif // FILE_READER_H
2. 创建模拟对象
使用 MOCK_METHOD 为 IFileReader 接口创建模拟对象:
cpp
// mock_file_reader.h
#ifndef MOCK_FILE_READER_H
#define MOCK_FILE_READER_H

#include “file_reader.h”
#include <gmock/gmock.h>

class MockFileReader : public IFileReader {
public:
MOCK_METHOD(std::string, readFile, (const std::string& filename), (override));
};

#endif // MOCK_FILE_READER_H
3. 编写测试用例
下面是一个使用模拟对象的测试用例,测试另一个依赖 IFileReader 接口的类 FileProcessor:
cpp
// file_processor.h
#ifndef FILE_PROCESSOR_H
#define FILE_PROCESSOR_H

#include “file_reader.h”
#include

class FileProcessor {
public:
FileProcessor(IFileReader& reader) : reader(reader) {}

std::string processFile(const std::string& filename) {std::string content = reader.readFile(filename);// 这里可以添加更多的处理逻辑return content;
}

private:
IFileReader& reader;
};

#endif // FILE_PROCESSOR_H

// test.cpp
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include “file_processor.h”
#include “mock_file_reader.h”

TEST(FileProcessorTest, ProcessFileTest) {
MockFileReader mockReader;
FileProcessor processor(mockReader);

std::string filename = "test.txt";
std::string expectedContent = "This is a test file.";// 设置模拟方法的期望行为
EXPECT_CALL(mockReader, readFile(filename)).WillOnce(testing::Return(expectedContent));// 调用被测试的方法
std::string result = processor.processFile(filename);// 验证结果
EXPECT_EQ(result, expectedContent);

}

int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
代码解释
MOCK_METHOD 的使用:在 MockFileReader 类中,使用 MOCK_METHOD 宏定义了 readFile 方法的模拟版本。
设置期望行为:在测试用例中,使用 EXPECT_CALL 宏设置了 mockReader 的 readFile 方法在被调用时的期望行为,即当传入 filename 时,返回 expectedContent。
验证结果:调用 FileProcessor 的 processFile 方法,并验证返回结果是否与期望的内容一致。
通过使用 MOCK_METHOD 和 EXPECT_CALL,我们可以模拟依赖对象的行为,从而更方便地对目标代码进行单元测试。
怎么讲一下上述代码,以及代码输出
代码详细解释

  1. 接口定义 (file_reader.h)
    cpp
    #ifndef FILE_READER_H
    #define FILE_READER_H

#include

class IFileReader {
public:
virtual ~IFileReader() = default;
virtual std::string readFile(const std::string& filename) = 0;
};

#endif // FILE_READER_H
功能:定义了一个抽象接口 IFileReader,其中包含一个纯虚函数 readFile,用于读取指定文件名的文件内容。任何实现该接口的类都必须提供 readFile 方法的具体实现。
关键部分:
virtual ~IFileReader() = default;:声明虚析构函数,确保在通过基类指针删除派生类对象时能正确释放资源。
virtual std::string readFile(const std::string& filename) = 0;:纯虚函数,要求派生类必须实现该方法。
2. 模拟对象定义 (mock_file_reader.h)
cpp
#ifndef MOCK_FILE_READER_H
#define MOCK_FILE_READER_H

#include “file_reader.h”
#include <gmock/gmock.h>

class MockFileReader : public IFileReader {
public:
MOCK_METHOD(std::string, readFile, (const std::string& filename), (override));
};

#endif // MOCK_FILE_READER_H
功能:创建了一个 IFileReader 接口的模拟类 MockFileReader。使用 MOCK_METHOD 宏为 readFile 方法生成模拟实现,方便在测试中控制该方法的行为。
关键部分:
MOCK_METHOD(std::string, readFile, (const std::string& filename), (override));:定义了 readFile 方法的模拟版本。当在测试中调用该模拟对象的 readFile 方法时,可以通过 EXPECT_CALL 来设置其返回值和调用次数等期望。
3. 被测试类定义 (file_processor.h)
cpp
#ifndef FILE_PROCESSOR_H
#define FILE_PROCESSOR_H

#include “file_reader.h”
#include

class FileProcessor {
public:
FileProcessor(IFileReader& reader) : reader(reader) {}

std::string processFile(const std::string& filename) {std::string content = reader.readFile(filename);// 这里可以添加更多的处理逻辑return content;
}

private:
IFileReader& reader;
};

#endif // FILE_PROCESSOR_H
功能:定义了一个 FileProcessor 类,该类依赖于 IFileReader 接口。processFile 方法调用传入的 IFileReader 对象的 readFile 方法来读取文件内容,并返回该内容。
关键部分:
FileProcessor(IFileReader& reader) : reader(reader) {}:构造函数,通过引用接收一个 IFileReader 对象,将其存储在成员变量 reader 中。
std::string processFile(const std::string& filename):调用 reader.readFile 读取文件内容并返回。
4. 测试用例 (test.cpp)
cpp
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include “file_processor.h”
#include “mock_file_reader.h”

TEST(FileProcessorTest, ProcessFileTest) {
MockFileReader mockReader;
FileProcessor processor(mockReader);

std::string filename = "test.txt";
std::string expectedContent = "This is a test file.";// 设置模拟方法的期望行为
EXPECT_CALL(mockReader, readFile(filename)).WillOnce(testing::Return(expectedContent));// 调用被测试的方法
std::string result = processor.processFile(filename);// 验证结果
EXPECT_EQ(result, expectedContent);

}

int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
功能:编写了一个测试用例 ProcessFileTest 来测试 FileProcessor 类的 processFile 方法。
关键部分:
MockFileReader mockReader; 和 FileProcessor processor(mockReader);:创建 MockFileReader 模拟对象和 FileProcessor 对象,并将模拟对象传递给 FileProcessor。
EXPECT_CALL(mockReader, readFile(filename)).WillOnce(testing::Return(expectedContent));:设置模拟对象 mockReader 的 readFile 方法在传入 filename 时,只调用一次并返回 expectedContent。
std::string result = processor.processFile(filename);:调用 FileProcessor 的 processFile 方法获取结果。
EXPECT_EQ(result, expectedContent);:验证 processFile 方法的返回结果是否与期望的内容一致。
代码输出
测试成功
如果测试用例通过,输出大致如下:
plaintext
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from FileProcessorTest
[ RUN ] FileProcessorTest.ProcessFileTest
[ OK ] FileProcessorTest.ProcessFileTest (0 ms)
[----------] 1 test from FileProcessorTest (0 ms total)

[----------] Global test environment tear-down
[] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 1 test.
解释:
[ RUN ]:表示开始执行 FileProcessorTest.ProcessFileTest 测试用例。
[ OK ]:表示该测试用例执行成功。
[ PASSED ] 1 test.:表示所有 1 个测试用例都通过了测试。
测试失败
如果测试用例失败,例如 EXPECT_EQ(result, expectedContent); 不满足,输出大致如下:
plaintext
[
] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from FileProcessorTest
[ RUN ] FileProcessorTest.ProcessFileTest
test.cpp:XX: Failure
Expected equality of these values:
result
Which is: “Actual result”
expectedContent
Which is: “This is a test file.”
[ FAILED ] FileProcessorTest.ProcessFileTest (0 ms)
[----------] 1 test from FileProcessorTest (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] FileProcessorTest.ProcessFileTest

1 FAILED TEST
解释:
test.cpp:XX: Failure:指出在 test.cpp 文件的第 XX 行断言失败。
Expected equality of these values::提示期望两个值相等,但实际不相等。
Which is: “Actual result” 和 Which is: “This is a test file.”:分别显示实际结果和期望结果。
[ FAILED ]:表示该测试用例执行失败。
[ FAILED ] 1 test, listed below: 和 1 FAILED TEST:表明有 1 个测试用例失败。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词