Mocking 参考

此页面列出了 GoogleTest 提供的用于创建和使用模拟对象的功能。 要使用它们,请添加 #include <gmock/gmock.h>

GoogleTest 定义了以下用于处理 mock 的宏。

MOCK_METHOD

MOCK_METHOD(return_type,method_name, (args...));
MOCK_METHOD(return_type,method_name, (args...), (specs...));

在 mock 类中定义一个 mock 方法 method_name,其参数为 (args...),返回类型为 return_type

MOCK_METHOD 的参数与方法声明相对应。 可选的第四个参数 specs... 是以逗号分隔的限定符列表。 接受以下限定符:

限定符 含义
const 使 mock 方法成为 const 方法。 如果覆盖 const 方法,则为必需。
override override 标记该方法。 如果覆盖 virtual 方法,建议使用。
noexcept noexcept 标记该方法。 如果覆盖 noexcept 方法,则为必需。
Calltype(calltype) 设置方法的调用类型,例如 Calltype(STDMETHODCALLTYPE)。 在 Windows 上很有用。
ref(qualifier) 使用给定的引用限定符标记该方法,例如 ref(&)ref(&&)。 如果覆盖具有引用限定符的方法,则为必需。

请注意,如果参数未被适当的括号包围,则参数中的逗号会阻止 MOCK_METHOD 正确解析参数。 请参见以下示例

class MyMock {
 public:
  // The following 2 lines will not compile due to commas in the arguments:
  MOCK_METHOD(std::pair<bool, int>, GetPair, ());              // Error!
  MOCK_METHOD(bool, CheckMap, (std::map<int, double>, bool));  // Error!

  // One solution - wrap arguments that contain commas in parentheses:
  MOCK_METHOD((std::pair<bool, int>), GetPair, ());
  MOCK_METHOD(bool, CheckMap, ((std::map<int, double>), bool));

  // Another solution - use type aliases:
  using BoolAndInt = std::pair<bool, int>;
  MOCK_METHOD(BoolAndInt, GetPair, ());
  using MapIntDouble = std::map<int, double>;
  MOCK_METHOD(bool, CheckMap, (MapIntDouble, bool));
};

MOCK_METHOD 必须在 mock 类定义的 public: 部分中使用,无论被 mock 的方法在基类中是 publicprotected 还是 private

EXPECT_CALL

EXPECT_CALL(mock_object,method_name(matchers...))

创建一个 expectation,期望对象 mock_object 的方法 method_name 被调用,其参数与给定的 matchers matchers... 匹配。 EXPECT_CALL 必须位于任何调用 mock 对象之前。

参数 matchers... 是以逗号分隔的 matchers 列表,对应于方法 method_name 的每个参数。 该 expectation 仅适用于 method_name 的调用,其参数与所有 matchers 匹配。 如果省略 (matchers...),则该 expectation 的行为就像每个参数的 matcher 都是一个 通配符 matcher (_)。 有关所有内置 matchers 的列表,请参见 Matchers 参考

以下可链式子句可用于修改 expectation,并且必须按以下顺序使用它们:

EXPECT_CALL(mock_object, method_name(matchers...))
    .With(multi_argument_matcher)  // Can be used at most once
    .Times(cardinality)            // Can be used at most once
    .InSequence(sequences...)      // Can be used any number of times
    .After(expectations...)        // Can be used any number of times
    .WillOnce(action)              // Can be used any number of times
    .WillRepeatedly(action)        // Can be used at most once
    .RetiresOnSaturation();        // Can be used at most once

请参见下面每个修改器子句的详细信息。

With

.With(multi_argument_matcher)

限制 expectation 仅适用于 mock 函数调用,其参数整体上与多参数 matcher multi_argument_matcher 匹配。

GoogleTest 将所有参数作为单个元组传递到 matcher 中。 因此,参数 multi_argument_matcher 必须是类型为 Matcher<std::tuple<A1, ..., An>> 的 matcher,其中 A1, ..., An 是函数参数的类型。

例如,以下代码设置了 expectation,即调用 my_mock.SetPosition() 时带有任意两个参数,第一个参数小于第二个参数:

using ::testing::_;
using ::testing::Lt;
...
EXPECT_CALL(my_mock, SetPosition(_, _))
    .With(Lt());

GoogleTest 为 2 元组提供了一些内置 matcher,包括上面的 Lt() matcher。 请参见 多参数 Matchers

With 子句在 expectation 上最多可以使用一次,并且必须是第一个子句。

