GoogleTest之Matchers的用法

本文详细介绍了gMock框架中的Matcher的使用,包括组合匹配、类型转换、重载函数匹配、基于参数执行不同Actions、多个参数匹配以及自定义Matcher。Matcher可以用于验证函数参数,而Actions定义了当匹配成功时执行的操作。此外,文章还提到了Matcher在处理STL容器和自定义对象成员验证的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

组合匹配

组合某些匹配某些值,可以使用以下:

Matcher使用描述
AllOf(m1, m2, …, mn)参数必须匹配m1, … mn
AllOfArray({m0, m1, …, mn}) / AllOfArray(a_container) / AllOfArray(begin, end) / AllOfArray(array) / AllOfArray(array, count)必须要和从初始化列表/STL容器/迭代器/可迭代的数组/C风格数组给定的参数匹配
AnyOf(m1, m2, …, mn)匹配m1到mn中任意的,至少一个
AnyOfArray({m0, m1, …, mn}) / AnyOfArray(a_container) / AnyOfArray(begin, end) / AnyOfArray(array) / AnyOfArray(array, count)用法同上,匹配任意一个就可以
Not(m)不匹配m就可以
Conditional(cond, m1, m2)如果cond为true则匹配m1,否则匹配m2

示例:

using ::testing::AllOf;
using ::testing::Gt;
using ::testing::HasSubstr;
using ::testing::Ne;
using ::testing::Not;
...
  // The argument must be > 5 and != 10.
  EXPECT_CALL(foo, DoThis(AllOf(Gt(5),Ne(10))));

  // The first argument must not contain sub-string "blah".
  EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")),NULL));

Matcher的类型转换

  • TODO gMock提供函数 SafeMatcherCast<T>(m) 能够将m转换为Matcher<T>

重载函数的匹配

  1. 通过Const()区分重载的const和非const函数
using ::testing::ReturnRef;

class MockFoo : public Foo {
  ...
  MOCK_METHOD(Bar&, GetBar, (), (override));
  MOCK_METHOD(const Bar&, GetBar, (), (const, override));
};
...
  MockFoo foo;
  Bar bar1, bar2;
  EXPECT_CALL(foo, GetBar()).WillOnce(ReturnRef(bar1));        // The non-const GetBar().
      
  EXPECT_CALL(Const(foo), GetBar()).WillOnce(ReturnRef(bar2));  // The const GetBar().
  // 对foo的调用都使用:Const(foo), 如:
  EXPECT_EQ(Const(foo).GetBar(), bar2);
  1. 区分相同参数个数但不同参数类型,需要指定准确类型。
    第一种方式是使用Matcher<type>() TODO 
    第二种方法:使用TypedEq<type>, An<type>()
using ::testing::An;
using ::testing::Matcher;
using ::testing::TypedEq;

class MockPrinter : public Printer {
 public:
  MOCK_METHOD(void, Print, (int n), (override));
  MOCK_METHOD(void, Print, (char c), (override));
};

TEST(PrinterTest, Print) {
  MockPrinter printer;

  EXPECT_CALL(printer, Print(An<int>()));            // void Print(int);
  EXPECT_CALL(printer, Print(Matcher<int>(Lt(5))));  // void Print(int);
  EXPECT_CALL(printer, Print(TypedEq<char>('a')));   // void Print(char);

  printer.Print(3);
  printer.Print(6);
  printer.Print('a');
}

基于参数执行不同的Actions

可以通过不同期望指定不同参数的Actions
示例代码:

TEST(test_matcher, mock_matcher01) {
  MockMatchFoo foo;
  EXPECT_CALL(foo, DoThis(_)).WillRepeatedly(Return(10));
  EXPECT_CALL(foo, DoThis(Lt(5))).WillRepeatedly(Return(20));

  EXPECT_EQ(foo.DoThis(2), 21);  // 参数值<5,会执行返回20的Action
  EXPECT_EQ(foo.DoThis(6), 12);  // 参数值>5,会调用参数为"_"的Acton
}

输出:
在这里插入图片描述

多个参数作为一个整体匹配

EXPECT_CALL的With方法可以让我们将所有参数作为一个整体来匹配。With的参数必须是Matcher<std::tuple<A1, ..., An>>(A1, … An是函数参数)

EXPECT_CALL(foo, InRange(Ne(0), _)).With(Lt());  // 第一个参数必须小于第二个参数,等价于:
EXPECT_CALL(foo, InRange(Ne(0), _)).With(AllArgs(Lt()));  // 但是这样更具有可读性

可以使用 Args<k1, …, kn>(m) 匹配n个参数

EXPECT_CALL(foo, Blah).With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); // 第0个小于第1个,第1个小于第2个

gMock将n个参数作为一个std::tuple类型,所以如果是谓词的话需要声明成std::tuple类型。

将Matchers作为谓词使用

