cpp-mock-testing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMock Testing
模拟测试
Instructions for AI coding agents on automating mock test creation using Google Mock (GMock) with consistent software testing patterns in this C++ project.
本指南为AI编码代理提供在C++项目中,使用Google Mock(GMock)框架并遵循一致软件测试模式来自动化创建模拟测试的说明。
1. Benefits
1. 优势
-
IsolationIsolates the unit under test from external dependencies, ensuring tests focus on the specific component's behavior.
-
ControlProvides precise control over dependency behavior through expectations and return values, enabling thorough testing of edge cases and error conditions.
-
VerificationAutomatically verifies that dependencies are called correctly with expected parameters and call counts.
-
FlexibilitySupports various testing scenarios including strict mocks, nice mocks, and sequence verification for complex interactions.
-
隔离性将被测单元与外部依赖项隔离,确保测试专注于特定组件的行为。
-
可控性通过预期设置和返回值,精确控制依赖项的行为,能够全面测试边缘情况和错误场景。
-
验证性自动验证依赖项是否按预期的参数和调用次数被正确调用。
-
灵活性支持多种测试场景,包括严格模拟(strict mocks)、宽松模拟(nice mocks)以及用于复杂交互的调用顺序验证。
2. Patterns
2. 模式
-
Mock ObjectsSimulated objects that mimic the behavior of real objects in controlled ways. They verify interactions between the unit under test and its dependencies.
-
Interface MockingCreating mock implementations of abstract interfaces or base classes to isolate the unit under test from concrete implementations.
-
Behavior VerificationVerifying that methods are called with expected arguments and in the correct order, rather than just checking return values.
-
Return Value StubbingConfiguring mock objects to return specific values when their methods are called, allowing control over dependency behavior during tests.
-
Exception InjectionUsing mocks to simulate error conditions by throwing exceptions, enabling tests to verify error handling logic.
-
模拟对象以可控方式模拟真实对象行为的仿真对象,用于验证被测单元与其依赖项之间的交互。
-
接口模拟为抽象接口或基类创建模拟实现,将被测单元与具体实现隔离开来。
-
行为验证验证方法是否以预期参数按正确顺序被调用,而非仅检查返回值。
-
返回值桩模拟配置模拟对象,使其在方法被调用时返回特定值,从而在测试期间控制依赖项的行为。
-
异常注入使用模拟对象抛出异常来模拟错误场景,以便测试错误处理逻辑。
3. Workflow
3. 工作流程
-
Identify DependenciesIdentify interfaces or classes that need to be mocked (e.g., database connections, file systems, network services, external APIs).
-
Create Mock ClassesCreate mock classes for interfaces underusing GMock's
test(s)/unit/<module>/macro.MOCK_METHOD -
Register with CMakeAdd the test file tousing
test(s)/unit/<module>/CMakeLists.txtwithmeta_gtest()option.WITH_GMOCKcmakemeta_gtest( WITH_GMOCK TARGET ${PROJECT_NAME}-test SOURCES <header>_test.cpp ) -
Define ExpectationsSet up expectations usingto specify:
EXPECT_CALL- Which methods should be called
- Expected arguments (using matchers)
- Call frequency (Times, AtLeast, AtMost, etc.)
- Return values or actions
-
Test Coverage RequirementsInclude comprehensive scenarios:
- Normal operation with mocked dependencies
- Error conditions (exceptions, null returns, invalid data)
- Boundary conditions in dependency interactions
- Sequence of calls to multiple dependencies
- Concurrent access scenarios when applicable
-
Apply TemplatesStructure all tests using the template pattern below.
-
识别依赖项识别需要被模拟的接口或类(例如数据库连接、文件系统、网络服务、外部API)。
-
创建模拟类使用GMock的宏,在
MOCK_METHOD目录下为接口创建模拟类。test(s)/unit/<module>/ -
注册到CMake使用带有选项的
WITH_GMOCK,将测试文件添加到meta_gtest()中。test(s)/unit/<module>/CMakeLists.txtcmakemeta_gtest( WITH_GMOCK TARGET ${PROJECT_NAME}-test SOURCES <header>_test.cpp ) -
定义预期使用设置预期,指定:
EXPECT_CALL- 哪些方法应该被调用
- 预期的参数(使用匹配器)
- 调用频率(Times、AtLeast、AtMost等)
- 返回值或动作
-
测试覆盖要求需包含全面的场景:
- 带有模拟依赖项的正常操作场景
- 错误场景(异常、空返回、无效数据)
- 依赖项交互的边界条件
- 多个依赖项的调用顺序
- 适用时的并发访问场景
-
应用模板使用以下模板模式构建所有测试。
4. Commands
4. 命令
| Command | Description |
|---|---|
| CMake preset configuration with GMock support and Compile with Ninja |
| Execute tests via ctest (mock tests are part of unit tests) |
| Execute tests via ctest and generate coverage reports including mock test coverage |
| 命令 | 描述 |
|---|---|
| 带有GMock支持的CMake预设配置,使用Ninja编译 |
| 通过ctest执行测试(模拟测试属于单元测试的一部分) |
| 通过ctest执行测试并生成包含模拟测试覆盖情况的覆盖率报告 |
5. Style Guide
5. 风格指南
-
Test Framework
-
Mock Class DefinitionDefine mock classes inheriting from the interface to be mocked. Usemacro with proper method signature, including const qualifiers and override specifiers.
MOCK_METHOD -
Include HeadersGMock/GTest headers are listed first in mock test files as a convention to clearly identify the file as a test file using the GMock framework.Include necessary headers in this order:
- GMock/GTest headers (,
<gmock/gmock.h>)<gtest/gtest.h> - Standard library headers (,
<memory>, etc.)<string> - Project interface headers
- Project implementation headers
- GMock/GTest headers (
-
NamespaceUseand
using namespace <namespace>;for convenience within test functions to access GMock matchers and actions.using namespace ::testing; -
Test OrganizationUse table-driven testing for multiple scenarios with the same mock setup. Eachor
TESTshould focus on one aspect of the interaction with mocked dependencies.TEST_F -
Mock Types
- NiceMock
Ignores unexpected calls (use for non-critical dependencies)
- StrictMock
Fails on any unexpected calls (use for strict verification)
- Default Mock
Warns on unexpected calls (balanced approach)
- NiceMock
-
Expectations
- Use to set up expectations before exercising the unit under test
EXPECT_CALL - Chain matchers with ,
.With(),.WillOnce(),.WillRepeatedly().Times() - Prefer specific matchers (,
Eq(),Gt()) over generic ones when possible_
- Use
-
Matchers and Actions
- Use built-in matchers: (anything),
_,Eq(),Ne(),Lt(),Gt(),Le(),Ge(),IsNull()NotNull() - Container matchers: ,
IsEmpty(),SizeIs(),Contains()ElementsAre() - String matchers: ,
StartsWith(),EndsWith(),HasSubstr()MatchesRegex() - Use ,
Return(),ReturnRef(),Throw(),DoAll()for actionsInvoke()
- Use built-in matchers:
-
Sequence VerificationUseor
InSequenceobjects when call order matters.Sequence -
TraceabilityEmployfor traceable failures in table-driven mock tests.
SCOPED_TRACE(tc.label) -
AssertionsUsemacros to allow all test cases to run. Mock expectations are automatically verified at the end of each test.
EXPECT_*
-
测试框架
-
模拟类定义定义继承自待模拟接口的模拟类。使用宏,并包含正确的方法签名,包括const限定符和override说明符。
MOCK_METHOD -
头文件包含按照惯例,GMock/GTest头文件应在模拟测试文件中排在最前面,以明确标识该文件是使用GMock框架的测试文件。按以下顺序包含必要的头文件:
- GMock/GTest头文件(、
<gmock/gmock.h>)<gtest/gtest.h> - 标准库头文件(、
<memory>等)<string> - 项目接口头文件
- 项目实现头文件
- GMock/GTest头文件(
-
命名空间在测试函数内使用和
using namespace <namespace>;,以便便捷地访问GMock匹配器和动作。using namespace ::testing; -
测试组织对于具有相同模拟设置的多场景测试,使用表格驱动测试。每个或
TEST应专注于与模拟依赖项交互的一个方面。TEST_F -
模拟类型
- NiceMock
忽略意外调用(用于非关键依赖项)
- StrictMock
遇到任何意外调用时失败(用于严格验证场景)
- 默认模拟
遇到意外调用时发出警告(平衡方案)
- NiceMock
-
预期设置
- 在执行被测单元之前,使用设置预期
EXPECT_CALL - 使用、
.With()、.WillOnce()、.WillRepeatedly()链式调用匹配器.Times() - 尽可能使用特定匹配器(、
Eq()、Gt())而非通用匹配器_
- 在执行被测单元之前,使用
-
匹配器与动作
- 使用内置匹配器:(任意值)、
_、Eq()、Ne()、Lt()、Gt()、Le()、Ge()、IsNull()NotNull() - 容器匹配器:、
IsEmpty()、SizeIs()、Contains()ElementsAre() - 字符串匹配器:、
StartsWith()、EndsWith()、HasSubstr()MatchesRegex() - 使用、
Return()、ReturnRef()、Throw()、DoAll()定义动作Invoke()
- 使用内置匹配器:
-
调用顺序验证当调用顺序重要时,使用或
InSequence对象。Sequence -
可追溯性在表格驱动模拟测试中,使用实现可追溯的失败定位。
SCOPED_TRACE(tc.label) -
断言使用宏,允许所有测试用例运行。模拟预期会在每个测试结束时自动验证。
EXPECT_*
6. Template
6. 模板
Use these templates for new mock tests. Replace placeholders with actual values.
使用以下模板创建新的模拟测试,将占位符替换为实际值。
6.1. File Header Template
6.1. 文件头模板
cpp
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <memory>
#include <string>
#include <vector>
#include "<module>/<interface>.hpp"
#include "<module>/<implementation>.hpp"
using namespace <namespace>;
using namespace ::testing;cpp
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <memory>
#include <string>
#include <vector>
#include "<module>/<interface>.hpp"
#include "<module>/<implementation>.hpp"
using namespace <namespace>;
using namespace ::testing;6.2. Mock Class Template
6.2. 模拟类模板
cpp
/**
* @brief Mock implementation of <Interface> for testing.
*/
class Mock<Interface> : public <Interface>
{
public:
MOCK_METHOD(<return_type>, <method_name>, (<param_types>), (override));
MOCK_METHOD(<return_type>, <method_name2>, (<param_types>), (const, override));
};cpp
/**
* @brief 用于测试的<Interface>模拟实现。
*/
class Mock<Interface> : public <Interface>
{
public:
MOCK_METHOD(<return_type>, <method_name>, (<param_types>), (override));
MOCK_METHOD(<return_type>, <method_name2>, (<param_types>), (const, override));
};6.3. Table-Driven Mock Test Template
6.3. 表格驱动模拟测试模板
cpp
TEST(<Module>Test, <FunctionName>WithMock)
{
// In-Got-Want
struct Tests
{
std::string label;
struct In
{
/* input types and names */
} in;
struct Want
{
<output_type> expected; // expected output type(s) and name(s)
/* expected mock call parameters and behavior */
<size_t> call_count; // number of times method should be called
<return_type> return_value; // value mock should return
<param_type> param; // expected parameter value(s)
} want;
};
// Table-Driven Testing
const std::vector<Tests> tests = {
{
"case-description-1",
/* in */ {/* input values */},
/* want */ {/* expected */, /* call_count */ 1, /* return_value */ {}, /* param */ {}}
},
{
"case-description-2",
/* in */ {/* input values */},
/* want */ {/* expected */, /* call_count */ 1, /* return_value */ {}, /* param */ {}}
},
// add more cases as needed
};
for (const auto &tc : tests)
{
SCOPED_TRACE(tc.label);
// Arrange
auto mock_dependency = std::make_shared<Mock<Interface>>();
EXPECT_CALL(*mock_dependency, <method_name>(tc.want.param))
.Times(tc.want.call_count)
.WillOnce(Return(tc.want.return_value));
<Implementation> object(mock_dependency);
// Act
auto got = object.<function>(tc.in.<input>);
// Assert
EXPECT_EQ(got, tc.want.expected);
}
}cpp
TEST(<Module>Test, <FunctionName>WithMock)
{
// 输入-实际-预期
struct Tests
{
std::string label;
struct In
{
/* 输入类型和名称 */
} in;
struct Want
{
<output_type> expected; // 预期输出类型和名称
/* 预期的模拟调用参数和行为 */
<size_t> call_count; // 方法应被调用的次数
<return_type> return_value; // 模拟对象应返回的值
<param_type> param; // 预期的参数值
} want;
};
// 表格驱动测试
const std::vector<Tests> tests = {
{
"用例描述1",
/* 输入 */ {/* 输入值 */},
/* 预期 */ {/* 预期结果 */, /* 调用次数 */ 1, /* 返回值 */ {}, /* 参数 */ {}}
},
{
"用例描述2",
/* 输入 */ {/* 输入值 */},
/* 预期 */ {/* 预期结果 */, /* 调用次数 */ 1, /* 返回值 */ {}, /* 参数 */ {}}
},
// 根据需要添加更多用例
};
for (const auto &tc : tests)
{
SCOPED_TRACE(tc.label);
// 准备阶段
auto mock_dependency = std::make_shared<Mock<Interface>>();
EXPECT_CALL(*mock_dependency, <method_name>(tc.want.param))
.Times(tc.want.call_count)
.WillOnce(Return(tc.want.return_value));
<Implementation> object(mock_dependency);
// 执行阶段
auto got = object.<function>(tc.in.<input>);
// 断言阶段
EXPECT_EQ(got, tc.want.expected);
}
}6.4. Sequence Verification Template
6.4. 调用顺序验证模板
cpp
TEST(<Module>Test, <FunctionName>WithSequence)
{
// Arrange
auto mock_dependency = std::make_shared<StrictMock<Mock<Interface>>>();
InSequence seq;
EXPECT_CALL(*mock_dependency, <method1>(_)).WillOnce(Return(<value1>));
EXPECT_CALL(*mock_dependency, <method2>(_)).WillOnce(Return(<value2>));
<Implementation> object(mock_dependency);
// Act
auto got = object.<function>();
// Assert
EXPECT_EQ(got, <expected>);
}cpp
TEST(<Module>Test, <FunctionName>WithSequence)
{
// 准备阶段
auto mock_dependency = std::make_shared<StrictMock<Mock<Interface>>>();
InSequence seq;
EXPECT_CALL(*mock_dependency, <method1>(_)).WillOnce(Return(<value1>));
EXPECT_CALL(*mock_dependency, <method2>(_)).WillOnce(Return(<value2>));
<Implementation> object(mock_dependency);
// 执行阶段
auto got = object.<function>();
// 断言阶段
EXPECT_EQ(got, <expected>);
}6.5. Exception Testing Template
6.5. 异常测试模板
cpp
TEST(<Module>Test, <FunctionName>ThrowsOnError)
{
// Arrange
auto mock_dependency = std::make_shared<Mock<Interface>>();
EXPECT_CALL(*mock_dependency, <method_name>(_))
.WillOnce(Throw(std::runtime_error("error message")));
<Implementation> object(mock_dependency);
// Act & Assert
EXPECT_THROW(object.<function>(), std::runtime_error);
}cpp
TEST(<Module>Test, <FunctionName>ThrowsOnError)
{
// 准备阶段
auto mock_dependency = std::make_shared<Mock<Interface>>();
EXPECT_CALL(*mock_dependency, <method_name>(_))
.WillOnce(Throw(std::runtime_error("错误消息")));
<Implementation> object(mock_dependency);
// 执行与断言
EXPECT_THROW(object.<function>(), std::runtime_error);
}6.6. NiceMock Template
6.6. NiceMock模板
cpp
TEST(<Module>Test, <FunctionName>WithNiceMock)
{
// Arrange
auto mock_dependency = std::make_shared<NiceMock<Mock<Interface>>>();
ON_CALL(*mock_dependency, <method_name>(_))
.WillByDefault(Return(<default_value>));
EXPECT_CALL(*mock_dependency, <critical_method>(_))
.Times(1)
.WillOnce(Return(<value>));
<Implementation> object(mock_dependency);
// Act
auto got = object.<function>();
// Assert
EXPECT_EQ(got, <expected>);
}cpp
TEST(<Module>Test, <FunctionName>WithNiceMock)
{
// 准备阶段
auto mock_dependency = std::make_shared<NiceMock<Mock<Interface>>>();
ON_CALL(*mock_dependency, <method_name>(_))
.WillByDefault(Return(<默认值>));
EXPECT_CALL(*mock_dependency, <critical_method>(_))
.Times(1)
.WillOnce(Return(<值>));
<Implementation> object(mock_dependency);
// 执行阶段
auto got = object.<function>();
// 断言阶段
EXPECT_EQ(got, <预期值>);
}7. References
7. 参考资料
- GoogleTest Mocking for Dummies guide.
- GoogleTest Mocking Cookbook guide.
- GoogleTest Mocking Cheat Sheet guide.
- GoogleTest Mocking for Dummies 指南。
- GoogleTest Mocking Cookbook 指南。
- GoogleTest Mocking Cheat Sheet 指南。