Times

.Times(cardinality)

指定 mock 函数调用被期望的次数。

参数 cardinality 表示期望的调用次数,可以是以下之一,所有这些都在 ::testing 命名空间中定义:

基数 含义
AnyNumber() 该函数可以被调用任意次数。
AtLeast(n) 期望函数调用至少 n 次。
AtMost(n) 期望函数调用最多 n 次。
Between(m, n) 期望函数调用在 mn 之间(包括 mn)。
Exactly(n)n 期望函数调用恰好 n 次。 如果 n 为 0,则不应发生调用。

如果省略 Times 子句,GoogleTest 会按如下方式推断基数:

Times 子句在 expectation 上最多可以使用一次。

InSequence

.InSequence(sequences...)

指定 mock 函数调用应按特定顺序进行。

参数 sequences... 是任意数量的 Sequence 对象。 分配给同一序列的期望调用应按声明期望的顺序发生。

例如,以下代码设置了 expectation,即在调用 my_mockGetSize()Describe() 方法之前,先调用 Reset() 方法,并且 GetSize()Describe() 的调用顺序可以相互任意:

using ::testing::Sequence;
Sequence s1, s2;
...
EXPECT_CALL(my_mock, Reset())
    .InSequence(s1, s2);
EXPECT_CALL(my_mock, GetSize())
    .InSequence(s1);
EXPECT_CALL(my_mock, Describe())
    .InSequence(s2);

InSequence 子句可以在 expectation 上使用任意次数。

另请参见 InSequence

之后

.After(expectations...)

指定模拟函数调用应在一个或多个其他调用之后发生。

参数 expectations... 最多可以是五个 ExpectationExpectationSet 对象。 模拟函数调用应在所有给定的期望之后发生。

例如,以下代码设置期望,即仅在调用 InitX()InitY() 之后才调用 my_mockDescribe() 方法。

using ::testing::Expectation;
...
Expectation init_x = EXPECT_CALL(my_mock, InitX());
Expectation init_y = EXPECT_CALL(my_mock, InitY());
EXPECT_CALL(my_mock, Describe())
    .After(init_x, init_y);

当期望的前提条件数量很多或可变时,例如,ExpectationSet 对象很有用

using ::testing::ExpectationSet;
...
ExpectationSet all_inits;
// Collect all expectations of InitElement() calls
for (int i = 0; i < element_count; i++) {
  all_inits += EXPECT_CALL(my_mock, InitElement(i));
}
EXPECT_CALL(my_mock, Describe())
    .After(all_inits);  // Expect Describe() call after all InitElement() calls

可以在期望上多次使用 After 子句。

WillOnce

.WillOnce(action)

指定在调用时模拟函数的实际行为,仅针对单个匹配的函数调用。

参数 action 表示函数调用将执行的动作。 有关内置操作的列表,请参见操作参考

当未指定 Times 时,使用 WillOnce 隐式地在期望上设置基数。 请参阅Times

每个匹配的函数调用将按声明的顺序执行下一个动作。 例如,以下代码指定 my_mock.GetNumber() 预计将被调用 3 次,并且在第一次、第二次和第三次调用时分别返回 123

using ::testing::Return;
...
EXPECT_CALL(my_mock, GetNumber())
    .WillOnce(Return(1))
    .WillOnce(Return(2))
    .WillOnce(Return(3));

可以在期望上多次使用 WillOnce 子句。 与 WillRepeatedly 不同,提供给每个 WillOnce 调用的操作最多被调用一次,因此可以是仅移动类型和/或具有 && 限定的调用运算符。

WillRepeatedly

.WillRepeatedly(action)

指定在调用时模拟函数的实际行为,对于所有后续匹配的函数调用。 如果有的话,在 WillOnce 子句中指定的操作执行完毕后生效。

参数 action 表示函数调用将执行的动作。 有关内置操作的列表,请参见操作参考

当未指定 Times 时,使用 WillRepeatedly 隐式地在期望上设置基数。 请参阅Times

如果已指定任何 WillOnce 子句,则匹配的函数调用将在 WillRepeatedly 指定的操作之前执行这些操作。 请参见以下示例

using ::testing::Return;
...
EXPECT_CALL(my_mock, GetName())
    .WillRepeatedly(Return("John Doe"));  // Return "John Doe" on all calls

EXPECT_CALL(my_mock, GetNumber())
    .WillOnce(Return(42))        // Return 42 on the first call
    .WillRepeatedly(Return(7));  // Return 7 on all subsequent calls

