匹配器参考
约 3261 字大约 11 分钟
2025-04-07
匹配器用于匹配单个参数。 你可以在 ON_CALL()
或 EXPECT_CALL()
中使用匹配器,或通过以下两个宏来直接验证值:
宏 | 描述 |
---|---|
EXPECT_THAT(actual_value, matcher) | 断言 actual_value 匹配 matcher 。 |
ASSERT_THAT(actual_value, matcher) | 功能同 EXPECT_THAT(actual_value, matcher) ,但会产生致命失败。 |
注意
虽然可以通过 EXPECT_THAT(actual, expected_value)
进行等值匹配,但需注意隐式转换可能导致的意外结果。 例如,EXPECT_THAT(some_bool, "some_string")
可以通过编译且可能匹配通过。
最佳实践:使用 EXPECT_THAT(actual_value, Eq(expected_value))
或 EXPECT_EQ(actual_value, expected_value)
进行等值比较。
内置匹配器按功能可分为以下类别。 其中 argument
为函数参数,例如上述示例中的 actual_value
, 或者 EXPECT_THAT(mock_object, method(mathcers))
中 method
的参数。 除特别说明外,所有匹配器均定义在 ::testing
命名空间。
通配符匹配器
匹配器 | 描述 |
---|---|
_ | argument 为任意合适类型值。 |
A<type>() An<type>() | argument 为任意 type 类型值。 |
通用比较匹配器
匹配器 | 描述 |
---|---|
Eq(value) value | argument == value 。 |
Ge(value) | argument >= value 。 |
Gt(value) | argument > value 。 |
Le(value) | argument <= value 。 |
Lt(value) | argument < value 。 |
Ne(value) | argument != value 。 |
IsFalse() | argument 在布尔上下文中求值为 false 。 |
DistanceFrom(target, m) | argument 与 target 的绝对差(abs(argument - target) )匹配 m |
DistanceFrom(target, get_distance, m) | argument 与target 的距离(get_distance(argument, target) ) 匹配 m |
IsTrue() | argument 在布尔上下文中求值为 true 。 |
IsNull() | argument 为空指针(兼容裸指针和智能指针)。 |
NotNull() | argument 为非空指针(兼容裸指针和智能指针)。 |
Optional(m) | argument 为包含值匹配 m 的 optional<> 。使用 nullopt 可以检测 optional<> 是否有值。若内部类型不支持 == 运算符,请使用 Eq(nullopt) 。 |
VariantWith<T>(m) | argument 为持有类型为 T 且其值匹配 m 的 variant<> 。 |
Ref(variable) | argument 为 variable 的引用。 |
TypedEq<type>(value) | argument 类型为 type 且等于 value 。当模拟函数存在重载时,可能需要使用 TypeEq<T>(m) 而非 Eq(m) 。 |
除 Ref()
外,这些匹配器都持有 value
的拷贝,以防其稍后被更改或销毁。 若编译器报错 value
没有拷贝构造函数,可以尝试包裹 std::ref()
,如 Eq(std::ref(non_copyable_value))
。 用户需确保这种情况下 non_copyable_value
不会被更改或销毁,否则匹配器的功能会改变。
IsTrue
和 IsFalse
适用于需要使用匹配器,或者值只能显式转换成布尔值而不支持隐式转换的场景。 对于其他情况,应使用 EXPECT_TRUE
和 EXPECT_FALSE
断言。
浮点数匹配器
匹配器 | 描述 |
---|---|
DoubleEq(a_double) | argument 为近似等于 a_double 的 double 值(NaN 视为不相等)。 |
FloatEq(a_float) | argument 为近似等于 a_float 的 float 值(NaN 视为不相等)。 |
NanSensitiveDoubleEq(a_double) | argument 为近似等于 a_double 的 double 值(NaN 视为相等)。 |
NanSensitiveFloatEq(a_float) | argument 为近似等于 a_float 的 float 值(NaN 视为相等)。 |
IsNan() | argument 为 NaN 。 |
上述匹配器使用基于 ULP 的比较(与 GoogleTest 相同)。 它们会根据期望值的绝对值自动选择合理的误差范围。 DoubleEq()
和 FloatEq()
符合 IEEE 标准,在比较两个 NaN
的相等性时返回 false
。 NanSensitive*
版本则将两个 NaN
视为相等,这通常更符合用户预期。
匹配器 | 描述 |
---|---|
DoubleNear(a_double, max_abs_error) | argument 是接近 a_double 的 double 值(绝对误差 <= max_abs_error ), 两个 NaN 视为不相等。 |
FloatNear(a_float, max_abs_error) | argument 是接近 a_float 的 float 值(绝对误差 <= max_abs_error ), 两个 NaN 视为不相等。 |
NonSensitiveDoubleNear(a_double, max_abs_error) | argument 是接近 a_double 的 double 值(绝对误差 <= max_abs_error ), 两个 NaN 视为相等。 |
NonSensitiveFloatNear(a_float, max_abs_error) | argument 是接近 a_float 的 float 值(绝对误差 <= max_abs_error ), 两个 NaN 视为相等。 |
字符串匹配器
argument
可以是 C 字符串或 C++ 字符串对象:
匹配器 | 描述 |
---|---|
ContainsRegex(string) | argument 匹配给定正则表达式。 |
EndsWith(suffix) | argument 以 suffix 结尾。 |
HasSubstr(string) | argument 包含子串 string 。 |
IsEmpty() | argument 为空字符串。 |
MatchesRegex(string) | argument 完整匹配给定正则表达式(从第一个字符开始到最后一个字符结束)。 |
StartsWith(prefix) | argument 以 prefix 开头。 |
StrCaseEq(string) | argument 与 string 相等(忽略大小写)。 |
StrCaseNe(string) | argument 与 string 不相等(忽略大小写)。 |
StrEq(string) | argument 与 string 相等。 |
StrNe(string) | argument 与 string 不相等。 |
WhenBase64Unescaped(m) | argument 是符合 RFC 4648 定义的 Web 安全的 Base64 转码字符串,且解码后匹配 m 。 |
ContainsRegex()
和 MatchesRegex()
会接管 RE
对象的所有权。 它们使用的正则表达式语法定义参见此处。 除 ContainsRegex()
和 MatchesRegex()
外,其他匹配器都支持宽字符串。
容器匹配器
大多数 STL 风格容器支持 ==
操作符,因此可以直接使用 Eq(expected_container)
或 expected_container
来精确匹配容器。 如果需要内联指定元素、更灵活地匹配元素或获取更详细的错误信息,则可以使用以下匹配器:
匹配器 | 描述 |
---|---|
BeginEndDistanceIs(m) | argument 是迭代器 begin() 和 end() 间距匹配 m 的容器。例如 BeginEndDistanceIs(2) 或 BeginEndDistanceIs(Lt(2)) 。对于定义了 size() 方法的容器,使用 SizeIs(m) 可能更高效。 |
ContainerEq(container) | 与 Eq(container) 相同,但失败信息会额外显示两个容器之间的差异元素。 |
Contains(e) | argument 包含至少一个匹配 e 的元素(e 可以是值或匹配器)。 |
Contains(e).Times(n) | argument 包含 n 个匹配 e 的元素(e 和 n 可以是值或匹配器)。不同于普通的 Contains 和 Each ,此方法支持校验任意出现次数,包括使用 Contains(e).Times(0) 校验不存在的情况。 |
Each(e) | argument 是每个元素都匹配 e 的容器(e 可以是值或匹配器)。 |
ElementsAre(e0, e1, ..., en) | argument 包含 n + 1 个元素,其中第 i 个元素匹配 ei (ei 可以是值或匹配器)。 |
ElementsAreArray({e0, e1, ..., en}) ElementsAreArray(a_container) ElementsAreArray(begin, end) ElementsAreArray(array) ElementsAreArray(array, count) | 功能同 ElementsAre() ,但期望值/匹配器来自初始化列表、STL 风格容器、迭代器范围或 C 风格数组。 |
IsEmpty() | argument 为空容器(container.empty() )。 |
IsSubsetOf({e0, e1, ..., en}) IsSubsetOf(a_container) IsSubsetOf(begin, end) IsSubsetOf(array) IsSubsetOf(array, count) | argument 匹配 UnorderedElementsAre(x0, x1, ..., xk) ,其中 {x0, x1, ..., xk} 是预期匹配器的某个子集。 |
IsSupersetOf({e0, e1, ..., en}) IsSupersetOf(a_container) IsSupersetOf(begin, end) IsSupersetOf(array) IsSupersetOf(array, count) | argument 的某个子集匹配 UnorderedElementsAre( 预期匹配器) 。 |
Pointwise(m, container) Pointwise(m, {e0, e1, ..., en}) | argument 包含与 container 相同数量的元素,且其中相同位置的元素匹配二元匹配器 m 。例如,Pointwise(Le(), upper_bounds) 验证 argument 的每个元素都不大于 upper_bounds 的对应元素(详见下文)。 |
SizeIs(m) | argument 是大小匹配 m 的容器。例如, SizeIs(2) 或 SizeIs(Lt(2)) 。 |
UnorderedElementsAre(e0, e1, ..., en) | argument 包含 n + 1 个元素,且存在某种排列使得每个元素匹配对应的 ei (ei 可以是值或匹配器)。 |
UnorderedElementsAreArray({e0, e1, ..., en}) UnorderedElementsAreArray(a_container) UnorderedElementsAreArray(begin, end) UnorderedElementsAreArray(array) UnorderedElementsAreArray(array, count) | 功能同 UnorderedElementsAre() ,但期望值/匹配器来自初始化列表、STL 风格容器、迭代器范围或 C 风格数组。 |
UnorderedPointwise(m, container) UnorderedPointwise(m, {e0, e1, ..., en}) | 功能同 Pointwise(m, container) ,但忽略元素顺序。 |
WhenSorted(m) | 当 argument 使用 < 运算符排序后,匹配容器匹配器 m 。例如,WhenSorted(ElementsAre(1, 2, 3)) 验证 argument 包含元素 1、2、3(忽略顺序)。 |
WhenSortedBy(comparator, m) 。 | 功能同 WhenSorted(m) ,但使用指定比较器代替 < 进行排序。例如,WhenSortedBy(std::greater(), ElementsAre(3, 2, 1)) 。 |
注
这些匹配器还可以匹配:
- 按引用传递的原生数组,如
Foo(const int (&a)[5])
。 - 以指针和长度形式传递的数组,如
Bar(const T* buffer, int len)
,见多参数匹配器。
- 按引用传递的原生数组,如
被匹配的数组可以是多维数组(即元素本身可以是数组)。
Pointwise(m, ...)
和UnorderedPointwise(m, ...)
中的m
应为匹配::std::tuple<T, U>
的匹配器, 其中T
和U
分别为实际容器和期望容器的元素类型。 例如,要比较两个不支持operator==
的Foo
容器时,可以编写:MATCHER(FooEq, "") { return std::get<0>(arg).Equals(std::get<1>(arg)); } ... EXPECT_THAT(actual_foos, Pointwise(FooEq(), expected_foos));
成员匹配器
匹配器 | 描述 |
---|---|
Field(&class::field, m) | argument.field (当 argument 为普通指针时为 argument->field )匹配 m ,其中 argument 为 class 类型的对象。 |
Field(field_name, &class::field, m) | 功能同双参数版本,但提供更友好的错误信息。 |
Key(e) | argument.first 匹配 e (e 可以是值或匹配器)。例如,Contains(Key(Le(5))) 可验证 map 中存在键 <= 5 。 |
Pair(m1, m2) | argument 是 std::pair 类型,其 first 字段匹配 m1 且 second 字段匹配 m2 。 |
FieldsAre(m...) | argument 是符合结构化协议的对象,其各字段依次匹配 m... 。兼容对象包括支持 std::tuple_size<Obj> + get<I>(obj) 协议的类型,C++17 及以上版本还支持符合结构化绑定的聚合类型。 |
Property(&class::property, m) | argument.property() (当 argument 为普通指针时使用 argument->property() )匹配匹配器 m ,其中 argument 是 class 类型的对象。property() 方法必须为无参 const 方法。 |
Property(property_name, &class::property, m) | 功能同双参数版本,但提供更友好的错误信息。 |
注意
不要对不属于你的成员函数使用 Property()
匹配器,因为获取函数地址具有脆弱性且不属于函数契约范畴。
注
FieldsAre()
可匹配任何支持结构化绑定的类型,如 std::tuple
、std::pair
、std::array
和聚合类型。 例如:
std::tuple<int, std::string> my_tuple{7, "hello world"};
EXPECT_THAT(my_tuple, FieldsAre(Ge(0), HasSubstr("hello")));
struct MyStruct {
int value = 42;
std::string greeting = "aloha";
};
MyStruct s;
EXPECT_THAT(s, FieldsAre(42, "aloha"));
函数/函数对象匹配器
匹配器 | 描述 |
---|---|
ResultOf(f, m) | f(argument) 匹配 m , 其中 f 为函数或函数对象。 |
ResultOf(result_description, f, m) | 功能同双参数版本,但提供更友好的错误消息。 |
指针匹配器
匹配器 | 描述 |
---|---|
Address(m) | std::addressof(argument) 的结果匹配 m 。 |
Pointee(m) | argument (智能指针或原始指针)指向的值匹配 m 。 |
Pointer(m) | argument (智能指针或原始指针)包含的指针值匹配 m 。无论 argument 类型如何, m 始终匹配原始指针值。 |
WhenDynamicCastTo<T>(m) | 当 argument 经过 dynamic_cast<T>() 转换后,匹配匹配器 m 。 |
多参数匹配器
技术上,所有匹配器都匹配单个值,多参数匹配器实际匹配的是元组。 下列匹配器可用于匹配元组(x, y)
:
匹配器 | 描述 |
---|---|
Eq() | x == y |
Ge() | x >= y |
Gt() | x > y |
Le() | x <= y |
Lt() | x < y |
Ne() | x != y |
可以以下选择器来选取参数的子集(或新的排序)进行匹配:
匹配器 | 描述 |
---|---|
AllArgs(m) | 等效于 m ,用于 .With(AllArgs(m)) 语法糖。 |
Args<N1, N2, ..., Nk>(m) | 选取基于索引参数组成的元组匹配 m ,例如 Args<1, 2>(Eq()) 验证第二个和第三个参数的相等性。 |
复合匹配器
可通过组合现有匹配器创建新匹配器:
匹配器 | 描述 |
---|---|
AllOf(m1, m2, ..., mn) | argument 同时匹配 m1 到 mn 的所有匹配器。 |
AllOfArray({m0, m1, ..., mn}) AllOfArray(a_container) AllOfArray(begin, end) AllOfArray(array) AllOfArray(array, count) | 功能同 AllOf() ,但匹配器来源于初始化列表、STL 风格容器、迭代器范围或 C 风格数组。 |
AnyOf(m1, m2, ..., mn) | argument 匹配 m1 到 mn 的任一匹配器。 |
AnyOfArray({m0, m1, ..., mn}) , AnyOfArray(a_container) , AnyOfArray(begin, end) , AnyOfArray(array) , or AnyOfArray(array, count) | 功能同 AnyOf() ,但匹配器来源于初始化列表、STL 风格容器、迭代器范围或 C 风格数组。 |
Not(m) | argument 不匹配匹配器 m 。 |
Conditional(cond, m1, m2) | 若 cond 为 true ,argument 匹配 m1 ,否则匹配 m2 。 |
匹配器适配器
匹配器 | 描述 |
---|---|
MatcherCast<T>(m) | 将匹配器 m 转换为 Matcher<T> 类型。 |
SafeMatcherCast<T>(m) | 将匹配器 m 安全转换为 Matcher<T> 类型。 |
Truly(predicate) | 当 predicate(argument) 返回被 C++ 视为 true 的值时匹配成功。 |
Truly(predicate)
会接管 predicate
的所有权,该谓词必须永久有效。
将匹配器作为谓词使用
匹配器 | 描述 |
---|---|
Matches(m)(value) | 当 value 匹配 m 时返回 true 。可以将 Matches(m) 作为一元函数单独使用。 |
ExplainMatchResult(m, value, result_listener) | 当 value 匹配 m 时返回 true ,失败时通过 result_listener 解释原因。 |
Value(value, m) | 当 value 匹配 m 时返回 true 。 |
定义匹配器
MATCHER(IsEven, "") {
return (arg % 2) == 0;
}
定义匹配偶数的 IsEven()
匹配器。
MATCHER_P(IsDivisibleBy, n, "") {
*result_listener << "where the remainder is " << (arg % n);
return (arg % n) == 0;
}
定义匹配能被 n
整除的数的 IsDivisibleBy(n)
匹配器。
MATCHER_P1(IsBetween, a, b,
absl::StrCat(negation ? "isn't" : "is", " between ",
PrintToString(a), " and ", PrintToString(b))) {
return a <= arg && arg <= b;
}
定义匹配区间 [a, b]
的 IsBetween(a, b)
匹配器。
注
MATCHER*
宏不能在函数或类内部使用。匹配器体必须是纯函数式(即无副作用,结果仅取决于被匹配值和函数参数)。
可使用
PrintToString(x)
将任意类型值x
转换成字符串。可在自定义匹配器中使用
ExplainMatchResult()
包装其他匹配器,例如:MATCHER_P(NestedPropertyMatches, matcher, "") { return ExplainMatchResult(matcher, arg.nested().property(), result_listener); }
可使用
DescribeMatcher<>
来描述其他匹配器,例如:MATCHER_P(XAndYThat, matcher, "X that " + DescribeMatcher<int>(matcher, negation) + (negation ? " or" : " and") + " Y that " + DescribeMatcher<double>(matcher, negation)) { return ExplainMatchResult(matcher, arg.x(), result_listener) && ExplainMatchResult(matcher, arg.y(), result_listener); }