前一篇介绍的一些匹配器都比较简单,我就随便打包举几个最简单的例子演示一下吧:我稍微修改一下之前的Foo.h和MockFoo.h, MockFoo.h 增加了2个方法
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #ifndef MOCKFOO_H_ #define MOCKFOO_H_ #include <gmock/gmock.h> #include <string> #include <vector> #include "FooInterface.h" namespace seamless { class MockFoo: public FooInterface { public: }; } #endif // MOCKFOO_H_ |
FooMain.h
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #include <cstdlib> #include <gmock/gmock.h> #include <iostream> #include <string> #include "MockFoo.h" using namespace seamless; using namespace std; using ::testing::Assign; using ::testing::Eq; using ::testing::Ge; using ::testing::Return; int main(int argc, char** argv) { } |
- 第22行,让setValue的形参可以传入任意参数
- 另外,我在第26~27行故意犯了个错(为了说明上述这些匹配器的作用),我之前明明让setDoubleValues第二个参 数得大于等于1,但我实际传入时却传入一个0。这时程序运行时就报错了:
unknown file: Failure
Unexpected mock function call - returning directly.
Function call: setDoubleValues(1, 0)
Google Mock tried the following 1 expectation, but it didn't match:
FooMain.cc:35: EXPECT_CALL(mockFoo, setDoubleValues(Eq(1), Ge(1)))...
Expected arg #1: is >= 1
Actual: 0
Expected: to be called once
Actual: never called - unsatisfied and active
FooMain.cc:35: Failure
Actual function call count doesn't match EXPECT_CALL(mockFoo, setDoubleValues(Eq(1), Ge(1)))...
Expected: to be called once
Actual: never called - unsatisfied and active
上述的那些匹配器都比较简单,下面我们来看看那些比较复杂的匹配吧。
成员匹配器
Field(&class::field, m) | argument.field (或 argument->field, 当argument是一个指针时)与匹配器m匹配, 这里的argument是一个class类的实例. |
Key(e) | 形参(argument)比较是一个类似map这样的容器,然后argument.first的值等于e |
Pair(m1, m2) | 形参(argument)必须是一个pair,并且argument.first等于m1,argument.second 等于m2. |
Property(&class::property, m) | argument.property()(或argument->property(),当argument是一个指 针时)与匹配器m匹配, 这里的argument是一个class类的实例. |
还是举例说明一下:
2 3 4 5 6 7 8 9 10 11 | TEST(TestField, Simple) { } int main(int argc, char** argv) { } |
这里我们使用Google Test来写个测试用例,这样看得比较清楚。
- 第5行,我们定义了一个Field(&Bar::num, Ge(0)),以说明 Bar的成员变量num必须大于等于0。
上面这个是正确的例子,我们为了说明Field的作用,传入一个bar.num = -1试试。
1 2 3 4 5 6 7 | TEST(TestField, Simple) { } |
运行是出错了:
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from TestField
[ RUN ] TestField.Simple
unknown file: Failure
Unexpected mock function call - returning directly.
Function call: get(@0xbff335bc 4-byte object )
Google Mock tried the following 1 expectation, but it didn't match:
FooMain.cc:34: EXPECT_CALL(mockFoo, get(Field(&Bar::num, Ge(0))))...
Expected arg #0: is an object whose given field is >= 0
Actual: 4-byte object , whose given field is -1
Expected: to be called once
Actual: never called - unsatisfied and active
FooMain.cc:34: Failure
Actual function call count doesn't match EXPECT_CALL(mockFoo, get(Field(&Bar::num, Ge(0))))...
Expected: to be called once
Actual: never called - unsatisfied and active
[ FAILED ] TestField.Simple (0 ms)
[----------] 1 test from TestField (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] TestField.Simple
1 FAILED TEST
匹配函数或函数对象的返回值
ResultOf(f, m) | f(argument) 与匹配器m匹配, 这里的f是一个函数或函数对象. |
指针匹配器
Pointee(m) | argument (不论是智能指针还是原始指针) 指向的值与匹配器m匹配. |
复合匹配器
AllOf(m1, m2, ..., mn) | argument 匹配所有的匹配器m1到mn |
AnyOf(m1, m2, ..., mn) | argument 至少匹配m1到mn中的一个 |
Not(m) | argument 不与匹配器m匹配 |
基数(Cardinalities)
基数用于Times()中来指定模拟函数将被调用多少次|
AnyNumber() | 函数可以被调用任意次. |
AtLeast(n) | 预计至少调用n次. |
AtMost(n) | 预计至多调用n次. |
Between(m, n) | 预计调用次数在m和n(包括n)之间. |
Exactly(n) 或 n | 预计精确调用n次. 特别是, 当n为0时,函数应该永远不被调用. |
行为(Actions)
Actions(行为)用于指定Mock类的方法所期望模拟的行为:比如返回什么样的值、对引用、指针赋上怎么样个值,等等。 值的返回
Return() | 让Mock方法返回一个void结果 |
Return(value) | 返回值value |
ReturnNull() | 返回一个NULL指针 |
ReturnRef(variable) | 返回variable的引用. |
ReturnPointee(ptr) | 返回一个指向ptr的指针 |
另一面的作用(Side Effects)
Assign(&variable, value) | 将value分配给variable |
使用函数或者函数对象(Functor)作为行为
Invoke(f) | 使用模拟函数的参数调用f, 这里的f可以是全局/静态函数或函数对象. |
Invoke(object_pointer, &class::method) | 使用模拟函数的参数调用object_pointer对象的mothod方法. |
复合动作
DoAll(a1, a2, ..., an) | 每次发动时执行a1到an的所有动作. |
IgnoreResult(a) | 执行动作a并忽略它的返回值. a不能返回void. |
这里我举个例子来解释一下DoAll()的作用,我个人认为这个DoAll()还是挺实用的。例如有一个 Mock方法:
1 | virtual int getParamter(std::string* name, |
对于这个方法,我这回需要操作的结果是将name指向value的地址,并且得到方法的返回值。
类似这样的需求,我们就可以这样定义期望过程:
1 2 3 4 5 6 7 8 | TEST(SimpleTest, F1) { } |
这时就用上了我们的DoAll()了,它将Assign()和Return()结合起来了。
序列(Sequences)
默认时,对于定义要的期望行为是无序(Unordered)的,即当我定义好了如下的期望行为:
1 2 3 | MockFoo mockFoo; |
对于这样的期望行为的定义,我何时调用mockFoo.getValue()或者何时mockFoo.getSize()都可以的。
但有时候我们需要定义有序的(Ordered)的调用方式,即序列 (Sequences) 指定预期的顺序. 在同一序列里的所有预期调用必须按它们指定的顺序发生; 反之则可以是任意顺序.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | using ::testing::Return; using ::testing::Sequence; int main(int argc, char **argv) { } |
- 首先在第8行建立两个序列:s1、s2。
- 然后在第11行中,EXPECT_CALL(mockFoo, getSize()).InSequence(s1, s2)说明getSize()的 行为优先于s1、s2.
- 而第12行时,EXPECT_CALL(mockFoo, getValue()).InSequence(s1)说明getValue()的 行为在序列s1中。
得到的结果如下:
First: 1
Second: Hello World!
当我尝试一下把mockFoo.getSize()和mockFoo.getValue()的调用对调时试试:
1 2 | cout << "Second:t" << mockFoo.getValue() << endl; |
得到如下的错误信息:
unknown file: Failure
Unexpected mock function call - returning default value.
Function call: getValue()
Returns: ""
Google Mock tried the following 1 expectation, but it didn't match:
FooMain.cc:29: EXPECT_CALL(mockFoo, getValue())...
Expected: all pre-requisites are satisfied
Actual: the following immediate pre-requisites are not satisfied:
FooMain.cc:28: pre-requisite #0
(end of pre-requisites)
Expected: to be called once
Actual: never called - unsatisfied and active
Second:
First: 1
FooMain.cc:29: Failure
Actual function call count doesn't match EXPECT_CALL(mockFoo, getValue())...
Expected: to be called once
Actual: never called - unsatisfied and active
另外,我们还有一个偷懒的方法,就是不要这么傻乎乎地定义这些个Sequence s1, s2的序列,而根据我定义期望行为(EXPECT_CALL)的顺序而自动地识别调用顺序,这种方式可能更为地通用。
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | using ::testing::InSequence; using ::testing::Return; int main(int argc, char **argv) { } |
(本文作者:garcia.wul)