每个期望最多可以使用一次 WillRepeatedly 子句。

RetiresOnSaturation

.RetiresOnSaturation()

指示在达到预期的匹配函数调用次数后,期望将不再处于活动状态。

RetiresOnSaturation 子句仅对具有上限基数的期望有意义。 在期望已饱和(已达到上限)之后,它将失效(不再匹配任何函数调用)。 请参见以下示例

using ::testing::_;
using ::testing::AnyNumber;
...
EXPECT_CALL(my_mock, SetNumber(_))  // Expectation 1
    .Times(AnyNumber());
EXPECT_CALL(my_mock, SetNumber(7))  // Expectation 2
    .Times(2)
    .RetiresOnSaturation();

在上面的示例中,对 my_mock.SetNumber(7) 的前两次调用与期望 2 匹配,然后期望 2 变为非活动状态并且不再匹配任何调用。 然后,对 my_mock.SetNumber(7) 的第三次调用将与期望 1 匹配。 如果期望 2 上没有 RetiresOnSaturation(),则对 my_mock.SetNumber(7) 的第三次调用将再次与期望 2 匹配,从而产生失败,因为超过了 2 次调用的限制。

每个期望最多可以使用一次 RetiresOnSaturation 子句,并且必须是最后一个子句。

ON_CALL

ON_CALL(mock_object,method_name(matchers...))

定义当使用与给定的匹配器 matchers... 匹配的参数调用对象 mock_object 的方法 method_name 时会发生什么。 需要一个修饰符子句来指定该方法的行为。设置该方法将被调用的任何期望。

参数 matchers... 是一个逗号分隔的匹配器列表,它们对应于方法 method_name 的每个参数。 ON_CALL 规范将仅适用于 method_name 的调用,这些调用的参数与所有匹配器都匹配。 如果省略了 (matchers...),则行为就像每个参数的匹配器都是一个 通配符匹配器 (_)。 有关所有内置匹配器的列表,请参见匹配器参考

以下可链式子句可用于设置方法的行为,并且必须按以下顺序使用它们

ON_CALL(mock_object, method_name(matchers...))
    .With(multi_argument_matcher)  // Can be used at most once
    .WillByDefault(action);        // Required

请参见下面每个修改器子句的详细信息。

With

.With(multi_argument_matcher)

将规范限制为仅匹配整个多参数匹配器 multi_argument_matcher 的模拟函数调用。

GoogleTest 将所有参数作为单个元组传递到 matcher 中。 因此,参数 multi_argument_matcher 必须是类型为 Matcher<std::tuple<A1, ..., An>> 的 matcher,其中 A1, ..., An 是函数参数的类型。

例如,以下代码设置了在任何两个参数调用 my_mock.SetPosition() 时的默认行为,第一个参数小于第二个参数

using ::testing::_;
using ::testing::Lt;
using ::testing::Return;
...
ON_CALL(my_mock, SetPosition(_, _))
    .With(Lt())
    .WillByDefault(Return(true));

GoogleTest 为 2 元组提供了一些内置 matcher,包括上面的 Lt() matcher。 请参见 多参数 Matchers

每个 ON_CALL 语句最多可以使用一次 With 子句。

WillByDefault

.WillByDefault(action)

指定匹配的模拟函数调用的默认行为。

参数 action 表示函数调用将执行的动作。 有关内置操作的列表,请参见操作参考

例如,以下代码指定默认情况下,对 my_mock.Greet() 的调用将返回 "hello"

using ::testing::Return;
...
ON_CALL(my_mock, Greet())
    .WillByDefault(Return("hello"));

WillByDefault 指定的操作将被匹配的 EXPECT_CALL 语句上指定的操作取代(如果有)。 请参见 EXPECT_CALLWillOnceWillRepeatedly 子句。

每个 ON_CALL 语句必须恰好使用一次 WillByDefault 子句。

GoogleTest 定义了以下用于处理模拟的类。

DefaultValue

::testing::DefaultValue<T>

允许用户为类型 T 指定默认值,该类型既可复制又可公开销毁(即可用作函数返回类型的任何类型)。 对于返回类型为 T 的模拟函数,此默认值从不指定动作的函数调用返回。

提供静态方法 Set()SetFactory()Clear() 来管理默认值

// Sets the default value to be returned. T must be copy constructible.
DefaultValue<T>::Set(value);

