西安专业建网站,制作音乐排行榜网页设计,网站程序系统,首页排名关键词优化Google Test#xff08;gtest#xff09;和 Google Mock#xff08;gmock#xff09;是 Google 开发的用于 C 的测试框架和模拟框架#xff0c;以下是对它们的详细讲解#xff1a; Google Test#xff08;gtest#xff09; 简介 Google Test 是一个用于 C 的单元测试框…Google Testgtest和 Google Mockgmock是 Google 开发的用于 C 的测试框架和模拟框架以下是对它们的详细讲解 Google Testgtest 简介 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 Mockgmock 简介 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 Testgtest和 Google Mockgmock进行 C 项目的单元测试可按以下步骤操作
安装必要的工具和扩展 编译器确保系统中安装了 C 编译器如 GCC在 Linux 系统中或 MinGW在 Windows 系统中。 CMakeCMake 是一个跨平台的构建工具用于生成项目的构建文件。可以从CMake 官网下载并安装。 VS Code 扩展安装以下 VS Code 扩展 C/C提供 C 语言支持包括代码高亮、智能提示等功能。 CMake Tools方便在 VS Code 中使用 CMake 进行项目构建。下载和配置 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 PWindows/Linux或Cmd Shift PMac输入CMake: Configure并选择该命令。VS Code 会根据CMakeLists.txt文件生成构建配置。 选择构建套件按下Ctrl Shift P输入CMake: Select a Kit选择合适的编译器套件。 构建项目按下Ctrl Shift P输入CMake: BuildVS 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 上安装 MinGWMinimalist 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-binMinGW 的基础二进制文件包含 GCC 编译器等核心工具。 mingw32-gcc-g±binC 编译器。 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 Testgtest详细介绍
概述 Google Test 是 Google 开发的一个用于 C 的单元测试框架它提供了丰富的功能和工具能帮助开发者编写和运行单元测试。其优点包括简洁的语法、强大的断言机制、灵活的测试用例组织方式被广泛应用于 C 项目的单元测试中。核心概念 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 等。当致命断言失败时测试会立即终止当前测试用例的执行。示例代码及解释 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(); } 测试代码的输出结果
测试成功的输出 当所有测试用例都通过时输出结果大致如下 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 Testgtest中一个重要的概念它允许你在多个测试用例之间共享数据和设置。以下是一个更详细的测试夹具类的示例展示了如何使用测试夹具进行单元测试。 示例场景 假设我们要实现一个简单的银行账户类 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 Mockgmock框架中的一个宏用于定义模拟方法。在单元测试中当被测试的代码依赖于某些接口或抽象类时我们可以使用 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 等是方法参数的名称。 示例代码
定义接口 首先我们定义一个简单的接口类 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我们可以模拟依赖对象的行为从而更方便地对目标代码进行单元测试。 怎么讲一下上述代码以及代码输出 代码详细解释
接口定义 (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 个测试用例失败。