GoogleTest Mock Actions 详解:模拟函数行为控制指南
什么是 Mock Actions
在单元测试中,Mock Actions(模拟行为)是定义模拟对象在被调用时应该如何响应的重要机制。GoogleTest 提供了一套丰富的内置 Actions,允许开发者精确控制模拟函数的行为,包括返回值设置、参数操作、异常抛出等多种场景。
返回值控制类 Actions
基础返回值设置
Return()
:用于无返回值(void)的模拟函数Return(value)
:返回指定值,类型转换在设置期望时完成ReturnArg<N>()
:返回第N个参数(从0开始计数)
指针与引用相关
ReturnNull()
:返回空指针ReturnPointee(ptr)
:返回指针指向的值ReturnRef(variable)
:返回变量的引用ReturnRefOfCopy(value)
:返回值的拷贝的引用
高级返回值模式
ReturnNew<T>(args...)
:每次调用返回新创建的T类型对象ReturnRoundRobin({a1,...,ak})
:轮询返回列表中的值
副作用类 Actions
这类 Actions 主要用于修改测试环境或被测对象的状态:
Assign(&var, value)
:给变量赋值DeleteArg<N>()
:删除第N个参数(必须是指针)SaveArg<N>(ptr)
:保存第N个参数到指针指向的位置SetArgReferee<N>(value)
:给第N个参数引用的变量赋值SetArrayArgument<N>(first, last)
:复制范围到数组参数SetErrnoAndReturn(error, value)
:设置errno并返回值Throw(exception)
:抛出指定异常
函数调用类 Actions
这类 Actions 允许将调用转发给其他函数或方法:
直接调用
Invoke(f)
:调用全局/静态函数或函数对象Invoke(obj_ptr, &Class::method)
:调用对象方法
无参调用
InvokeWithoutArgs(f)
:调用无参函数InvokeWithoutArgs(obj_ptr, &Class::method)
:调用无参方法
参数转发
InvokeArgument<N>(args...)
:调用第N个参数(必须是可调用对象)
使用示例:
using ::testing::Invoke;
double Calculate(Unused, double x, double y) { return x*y; }
...
EXPECT_CALL(mock, Compute(_, _, _)).WillOnce(Invoke(Calculate));
复合 Actions
组合多个 Actions 实现复杂行为:
DoAll(a1, a2, ...)
:执行所有Actions,返回最后一个的结果IgnoreResult(a)
:执行Action但忽略返回值WithArg<N>(a)
:将第N个参数传给Action执行WithArgs<N1,N2,...>(a)
:将选定参数传给ActionWithoutArgs(a)
:无参执行Action
自定义 Actions
GoogleTest 提供了宏来定义自定义 Actions:
-
ACTION(Name)
:定义无参ActionACTION(Sum) { return arg0 + arg1; }
-
ACTION_P(Name, param)
:定义带参数的ActionACTION_P(Add, n) { return arg0 + n; }
-
ACTION_Pk(Name, p1,...,pk)
:定义多参数Action
最佳实践与注意事项
- 生命周期管理:
Invoke
会获取回调对象的所有权,应确保其生命周期足够长 - 引用传递:使用
std::ref()
包装需要引用传递的参数 - 类型安全:
Return(value)
会立即进行类型转换,而非调用时转换 - 默认行为:
DoDefault()
可用于执行ON_CALL()
定义的默认行为
实际应用示例
TEST(MyTest, ComplexMockBehavior) {
MockService service;
int saved_arg = 0;
std::vector<int> output;
EXPECT_CALL(service, ProcessData(_, _))
.WillOnce(DoAll(
SaveArg<0>(&saved_arg),
SetArgPointee<1>(100),
Return(true)
));
bool result = service.ProcessData(42, output);
EXPECT_TRUE(result);
EXPECT_EQ(saved_arg, 42);
EXPECT_EQ(output[0], 100);
}
通过合理组合这些Actions,可以构建出各种复杂的模拟行为,满足不同场景下的单元测试需求。掌握这些Actions的使用,将显著提升单元测试的灵活性和表达能力。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考