MatcherDescription
Matches(m)(value)如果value值匹配m则为true,否则为false
ExplainMatchResult(m, value, result_listener)如果value匹配m则为true,返回result_listener
Value(value, m)如果value和m匹配则为true
TEST(test_matcher, mock_as_predicate) {
  vector<int> v{1,2,3,4,5,6,7,8,11,12,15,17,18,22,33,44};
  const int count = count_if(v.begin(), v.end(), Matches(Ge(10)));  // 计算大于10的个数
  std::cout << "count: " << count << std::endl;

  int count1 = count_if(v.begin(), v.end(), Matches(AllOf(Ge(10), Le(20), Ne(15)))); // >=0,<=20,!=15的元素个数
  std::cout << "count1: " << count1 << std::endl;
}
  • ExplainMatchResult 待验证
  • Value 待验证

将谓词用作Matchers

使用一元谓词通过Truly函数warpping可以作为自定义Matcher(多个参数的谓词不支持?)。不需要必须返回bool值,只需要返回值能通过 if(return_value)成立即可。
以下示例代码要求参数必须是偶数:

int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; }

TEST(test_matcher, mock_self_matchers) {
  mock_matcher::MockFoo foo;
  EXPECT_CALL(foo, DoThis(Truly(IsEven))).WillOnce(Return(3));
  EXPECT_EQ(foo.DoThis(2), 3);  // DoThis的参数为奇数会报错
}

Matchers的参数为不可拷贝

EXPECT_CALL(mock_obj, Foo(bar)) 这种形式bar会做一份拷贝给Foo后EXPECT_CALL执行。所以EXPECT_CALL对bar的修改对原bar无影响。但如果bar是不可拷贝的,那么:

  1. 可以自定义matcher使用Truly作为 ——怎样实现TODO
  2. 如果在保证不会修改的情况下,可以使用std::ref让其作为引用传入
  // Expects that Foo()'s argument == bar.
  EXPECT_CALL(mock_obj, Foo(Eq(std::ref(bar))));

  // Expects that Foo()'s argument < bar.
  EXPECT_CALL(mock_obj, Foo(Lt(std::ref(bar))));

验证对象的成员

验证数据成员是否符合matcher m:Field(&MyObject::data_member, m)
验证成员函数是否符合matcher m:Property(&MyObject::func_member, m)
示例:TODO

验证指针参数指向的值

Pointee(m)可以用于验证指针指向的值是否匹配m。

class Foo {
public:
    virtual int DoPointer(int* p) = 0;
};

class MockFoo : public Foo {
public:
  MOCK_METHOD(int, DoPointer, (int* p), (override));
};

TEST(test_matcher, mock_pointee) {
  mock_matcher::MockFoo foo;
  int *p = new int(3);
  EXPECT_CALL(foo, DoPointer(Pointee(Ge(3))));
  foo.DoPointer(p);
}
  • 是否支持智能指针?

自定义Matcher

TODO

匹配STL容器

  1. ElementsAre的用法:
MOCK_METHOD(void, Foo, (const vector<int>& numbers), (override));
EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5)));  

说明:必须要有四个参数其按这个顺序传入:一个=1,一个>0,一个为任意值,一个=5

  1. UnorderedElementsAre的用法:
OCK_METHOD(void, Foo, (const vector<int>& numbers), (override));
EXPECT_CALL(mock, Foo(UnorderedElementsAre(1, Gt(0), _, 5)));

必须要有四个参数其按任意顺序传入:一个=1,一个>0,一个为任意值,一个=5

  1. C风格的字符串使用 ElementsAreArray() 或者 UnorderedElementsAreArray()
  const int expected_vector1[] = {1, 5, 2, 4, ...};
  EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1)));

  Matcher<int> expected_vector2[] = {1, Gt(2), _, 3, ...};
  EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2)));
  1. 数组是动态创建可以给ElementsAreArray一个额外的参数用于指定数组大小:
  using ::testing::ElementsAreArray;
  int* const expected_vector3 = new int[count];
  EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count)));
  1. Pair用于关联容器如map:
  using ::testing::UnorderedElementsAre;
  using ::testing::Pair;
  absl::flat_hash_map<string, int> m = {{"a", 1}, {"b", 2}, {"c", 3}};
  EXPECT_THAT(m, UnorderedElementsAre(Pair("a", 1), Pair("b", 2), Pair("c", 3)));

汇总:

  1. ElementsAre*()可以匹配任何支持STL迭代器的容器

Matcher汇总

MatcherDescription
_可以是正确类型的任意值
A<type>()An<type>()类型type的任意值

多参数匹配

匹配一个tuple(x, y)

MatcherDescription
Eq()x == y
Ge()x >= y
Gt()x > y
Le()x <= y
Lt()x < y
Ne()x != y
MatcherDescription
AllArgs(m)Equivalent to m. Useful as syntactic sugar in .With(AllArgs(m)).
Args<N1, N2, …, Nk>(m)The tuple of the k selected (using 0-based indices) arguments matches m, e.g. Args<1, 2>(Eq()).
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值