GoogleTest Actions 权威参考:gMock 内置动作(Built-in Actions)与自定义动作完整指南
【免费下载链接】googletestGoogleTest - Google Testing and Mocking Framework项目地址: https://gitcode.com/GitHub_Trending/go/googletest
本指南以 GoogleTest 官方参考文档 docs/reference/actions.md 为骨架,深入拆解 gMock 中"动作(Action)"这一核心概念:动作规定了当 mock 函数被调用时它应当做什么。文章逐一覆盖返回值型、副作用型、可调用对象型、默认动作、组合动作与
ACTION*自定义动作等全部类别,并结合gmock-actions.h、gmock-more-actions.h的实现与其单元测试进行源码级佐证。读完本文,你将能够像查字典一样熟练选取、组合甚至亲手编写 gMock 动作,让EXPECT_CALL/ON_CALL真正做到"指哪打哪"。
基础概念速览:动作是配合 Actions: What Should It Do? 章节中WillOnce()/WillRepeatedly()/WillByDefault()使用的行为单元。一个 mock 对象本身没有真实实现,用户通过"期望(expectation)+ 动作(action)"告知框架:某方法被调用时该做什么。gMock 的所有内置动作都定义在::testing命名空间下,这意味着在你的测试代码中既可以using ::testing::Return;单独引入,也可以直接使用testing::Return(...)全限定名。
一、返回值动作(Returning a Value)
mock 方法最常见的行为就是"返回某个值"。gMock 提供以下返回值动作:
| 动作 | 说明 |
|---|---|
Return() | 从一个返回void的 mock 函数中返回。 |
Return(value) | 返回value。若value的类型与 mock 函数的返回类型不同,value在设置期望的那一刻被转换为后者,而不是在动作执行时才转换。 |
ReturnArg<N>() | 返回第N个(从 0 开始)参数。 |
ReturnNew<T>(a1, ..., ak) | 返回new T(a1, ..., ak);每次调用都创建一个新对象。 |
ReturnNull() | 返回空指针。 |
ReturnPointee(ptr) | 返回ptr所指向的值。 |
ReturnRef(variable) | 返回对variable的引用。 |
ReturnRefOfCopy(value) | 返回对value的一份副本的引用;这份副本与动作同生命周期。 |
ReturnRoundRobin({a1, ..., ak}) | 每次调用依次返回列表中的下一个ai,到达末尾后从头开始循环。 |
1.1 深入Return(value):为何"转换发生在设置期望时"
文档特别强调:Return(value)中value与返回类型的转换是急切(eager)完成的,而非动作执行时才转换。这一语义在 gmock-actions.h 的ReturnAction实现中得到了精确落实:
- 构造阶段
ReturnAction(R value)保存原始值; - 在转换为
Action<U(Args...)>/OnceAction<U(Args...)>时,模板参数以std::is_convertible<R, U>、std::is_move_constructible<U>(或std::is_copy_constructible<U>)作为硬性约束; - 内部
Impl::State在构造时即通过value(ImplicitCast_<U>(input_value))预先把结果类型U实例化出来并保存在堆上。
源码注释揭示了一个关键陷阱:若返回类型是"类引用类型",例如 mock 返回std::string_view而Return传入std::string,如果延迟到执行期再转换,源字符串可能在动作执行前已被销毁,导致悬垂引用。因此 gMock 在 2009 年的提交中就把转换提前到"动作定型"时完成。这也提醒使用者:传给Return()的值应当能在设置期望后安全存活。
1.2ReturnRefvsReturnRefOfCopy:引用的生命周期差异
ReturnRef(variable)只是把引用转发出去,不复制,因此variable必须在 mock 被调用时仍然存活,否则行为未定义;它要求参数是非常量左值,源码中甚至显式delete了右值重载(ReturnRef(R&&) = delete),从编译期就拦截了"返回对临时量引用"的误用。而ReturnRefOfCopy(value)会把值复制一份并保存在动作对象内部,返回的是指向这份副本的引用,因此即使value在设置期望后立即销毁也没有问题——前提是动作本身存活(副本"与动作同生命周期")。相应地,ReturnRefOfCopy的实现内部直接持有值成员(见ReturnRefOfCopyAction,gmock-actions.h),并在编译期用static_assert之类的检查捕获"本应使用Return却误用ReturnRefOfCopy"的场景。
1.3ReturnArg<N>、ReturnNew<T>、ReturnPointee与智能指针
ReturnArg<N>()的实现利用std::get<k>(std::forward_as_tuple(...))把第N个参数原样返回(ReturnArgAction),因此参数类型与返回类型必须兼容,且越界访问在编译期通过enable_if<(k < sizeof...(Args))>被拦截。ReturnNew<T>(a1, ..., ak)每次被调用都会执行new T(unpacked_params...)(ReturnNewAction),适用于"每次调用需要全新对象"的场景。测试ReturnNewTest.Unary(gmock-actions_test.cc)验证了它可用于返回裸指针与指向 const 的指针。ReturnPointee(ptr)返回*pointer(ReturnPointeeAction),当指针所指向对象内容变化时,后续调用会返回最新值。ReturnNull()是多态动作,可同时用于裸指针与智能指针返回函数——测试ReturnNullTest.WorksInSmartPointerReturningFunction证实了这一点。
1.4ReturnRoundRobin:循环出值
ReturnRoundRobin({a1, ..., ak})适用于"按照预定序列反复循环返回"的场景(如依次返回1,2,3,1,2,3,...)。其实现(ReturnRoundRobinAction)在构造时通过GTEST_CHECK_(!values.empty())校验至少需要一个元素,并将状态封装在shared_ptr<State>中(含std::vector<T> values与游标size_t i),Next()在取到末尾时重置为 0 形成环。因为状态被共享,动作被复制后仍能维持连续计数。测试ReturnRoundRobinTest.WorksForInitList与WorksForVector(gmock-actions_test.cc)分别覆盖了初始化列表与std::vector两种构造方式。
二、副作用动作(Side Effects)
除了返回值,动作还可用于修改外部状态(传出参数、被测试系统的全局变量等):
| 动作 | 说明 |
|---|---|
Assign(&variable, value) | 把value赋给variable。 |
DeleteArg<N>() | delete第N个(从 0 开始)参数,该参数必须是指针。 |
SaveArg<N>(pointer) | 通过拷贝赋值把第N个参数保存到*pointer。 |
SaveArgByMove<N>(pointer) | 通过移动赋值把第N个参数保存到*pointer。 |
SaveArgPointee<N>(pointer) | 把第N个参数所指向的值保存到*pointer。 |
SetArgReferee<N>(value) | 把value赋给第N个参数所引用的变量。 |
SetArgPointee<N>(value) | 把value赋给第N个参数所指向的位置。 |
SetArgumentPointee<N>(value) | 与SetArgPointee<N>(value)等价。已废弃,文档注明将在 v1.7.0 中移除。 |
SetArrayArgument<N>(first, last) | 把源区间[first, last)的元素复制到第N个参数指向的数组(该参数可以是指针或迭代器);动作不接管源区间元素的所有权。 |
SetErrnoAndReturn(error, value) | 将errno设为error并返回value。 |
Throw(exception) | 抛出给定异常,exception可以是任何可拷贝值。自 v1.1.0 起可用。 |
2.1 参数写入族:把"读参数"变成"写参数"
SetArgReferee<N>(value)写入的是引用参数本身(T&),典型场景是"被 mock 的输出型引用参数应当被填上某个值"。SetArgPointee<N>(value)/SaveArgPointee<N>(pointer)写入的是指针参数指向的内存,二者一个往指针参数里写、一个把指针参数指向的内容读走。SaveArg<N>(pointer)按拷贝保存参数值;SaveArgByMove<N>(pointer)按移动保存,适用于不可拷贝(move-only)的参数类型(见 SaveArgByMoveAction 及工厂函数 SaveArgByMove)。
这些动作在源码中统一以std::get<N>(std::tie(args...))取出第N个参数后解引用写入。文档特别标注:SetArgumentPointee名称已废弃并将被移除,请直接使用SetArgPointee——当前仓库 gmock-actions.h 仍同时保留两个函数入口以便平滑迁移,但新代码一律写SetArgPointee。
SetArrayArgument<N>(first, last)的循环实现(SetArrayArgumentAction)会从first遍历到last,一边迭代源区间一边递增目标位置,等价于std::copy(first, last, 目标起始),非常适合为缓冲区、C 风格数组批量填充测试数据。
2.2Assign、DeleteArg、SetErrnoAndReturn的工程语义
Assign(&variable, value)在多线程/状态机测试中常用于"某调用发生后翻转开关变量"。AssignAction(gmock-actions.h)直接持有目标指针并执行*ptr_ = value_,属于典型副作用型动作。DeleteArg<N>()用于"本应消费指针的所有权"的场景。其实现(DeleteArgAction)对非指针参数的重载带有[[deprecated]]告警,提示"参数可能已迁移为智能指针,应移除此动作"。SetErrnoAndReturn(error, value)专门用于模拟read/write/ioctl等系统调用与 libc 函数的错误路径——既设置errno又返回-1。实现(SetErrnoAndReturnAction)的Perform()先执行errno = errno_;再返回结果。注意平台限制:该动作整体被#ifndef GTEST_OS_WINDOWS_MOBILE包裹,即 Windows Mobile 平台不可用;测试 gmock-actions_test.cc 的SetErrnoAndReturnTest覆盖了返回int、指针及可兼容类型三种情形。
2.3Throw的使用前提
Throw(exception)动作在 ThrowAction 中通过模板转换运算符适配任意返回类型,运行时抛出的是exception的拷贝。源码将其放在#if GTEST_HAS_EXCEPTIONS保护之下,也就是说只有编译器启用了异常(C++ 异常打开)时该动作才可用;否则用它会导致编译失败或需要配合 gtest 的异常相关死亡测试机制使用。
三、把函数、仿函数或 Lambda 当作动作(Using a Function, Functor, or Lambda)
gMock 允许"调用一个可调用对象"来替代内联返回值逻辑。下表中,"callable(可调用对象)"泛指自由函数、std::function、仿函数(functor)或 lambda:
| 动作 | 说明 |
|---|---|
f | 以传给 mock 函数的参数调用f(f为任意 callable)。 |
Invoke(f) | 以传给 mock 函数的参数调用f;f可以是全局/静态函数或仿函数。 |
Invoke(object_pointer, &class::method) | 以传给 mock 函数的参数在对象上调用成员方法。 |
InvokeWithoutArgs(f) | 调用f(全局/静态函数或仿函数);f必须不接收任何参数。 |
InvokeWithoutArgs(object_pointer, &class::method) | 调用对象上不接收任何参数的成员方法。 |
InvokeArgument<N>(arg1, arg2, ..., argk) | 调用 mock 函数的第N个(从 0 开始)参数——它必须是一个函数或仿函数——并向其传入给定的k个参数。 |
除InvokeArgument外,被调用函数的返回值将作为整个动作的返回值。
3.1 直接用 callable 作动作与Invoke家族
- 表中最上面一行
f指的是:当期望设定时直接写函数/仿函数/lambda 的名字(不带Return包裹),gMock 的Action<F>会通过可调用对象兼容性检测接受它。这使得测试可以写出.WillOnce(MyFunctor{...})之类高度内聚的表达式。 Invoke(f)、Invoke(obj, &Cls::m)、InvokeWithoutArgs(...)是显式版本。成员方法版在底层被包装为(obj_ptr->*method_ptr)(std::forward<Args>(args)...)(见 InvokeMethodAction),调用时 mock 收到的参数会被无缝转发给真实方法——这经常用来把 mock 调用"委托"给一个真实的辅助对象。- 测试 gmock-more-actions_test.cc 中的
InvokeTest系列(Nullary/Unary/…/FunctionThatTakes10Arguments)覆盖了 0 至 10 个参数的自由函数、成员方法、仿函数等情形,可作为调用形态的完整参照。
3.2Unused:忽略不想处理的参数
当自定义 callable 的形参个数少于 mock 函数时,可用::testing::Unused声明"我不关心的参数":
using ::testing::Invoke; using ::testing::Unused; double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } ... EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance));上面的Distance虽然只用到x、y,但因为第一个参数声明为Unused,它可以同时服务于形参签名不同的多个 mock 方法。源码中Unused被定义为internal::IgnoredValue的别名(gmock-actions.h),而IgnoredValue可从任意值隐式构造——这正是它能在不同签名间复用的原理。InvokeTest.FunctionWithUnusedParameters与InvokeTest.MethodWithUnusedParameters就是这一用法的实测样例。
3.3Invoke的回调所有权约束
文档特别提醒:Invoke(callback)与InvokeWithoutArgs(callback)会接管callback的所有权,且要求其为"永久对象"(permanent);callback的类型必须是基类回调类型而非派生类型,否则无法通过编译。原文档给出的例子如下:
BlockingClosure* done = new BlockingClosure; ... Invoke(done) ...; // 这无法通过编译! Closure* done2 = new BlockingClosure; ... Invoke(done2) ...; // 这可以正常工作。原因在于:gMock 需要按基类类型统一持有并最终释放该回调,若传入派生类指针,编译器无法确定正确的所有权管理类型。这一约束本质上服务于"由 mock 生命周期托管回调"的设计。
3.4InvokeArgument<N>(...):回调参数的"反向调用"
InvokeArgument是Invoke的"反向操作"——它不去调用某个已知函数,而是调用 mock 收到的第N个参数(该参数本身是一个函数/仿函数),并把用户预置的实参传给它。典型场景是模拟"回调型 API":被测代码把回调传进来,而你要验证/驱动这个回调。
using ::testing::InvokeArgument; ... InvokeArgument<2>(5, string("Hi"), std::ref(foo))上述代码会调用 mock 函数的第 2 个参数(一个 3 元 callable),以值方式传给它5和string("Hi"),以引用方式传给它foo。
引用传参规则(务必注意):InvokeArgument的参数默认按值传递,若某个参数需要按引用传递,必须用std::ref()包裹。此外文档强调一个隐蔽细节——若被调用方按引用接收参数但调用方忘了用std::ref(),则它收到的是"临时拷贝的引用"而非原始对象,这会让副作用落空。实现层面,InvokeArgument定义在 gmock-more-actions.h:其InvokeArgumentAction把N限定为enable_if<(index < sizeof...(Args))>,通过内部的FlatTuple保存实参并在执行期取出第N个 callable 加以调用。测试InvokeArgumentTest.Function5、Functor1MoveOnly、OneShotFunctor1等(gmock-more-actions_test.cc)验证了它可驱动空参函数、普通仿函数、move-only 仿函数与一次性(one-shot)仿函数等类型。
四、默认动作(Default Action)
| 动作 | 说明 |
|---|---|
DoDefault() | 执行默认动作(由ON_CALL()设定,或 gMock 的内置默认动作)。 |
DoDefault()通常用在EXPECT_CALL(...).WillRepeatedly(DoDefault())的组合里,表达"这条期望只关心参数匹配/调用次数,实际行为交给默认实现"——最常见的就是配合ON_CALL()预先设定的"桩行为",或在 mock 方法需要调用真实对象时(见 gMock Cookbook 中的Delegating Calls to a Real Object)。
两个需要牢记的约束(均可从源码与测试验证):
DoDefault()不能用在组合动作内部(例如DoAll(x, DoDefault()))。文档将其归因于技术原因,并明确说明强行使用会在运行时报错。测试 gmock-actions_test.cc 的DoDefaultDeathTest.DiesIfUsedInCompositeAction以死亡测试断言了DoAll(VoidFunc, DoDefault())触发终止。DoDefault()不能放在ON_CALL().WillByDefault()中(否则构成无限递归)。同一文件中的DoDefaultTest.CannotBeUsedInOnCall死亡测试验证了这一点。
另外要理解DoDefault()时"内置默认值"的语义:当 mock 函数返回内建类型或指针时,即使没有任何动作,gMock 也会提供默认行为——void函数直接返回、bool返回false、数值返回 0、指针返回nullptr;C++11 起若返回类型可默认构造,则默认返回默认构造的值。这个逻辑由 BuiltInDefaultValueGetter 实现:类型没有内置默认值时Get()会断言失败并终止进程。因此DoDefaultTest.ReturnsBuiltInDefaultValueByDefault与DoDefaultTest.ReturnsUserSpecifiedPerTypeDefaultValueWhenThereIsOne等测试分别验证了"无默认动作"与"用户通过DefaultValue<T>::Set()指定默认值"两种路径。DoDefaultAction本身只是一层极薄的多态包装(gmock-actions.h),真正的默认值解析发生在动作执行时。
五、组合动作(Composite Actions)
组合动作用于把多个简单动作串成一条执行链,或对动作入参做裁剪/重排:
| 动作 | 说明 |
|---|---|
DoAll(a1, a2, ..., an) | 每次调用依次执行a1到an,返回an的结果。前n-1个子动作必须返回 void,并且只能看到参数的只读视图。 |
IgnoreResult(a) | 执行动作a并忽略其结果;a不能返回 void。 |
WithArg<N>(a) | 把 mock 函数的第N个(从 0 开始)参数传给动作a并执行之。 |
WithArgs<N1, N2, ..., Nk>(a) | 把选取的(从 0 开始的)参数传给动作a并执行之。 |
WithoutArgs(a) | 不带任何参数地执行动作a。 |
5.1DoAll:经典"先副作用、后返回值"组合
DoAll是编写 mock 行为的"瑞士军刀"。最经典的用法是先写传出参数、再返回状态码:
EXPECT_CALL(mock, Read(_, _)) .WillOnce(DoAll(SetArgPointee<0>(buffer), SetArgPointee<1>(bytes_read), Return(0)));源码层面,DoAll 工厂 的注释与实现共同说明了两条硬性规则:
- 除最后一个动作外,其余子动作的返回值类型必须可"忽略"(即返回
void或可被包装为忽略值); - 前面的子动作看到的是参数的只读视图——这符合"用组合动作传值、用专用动作写参"的分工哲学,也避免了多个写动作间的执行顺序歧义。从注释与测试可推断,若违反 void 约束,通常会在编译期因返回类型不兼容而失败。
DoAll的单参数重载已被标记废弃(提示"避免对单个动作使用DoAll",见 gmock-actions.h)。
5.2WithArg/WithArgs:重排与挑选参数
WithArgs<N1, N2, ..., Nk>(action)允许你自由挑选、重排甚至重复使用mock 参数去喂给内层动作。例如当内层函数需要的参数顺序与 mock 签名不一致时:
using ::testing::WithArgs; EXPECT_CALL(mock, IsPointVisible(_, _)) .WillOnce(WithArgs<1, 0>(Invoke(MyCompare))); // 调换参数顺序- 单参数选取用
WithArg<N>(无s)。 - 内层动作不要求是
Invoke——任何单参/多参动作皆可。 - 参数可重复,如
WithArgs<2, 3, 3, 5>(...);也可只挑一部分,如WithArgs<0, 1, 3>(Ternary)。 - 当内层动作的参数比选出的参数少时,多余参数会被丢弃。
实现上,WithArg/WithArgs/WithoutArgs都归一化到模板类WithArgsAction(gmock-actions.h),WithoutArgs本质上是"0 个参数被选出"的特例(gmock-actions.h)。测试 gmock-actions_test.cc 的WithArgsTest系列非常系统:OneArg/TwoArgs/TenArgs覆盖参数数量边界,RepeatedArguments验证WithArgs<1, 1, 1, 1>(SumOf4)这样的重复选取,ReversedArgumentOrder验证WithArgs<1, 0>颠倒顺序,NonInvokeAction则证明内层动作不必是Invoke,ReturnReference甚至允许内层动作返回引用。
5.3IgnoreResult的定位
IgnoreResult(a)的语义是"执行但丢掉结果",适用于你想复用某个"有返回值却被当作纯副作用使用"的函数或动作,同时又能把它塞进要求 void 的上下文(例如放在DoAll的非末位)。实现层面,IgnoreResultAction会把内层函数包装为忽略返回值的形式(参见MakeResultIgnoredValue机制,gmock-actions.h 与 internal 工具头 gmock-internal-utils.h)。
六、自定义动作(Defining Actions)
当内置动作无法覆盖业务语义时,gMock 提供了ACTION*宏家族来定义命名参数化动作:
| 宏 | 说明 |
|---|---|
ACTION(Sum) { return arg0 + arg1; } | 定义动作Sum(),返回 mock 函数第 0、1 个参数之和。 |
ACTION_P(Plus, n) { return arg0 + n; } | 定义动作Plus(n),返回 mock 函数第 0 个参数与n之和。 |
ACTION_Pk(Foo, p1, ..., pk) { statements; } | 定义带k个参数的动作Foo(p1, ..., pk),执行给定语句。 |
在宏体内,mock 函数的参数以arg0、arg1、…、arg9(最多 10 个)直接可用,并附带类型别名arg0_type、arg1_type…;同时还能访问args(完整参数元组)与args_type。例如测试文件 gmock-actions_test.cc 中就用ACTION(ReturnArity) { return std::tuple_size_v<args_type>; }定义了一个"返回 mock 函数参数个数"的动作,并通过Action<int(int)>(ReturnArity()).Perform(std::make_tuple(0))直接验证。
6.1 宏到类的展开机制
ACTION(name)会在编译期生成名为nameAction的类,而ACTION_P/ACTION_Pk生成nameActionP/nameActionPk(见 gmock-actions.h 及宏内部实现GMOCK_INTERNAL_ACTION,gmock-actions.h):
- 参数的模板类型别名自动生成(
GMOCK_ACTION_TYPENAME_PARAMS_),因而使用ACTION_P(Plus, n)后可在函数体重写n_type以表达与参数类型相关的逻辑; - 每个
ACTION_P变体在构造时通过std::forward<param##_type>完美转发保存参数(对应GMOCK_ACTION_INIT_PARAMS_),支持 move-only 参数类型; - 生成的动作类带
template <typename F> operator Action<F>()转换运算符,因此能自动适配不同签名的 mock 函数——这正是"宏定义动作天然多态"的根源; ACTION()系列是模板展开实现,因此在类内部或函数内部无法定义。
使用位置约束(重要):ACTION*宏不能在函数或类内部使用——文档明确列出此限制。其根因也写在头文件注释中(gmock-actions.h):宏生成的代码是模板,C++ 不允许在局部类中声明模板;但这并不妨碍在局部作用域直接使用普通 lambda 或仿函数作为动作。
6.2 更底层的自定义途径(进阶)
头文件注释(gmock-actions.h)给出了一条工程建议:当某个自定义动作会被大量复用时,优先考虑实现ActionInterface或使用MakePolymorphicAction(),而非宏。宏虽然开发效率高,但对"mock 函数参数类型"与"动作参数类型"的控制粒度较粗,编译错误信息不够友好;而ActionInterface方案允许按参数类型重载。实现ActionInterface需要两件套:
// 1. 一个实现 ActionInterface 的类,实现 Perform() // 2. 一个返回 Action 对象的工厂函数核心接口定义在 gmock-actions.h:ActionInterface<F>暴露Result Perform(const ArgumentTuple& args)(其中ArgumentTuple是 mock 函数参数的std::tuple)。测试 gmock-actions_test.cc 中的MyActionImpl与IsNotZero分别演示了"实现ActionInterface后直接构造Action"以及配合MakeAction()使用的两种方式。此外,PolymorphicAction(gmock-actions.h)让你仅凭一个带template Perform()的拷贝实现类,就能生成可适配任意签名的动作,Return()、ReturnNull()等多态内置动作正是由此机制提供。
七、总结:动作的选取方法论
面对一个 mock 调用,可按下述决策链快速锁定动作:
- 只想返回:值用
Return,引用用ReturnRef(注意被引用变量生命周期),需要独立副本引用用ReturnRefOfCopy,序列/循环值用ReturnRoundRobin,返回参数之一用ReturnArg,返回堆上新对象用ReturnNew,空指针用ReturnNull。 - 想改外部状态:写引用参数用
SetArgReferee,写指针目标用SetArgPointee(别再用废弃的SetArgumentPointee),批量拷贝到数组用SetArrayArgument,读走参数用SaveArg/SaveArgPointee/SaveArgByMove,直接删参数用DeleteArg,模拟系统调用失败用SetErrnoAndReturn,想抛异常用Throw(需启用 C++ 异常)。 - 想把调用转交给已有逻辑:自由函数/仿函数/lambda 用
Invoke(或直接写 callable),成员函数用Invoke(obj, &Cls::m),无参版本用InvokeWithoutArgs,调用传入的回调用InvokeArgument;签名不匹配的参数用Unused占位。 - 想把默认行为并入期望:用
DoDefault(),但牢记其不可嵌入组合动作、不可用于ON_CALL。 - 想串联/改写入参:先副作用后返回用
DoAll(前导动作须为 void),忽略结果用IgnoreResult,重排/挑选/丢弃参数用WithArg/WithArgs/WithoutArgs。 - 内置不够用:小而专用用
ACTION/ACTION_P/ACTION_Pk(只能在命名空间作用域定义);高复用、要求精细类型控制则实现ActionInterface或PolymorphicAction。
每个动作的签名、所有权语义与平台/编译器限制,均可在本仓库对应源码中逐一核对:动作声明集中在 googlemock/include/gmock/gmock-actions.h 与 googlemock/include/gmock/gmock-more-actions.h;行为契约由 googlemock/test/gmock-actions_test.cc 与 googlemock/test/gmock-more-actions_test.cc 中的数百个测试守护。若需进一步了解动作与EXPECT_CALL/ON_CALL的配合范式,可继续阅读 gmock_for_dummies、gmock_cook_book 与 gmock_cheat_sheet。
【免费下载链接】googletestGoogleTest - Google Testing and Mocking Framework项目地址: https://gitcode.com/GitHub_Trending/go/googletest
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考