// Sets a factory. Will be invoked on demand. T must be move constructible.
T MakeT();
DefaultValue<T>::SetFactory(&MakeT);

// Unsets the default value.
DefaultValue<T>::Clear();

NiceMock

::testing::NiceMock<T>

表示一个模拟对象,该对象禁止对不感兴趣的调用发出警告。 模板参数 T 是任何模拟类,除了另一个 NiceMockNaggyMockStrictMock

NiceMock<T> 的用法类似于 T 的用法。 NiceMock<T>T 的子类,因此可以在接受类型为 T 的对象的任何地方使用它。 此外,可以使用 T 的构造函数接受的任何参数来构造 NiceMock<T>

例如,如果调用了 DoSomething() 以外的方法,则以下代码禁止对类型为 MockClass 的模拟 my_mock 发出警告

using ::testing::NiceMock;
...
NiceMock<MockClass> my_mock("some", "args");
EXPECT_CALL(my_mock, DoSomething());
... code that uses my_mock ...

仅当直接在类 T 的定义中使用 MOCK_METHOD 宏定义的模拟方法时,NiceMock<T> 才有效。 如果模拟方法是在 T 的基类中定义的,则可能仍会生成警告。

如果 T 的析构函数不是虚拟的,则 NiceMock<T> 可能无法正常工作。

NaggyMock

::testing::NaggyMock<T>

代表一个模拟对象,它会在不重要的调用上生成警告。模板参数 T 可以是任何模拟类,但不能是另一个 NiceMockNaggyMockStrictMock

NaggyMock<T> 的用法类似于 T 的用法。NaggyMock<T>T 的子类,因此可以在接受 T 类型对象的任何地方使用它。此外,NaggyMock<T> 可以使用 T 的构造函数接受的任何参数来构造。

例如,以下代码会在类型为 MockClass 的模拟对象 my_mock 上,如果调用了除 DoSomething() 之外的方法,则生成警告

using ::testing::NaggyMock;
...
NaggyMock<MockClass> my_mock("some", "args");
EXPECT_CALL(my_mock, DoSomething());
... code that uses my_mock ...

默认情况下,类型为 T 的模拟对象的行为方式与 NaggyMock<T> 相同。

StrictMock

::testing::StrictMock<T>

代表一个模拟对象,它会在不重要的调用上生成测试失败。模板参数 T 可以是任何模拟类,但不能是另一个 NiceMockNaggyMockStrictMock

StrictMock<T> 的用法类似于 T 的用法。StrictMock<T>T 的子类,因此可以在接受 T 类型对象的任何地方使用它。此外,StrictMock<T> 可以使用 T 的构造函数接受的任何参数来构造。

例如,以下代码会在类型为 MockClass 的模拟对象 my_mock 上,如果调用了除 DoSomething() 之外的方法,则生成测试失败

using ::testing::StrictMock;
...
StrictMock<MockClass> my_mock("some", "args");
EXPECT_CALL(my_mock, DoSomething());
... code that uses my_mock ...

StrictMock<T> 仅适用于直接在类 T 的定义中使用 MOCK_METHOD 宏定义的模拟方法。 如果模拟方法是在 T 的基类中定义的,则可能不会生成失败。

如果 T 的析构函数不是虚函数,则 StrictMock<T> 可能无法正常工作。

Sequence

::testing::Sequence

代表期望的时序。 有关用法,请参见 EXPECT_CALLInSequence 子句。

InSequence

::testing::InSequence

此类型的对象会导致在其作用域中遇到的所有期望都置于匿名序列中。

这允许更方便地在单个序列中表达多个期望

using ::testing::InSequence;
{
  InSequence seq;

  // The following are expected to occur in the order declared.
  EXPECT_CALL(...);
  EXPECT_CALL(...);
  ...
  EXPECT_CALL(...);
}

InSequence 对象的名称无关紧要。

Expectation

::testing::Expectation

表示由 EXPECT_CALL 创建的模拟函数调用期望

using ::testing::Expectation;
Expectation my_expectation = EXPECT_CALL(...);

可用于指定期望的序列; 请参见 EXPECT_CALLAfter 子句。

ExpectationSet

::testing::ExpectationSet

表示一组模拟函数调用期望。

使用 += 运算符将 Expectation 对象添加到集合中

using ::testing::ExpectationSet;
ExpectationSet my_expectations;
my_expectations += EXPECT_CALL(...);

可用于指定期望的序列; 请参见 EXPECT_CALLAfter 子句。