
性能剖析内存管理开发工具【免费下载链接】gperftoolsMain gperftools repository项目地址https://gitcode.com/gh_mirrors/gp/gperftools点击查看免费下载Matchers匹配器是 GoogleTest / GoogleMock 中用于校验单个参数的利器它们既可以在EXPECT_CALL()、ON_CALL()中描述 mock 方法的期望入参也可以配合EXPECT_THAT()/ASSERT_THAT()直接断言任意值让测试读起来像英文句子并在失败时给出“实际值 vs 期望”的清晰诊断。本指南以本仓库内vendor/googletest/docs/reference/matchers.md为骨架完整梳理内置匹配器的全部类别与用法并结合 gperftools 测试代码如 generic_writer_test.cc展示其在真实项目测试中的应用方式读完后你将能熟练选用内置匹配器、组合它们并自定义属于自己的匹配器。1. 入门EXPECT_THAT与ASSERT_THAT匹配器匹配的是单个参数。你可以在 mock 的ON_CALL()或EXPECT_CALL()中使用它也可以用下面两个宏直接校验一个值宏说明EXPECT_THAT(actual_value, matcher)断言actual_value匹配matcher非致命失败失败后测试继续执行ASSERT_THAT(actual_value, matcher)与EXPECT_THAT相同但失败是致命的会中止当前测试函数警告EXPECT_THAT(actual_value, expected_value)这种“直接用值做相等匹配”的写法虽然被支持但隐式类型转换可能带来出乎意料的结果。例如EXPECT_THAT(some_bool, some string)能编译通过却可能在无意义的情况下通过。最佳实践优先把比较写明确使用EXPECT_THAT(actual_value, Eq(expected_value))或者直接用EXPECT_EQ(actual_value, expected_value)。EXPECT_THAT的使用示例源自 assertions.md 的 Generalized Assertion 章节#include gmock/gmock.h using ::testing::AllOf; using ::testing::Gt; using ::testing::Lt; using ::testing::MatchesRegex; using ::testing::StartsWith; EXPECT_THAT(value1, StartsWith(Hello)); // 以 Hello 开头 EXPECT_THAT(value2, MatchesRegex(Line \\d)); // 匹配正则 ASSERT_THAT(value3, AllOf(Gt(5), Lt(10))); // 介于 5 与 10 之间失败时消息会同时打印“实际值”与“期望描述”例如Value of: value1 Actual: Hi, world! Expected: starts with Hello这种可读的失败信息正是 matcher 相比裸布尔断言的核心优势。所有内置匹配器定义在::testing命名空间中除非特别说明使用前通过using ::testing::...;引入即可。2. Wildcard 匹配器通配一切匹配器说明_argument可以是正确类型的任意值。Atype()或Antype()argument可以是type类型的任意值。在EXPECT_CALL(mock, method(_))中_是最常用的“我不关心这个参数”的占位符Aint()则限定参数必须是int类型常用于消除重载歧义。3. 通用比较匹配器匹配器说明Eq(value)或直接写valueargument valueGe(value)argument valueGt(value)argument valueLe(value)argument valueLt(value)argument valueNe(value)argument ! valueIsFalse()argument在布尔上下文中求值为false。IsTrue()argument在布尔上下文中求值为true。DistanceFrom(target, m)argument与target之间的距离按abs(argument - target)计算匹配m。DistanceFrom(target, get_distance, m)距离按自定义函数get_distance(argument, target)计算后匹配m。IsNull()argument是空指针裸指针或智能指针均可。NotNull()argument是非空指针裸指针或智能指针均可。Optional(m)argument是optional且其中包含的值匹配m。要测试optional是否被设置可与nullopt比较若内部类型没有可能需要Eq(nullopt)。VariantWithT(m)argument是variant当前持有类型T的备选值且该值匹配m。Ref(variable)argument是对variable的引用。TypedEqtype(value)argument类型为type且等于value。当 mock 函数被重载时可能需要用它替代Eq(value)。两个关键细节拷贝语义除Ref()外这些匹配器会拷贝一份value以防后续被修改或析构。若编译器提示value没有公开拷贝构造函数可用std::ref()包裹例如Eq(std::ref(non_copyable_value))但包裹后必须保证non_copyable_value之后不再被改变否则匹配器语义会被悄悄篡改。IsTrue/IsFalse的适用场景当需要“必须使用匹配器”的场合或类型只能显式转换为布尔、不能隐式转换时它们很有用其他情况下直接用EXPECT_TRUE/EXPECT_FALSE断言即可参见 assertions.md。4. 浮点匹配器ULP 级近似比较直接对浮点数用比较是测试中的常见坑舍入误差。GoogleTest 提供了一组基于ULPunits in the last place的近似比较匹配器与 googletest 自身的浮点断言使用同一算法会根据期望值的绝对值自动挑选合理的误差界限匹配器说明DoubleEq(a_double)argument是近似等于a_double的double两个 NaN 视为不相等。FloatEq(a_float)argument是近似等于a_float的float两个 NaN 视为不相等。NanSensitiveDoubleEq(a_double)同上但两个 NaN 视为相等。NanSensitiveFloatEq(a_float)同上但两个 NaN 视为相等。IsNan()argument是任意浮点类型的 NaN 值。IEEE 标准要求“两个 NaN 相等”的比较结果为 false因此DoubleEq()/FloatEq()遵循该标准而NanSensitive*版本把两个 NaN 当作相等通常更符合用户直觉。如果需要指定绝对误差上限使用下面这组匹配器说明DoubleNear(a_double, max_abs_error)double值绝对误差 max_abs_error两个 NaN 视为不相等。FloatNear(a_float, max_abs_error)float值绝对误差 max_abs_error两个 NaN 视为不相等。NanSensitiveDoubleNear(a_double, max_abs_error)同上但两个 NaN 视为相等。NanSensitiveFloatNear(a_float, max_abs_error)同上但两个 NaN 视为相等。5. 字符串匹配器argument可以是 C 字符串const char*或 C 字符串对象std::string除特别说明外均同时支持宽字符串匹配器说明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是 base-64 转义字符串其反转义后的字符串匹配m支持 RFC 4648 第 5 节定义的 web-safe 格式。ContainsRegex()和MatchesRegex()会接管take ownership传入的RE对象正则语法定义见 advanced.md 的 Regular Expression Syntax 一节除这两个外其余字符串匹配器同样适用于宽字符串。6. 异常匹配器断言调用抛出的异常这组匹配器作用于可调用对象lambda、函数对象等调用它并检查抛出的异常匹配器说明ThrowsE()argument是可调用对象调用时抛出类型为E的异常。ThrowsE(m)调用时抛出类型为E的异常且该异常满足匹配器m。ThrowsMessageE(m)调用时抛出类型为E的异常且异常的消息message满足匹配器m。原文档示例可直接复制运行auto argument [] { throw std::runtime_error(error msg); }; // 检查 lambda 抛出 std::runtime_error。 EXPECT_THAT(argument, Throwsstd::runtime_error()); // 检查抛出的异常类型正确且 what() 返回的字符串等于 error msg。 EXPECT_THAT(argument, Throwsstd::runtime_error(Property(std::runtime_error::what, Eq(error msg)))); // 检查异常消息包含子串 msg。 EXPECT_THAT(argument, ThrowsMessagestd::runtime_error(HasSubstr(msg)));7. 容器匹配器元素级灵活校验大多数 STL 风格容器支持因此Eq(expected_container)或直接写容器对象即可做整体相等匹配。当你想内联书写元素、做更灵活的匹配或获得更详尽的失败信息时用下面的匹配器匹配器说明BeginEndDistanceIs(m)begin()与end()迭代器之间相隔的步数匹配m例如BeginEndDistanceIs(2)或BeginEndDistanceIs(Lt(2))定义了size()的容器用SizeIs(m)更高效。ContainerEq(container)与Eq(container)相同但失败信息还会指出哪些元素只在其中一个容器里。Contains(e)argument包含一个匹配e的元素e可以是值或匹配器。Contains(e).Times(n)匹配e的元素个数为n值或匹配器与普通Contains/Each不同它支持任意出现次数包括用Contains(e).Times(0)断言“不存在”。Each(e)argument中的每一个元素都匹配e值或匹配器。ElementsAre(e0, e1, ..., en)argument恰好有n 1个元素第i个元素匹配ei值或匹配器。ElementsAreArray({...})/(a_container)/(begin, end)/(array)/(array, count)与ElementsAre()相同但期望值/匹配器来自初始化列表、STL 容器、迭代器区间或 C 数组。IsEmpty()argument是空容器container.empty()。IsSubsetOf(...)argument与期望匹配器的某个子集匹配UnorderedElementsAre(...)即argument的元素是期望集合的子集。IsSupersetOf(...)argument的某个子集与期望匹配器匹配UnorderedElementsAre(...)。Pointwise(m, container)/Pointwise(m, {e0, ...})元素个数相同且对每个i(argument 的第 i 个元素, 期望的第 i 个元素)组成的二元组匹配m。例如Pointwise(Le(), upper_bounds)验证每个元素不超过对应的上界。SizeIs(m)容器大小匹配m例如SizeIs(2)或SizeIs(Lt(2))。UnorderedElementsAre(e0, ..., en)有n 1个元素且存在某种排列使每个元素分别匹配某个ei忽略顺序。UnorderedElementsAreArray(...)与UnorderedElementsAre()相同期望值来自初始化列表/容器/迭代器区间/C 数组。UnorderedPointwise(m, container)与Pointwise(m, container)类似但忽略元素顺序。WhenSorted(m)用排序后匹配容器匹配器m例如WhenSorted(ElementsAre(1, 2, 3))验证包含 1、2、3 且忽略顺序。WhenSortedBy(comparator, m)与WhenSorted(m)相同但使用指定的比较器例如WhenSortedBy(std::greater(), ElementsAre(3, 2, 1))。Notes这些匹配器还可以匹配① 按引用传递的原生数组如Foo(const int (a)[5])② 以“指针 长度”传递的数组如Bar(const T* buffer, int len)见下文 Multi-argument Matchers。被匹配的数组可以是多维的元素本身是数组。Pointwise(m, ...)与UnorderedPointwise(m, ...)中的m应当是::std::tupleT, U的匹配器其中T、U分别是实际容器与期望容器的元素类型。例如两个不支持operator的Foo容器可以这样比较MATCHER(FooEq, ) { return std::get0(arg).Equals(std::get1(arg)); } ... EXPECT_THAT(actual_foos, Pointwise(FooEq(), expected_foos));8. 成员匹配器深入到对象内部匹配器说明Field(class::field, m)argument.field若argument是裸指针则为argument-field匹配margument是class类型的对象。Field(field_name, class::field, m)与两参数版本相同但提供更好的失败信息带字段名。Key(e)argument.first匹配e值或匹配器。例如Contains(Key(Le(5)))可验证map中存在键 5。Pair(m1, m2)argument是std::pairfirst匹配m1、second匹配m2。FieldsAre(m...)argument是兼容对象各字段与匹配器逐个对应。兼容对象指任何支持std::tuple_sizeObjgetI(obj)协议的类型C17 起也支持结构化绑定兼容类型如聚合类型。Property(class::property, m)argument.property()裸指针时为argument-property()匹配mproperty()必须无参数且声明为const。Property(property_name, class::property, m)与两参数版本相同但提供更好的失败信息。警告不要对你不拥有的成员函数使用Property()——取函数地址是脆弱的操作通常不属于函数的契约范围。FieldsAre()的典型用法覆盖std::tuple、结构化绑定类型与聚合类型std::tupleint, 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));9. 函数/仿函数/回调结果匹配器匹配器说明ResultOf(f, m)f(argument)的结果匹配mf是函数或仿函数。ResultOf(result_description, f, m)与两参数版本相同但提供更好的失败信息。适合对“经过转换后的值”做断言比如EXPECT_THAT(value, ResultOf(std::string::size, Gt(10)))。10. 指针匹配器匹配器说明Address(m)std::addressof(argument)的结果匹配m。Pointee(m)argument智能指针或裸指针指向的值匹配m。Pointer(m)argument智能指针或裸指针内含的指针匹配m无论argument是什么类型m都作用于裸指针。WhenDynamicCastToT(m)argument经dynamic_castT()转换后匹配m。注意Pointee(m)解引用后匹配目标值与Pointer(m)匹配指针本身的语义差异后者常配合Eq(ptr)验证指针身份。11. 多参数匹配器严格来说所有匹配器匹配的都是单个值“多参数匹配器”只是匹配元组tuple。用于匹配元组(x, y)的匹配器如下匹配器说明Eq()x yGe()x yGt()x yLe()x yLt()x yNe()x ! y配合以下选择器可以挑选或重排部分参数参与匹配匹配器说明AllArgs(m)等价于m在.With(AllArgs(m))中作为语法糖使用。ArgsN1, N2, ..., Nk(m)按 0 起始下标选出的k个参数组成的元组匹配m例如Args1, 2(Eq())。例如 mock 函数Foo(int a, int b)的调用Foo(1, 2)可以用EXPECT_CALL(mock, Foo).With(Args0, 1(Lt()))断言第一个参数小于第二个参数。12. 组合匹配器And / Or / Not用一个或多个匹配器组合出新的匹配器匹配器说明AllOf(m1, m2, ..., mn)argument同时匹配m1到mn中的所有匹配器。AllOfArray({...})/(a_container)/(begin, end)/(array)/(array, count)与AllOf()相同匹配器来自初始化列表/容器/迭代器区间/C 数组。AnyOf(m1, m2, ..., mn)argument至少匹配其中一个。AnyOfArray(...)与AnyOf()相同匹配器来自集合形式。Not(m)argument不匹配m。Conditional(cond, m1, m2)若cond为 true 匹配m1否则匹配m2。注意前文ASSERT_THAT(value3, AllOf(Gt(5), Lt(10)))就是组合匹配器的典型应用一个断言同时表达“大于 5 且小于 10”。13. 适配器类型转换与自定义谓词匹配器说明MatcherCastT(m)把匹配器m转换为类型MatcherT。SafeMatcherCastT(m)把匹配器m安全地转换为MatcherT安全转换规则见 gmock_cook_book.md 的 SafeMatcherCast 一节。Truly(predicate)predicate(argument)返回 C 意义上的真值predicate是函数或仿函数。AddressSatisfies(callback)与Truly(callback)会接管take ownershipcallback因此回调必须是长期有效的permanent callback。14. 把匹配器当作谓词使用匹配器不仅能写在断言里还能当作独立的布尔判定函数匹配器/函数说明Matches(m)(value)若value匹配m则求值为 true。Matches(m)本身可作为一元仿函数使用。ExplainMatchResult(m, value, result_listener)若value匹配m则求值为 true并把匹配/不匹配的原因解释给result_listener。Value(value, m)若value匹配m则求值为 true。这让你可以方便地把匹配器塞进std::find_if、std::count_if等算法里。15. 自定义匹配器MATCHER*宏家族内置匹配器不够用时用宏定义自己的匹配器宏说明MATCHER(IsEven, ) { return (arg % 2) 0; }定义无参匹配器IsEven()匹配偶数。MATCHER_P(IsDivisibleBy, n, ) { *result_listener where the remainder is (arg % n); return (arg % n) 0; }定义单参匹配器IsDivisibleBy(n)匹配能被n整除的数。MATCHER_P2(IsBetween, a, b, absl::StrCat(negation ? isnt : is, between , PrintToString(a), and , PrintToString(b))) { return a arg arg b; }定义双参匹配器IsBetween(a, b)匹配区间[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 DescribeMatcherint(matcher, negation) (negation ? or : and) Y that DescribeMatcherdouble(matcher, negation)) { return ExplainMatchResult(matcher, arg.x(), result_listener) ExplainMatchResult(matcher, arg.y(), result_listener); }注意negation是宏展开时自动提供的变量用于区分“匹配”与“不匹配”两种描述语境。16. 在 gperftools 项目中的实际落地gperftools 仓库把 GoogleTest 作为子目录vendor/googletest引入其单元测试全部构建在 GoogleTest 断言体系之上包含gtest/gtest.h。例如 generic_writer_test.cc 中就用EXPECT_LT验证格式化输出长度、并借助std::string构造预期输出进行整体比对malloc_hook_test.cc、tcmalloc_unittest.cc、page_heap_test.cc 等测试文件同样大量使用EXPECT_系列断言共计数十处。当你需要在 gperftools 这类 C 项目中编写新测试时可以这样组合使用本文的匹配器校验分配器返回的指针EXPECT_THAT(ptr, NotNull())校验字符串化的统计输出EXPECT_THAT(output, HasSubstr(bytes in use))校验容器统计结果EXPECT_THAT(sizes, ElementsAre(8, 16, 32))或忽略顺序的UnorderedElementsAre(...)校验浮点类性能指标EXPECT_THAT(ratio, DoubleNear(0.5, 1e-6))在 mock 场景中EXPECT_CALL(mock, Allocate(_, Ge(4096)))描述“任意类型、大小至少 4096”的调用。17. 扩展阅读Assertions ReferenceEXPECT_THAT之外的完整断言宏清单EXPECT_TRUE、EXPECT_EQ、浮点断言等。gmock_cook_book.mdSafeMatcherCast 等进阶技巧、自定义匹配器完整指南。gmock_cheat_sheet.mdGoogleMock 备忘单与本文匹配器互为补充。advanced.mdContainsRegex/MatchesRegex使用的正则表达式语法定义。赞分享性能剖析内存管理开发工具【免费下载链接】gperftoolsMain gperftools repository项目地址https://gitcode.com/gh_mirrors/gp/gperftools点击查看免费下载相关推荐gMock Matchers 完整参考GoogleTest 匹配器 API 详解与 yaml-cpp 项目实战gMock Matchers 完整参考GoogleTest 匹配器 API 详解与 yaml cpp 项目实战 导读 本文是 GoogleTestgoogl序列化后端Sinon Matchers API 完全指南用 sinon.match 实现灵活精确的参数匹配与断言Sinon Matchers API 完全指南用 sinon.match 实现灵活精确的参数匹配与断言 导读 Sinon 的 Matchers匹配器是测试测试开发工具Jest Using Matchers 完全指南从常用断言到匹配器底层原理Jest Using Matchers 完全指南从常用断言到匹配器底层原理 Jest 通过匹配器Matchers让你以声明式的方式断言各种类型的值。本测试质量保障代码覆盖率开发工具上一篇PrismUI未来展望组件库的完整发展路线图和社区规划指南下一篇codesandbox-client中的自动驾驶数据可视化AI决策过程解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考