目录
组合匹配
组合某些匹配某些值,可以使用以下:
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>
重载函数的匹配
- 通过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);
- 区分相同参数个数但不同参数类型,需要指定准确类型。
第一种方式是使用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作为谓词使用
Matcher | Description |
---|---|
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是不可拷贝的,那么:
- 可以自定义matcher使用Truly作为 ——怎样实现TODO
- 如果在保证不会修改的情况下,可以使用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容器
- ElementsAre的用法:
MOCK_METHOD(void, Foo, (const vector<int>& numbers), (override));
EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5)));
说明:必须要有四个参数其按这个顺序传入:一个=1,一个>0,一个为任意值,一个=5
- UnorderedElementsAre的用法:
OCK_METHOD(void, Foo, (const vector<int>& numbers), (override));
EXPECT_CALL(mock, Foo(UnorderedElementsAre(1, Gt(0), _, 5)));
必须要有四个参数其按任意顺序传入:一个=1,一个>0,一个为任意值,一个=5
- 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)));
- 数组是动态创建可以给ElementsAreArray一个额外的参数用于指定数组大小:
using ::testing::ElementsAreArray;
int* const expected_vector3 = new int[count];
EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count)));
- 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)));
汇总:
- ElementsAre*()可以匹配任何支持STL迭代器的容器
Matcher汇总
Matcher | Description |
---|---|
_ | 可以是正确类型的任意值 |
A<type>() /An<type>() | 类型type的任意值 |
多参数匹配
匹配一个tuple(x, y)
Matcher | Description |
---|---|
Eq() | x == y |
Ge() | x >= y |
Gt() | x > y |
Le() | x <= y |
Lt() | x < y |
Ne() | x != y |
Matcher | Description |
---|---|
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()). |