C++项目Google Mock初实践(4…

来源:互联网 发布:手机淘宝运费险怎么退 编辑:程序博客网 时间:2024/05/26 14:08
原文地址:Mock初实践(4)">C++项目Google Mock初实践(4)作者:良无限测试部

前一篇介绍的一些匹配器都比较简单,我就随便打包举几个最简单的例子演示一下吧:我稍微修改一下之前的Foo.hMockFoo.hMockFoo.h 增加了2个方法

 1

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:

       MOCK_METHOD0(getArbitraryString, std::string());

       MOCK_METHOD1(setValue, void(std::string&value));

       MOCK_METHOD2(setDoubleValues, void(int x, int y));

};

 

}  // namespaceseamless

 

#endif // MOCKFOO_H_

FooMain.h

 1

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) {

       ::testing::InitGoogleMock(&argc, argv);

 

       string value = "Hello World!";

       MockFoo mockFoo;

 

       EXPECT_CALL(mockFoo, setValue(testing::_));

       mockFoo.setValue(value);

 

       // 这里我故æ„�犯错

       EXPECT_CALL(mockFoo, setDoubleValues(Eq(1), Ge(1)));

       mockFoo.setDoubleValues(1, 0);

 

       return EXIT_SUCCESS;

}

  • 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'tmatch:

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等于m1argument.second 等于m2.

Property(&class::property, m)

argument.property()(argument->property(),argument是一个指 针时)与匹配器m匹配, 这里的argument是一个class类的实例.

还是举例说明一下:

 1

2

3

4

5

6

7

8

9

10

11

TEST(TestField, Simple) {

       MockFoo mockFoo;

       Bar bar;

       EXPECT_CALL(mockFoo, get(Field(&Bar::num,Ge(0)))).Times(1);

       mockFoo.get(bar);

}

 

int main(int argc, char** argv) {

       ::testing::InitGoogleMock(&argc, argv);

       return RUN_ALL_TESTS();

}

这里我们使用GoogleTest来写个测试用例,这样看得比较清楚。

  • 5行,我们定义了一个Field(&Bar::num,Ge(0)),以说明Bar的成员变量num必须大于等于0

上面这个是正确的例子,我们为了说明Field的作用,传入一个bar.num = -1试试。

1

2

3

4

5

6

7

TEST(TestField, Simple) {

       MockFoo mockFoo;

       Bar bar;

       bar.num = -1;

       EXPECT_CALL(mockFoo, get(Field(&Bar::num,Ge(0)))).Times(1);

       mockFoo.get(bar);

}

运行是出错了:

[==========] 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'tmatch:

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 匹配所有的匹配器m1mn

AnyOf(m1, m2, ..., mn)

argument 至少匹配m1mn中的一个

Not(m)

argument 不与匹配器m匹配

基数(Cardinalities

基数用于Times()中来指定模拟函数将被调用多少次|

AnyNumber()

函数可以被调用任意次.

AtLeast(n)

预计至少调用n.

AtMost(n)

预计至多调用n.

Between(m, n)

预计调用次数在mn(包括n)之间.

Exactly(n) n

预计精确调用n. 特别是, n0,函数应该永远不被调用.

行为(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)

每次发动时执行a1an的所有动作.

IgnoreResult(a)

执行动作a并忽略它的返回值. a不能返回void.

这里我举个例子来解释一下DoAll()的作用,我个人认为这个DoAll()还是挺实用的。例如有一个 Mock方法:

1

virtual int getParamter(std::string* name,  std::string* value) = 0

对于这个方法,我这回需要操作的结果是将name指向value的地址,并且得到方法的返回值。
类似这样的需求,我们就可以这样定义期望过程:

1

2

3

4

5

6

7

8

TEST(SimpleTest, F1) {

   std::string* a = new std::string("yes");

   std::string* b = new std::string("hello");

   MockIParameter mockIParameter;

   EXPECT_CALL(mockIParameter, getParamter(testing::_,testing::_)).Times(1).

       WillOnce(testing::DoAll(testing::Assign(&a, b),testing::Return(1)));

   mockIParameter.getParamter(a, b);

}

这时就用上了我们的DoAll()了,它将Assign()Return()结合起来了。

序列(Sequences

默认时,对于定义要的期望行为是无序(Unordered的,即当我定义好了如下的期望行为:

1

2

3

MockFoo mockFoo;

       EXPECT_CALL(mockFoo, getSize()).WillOnce(Return(1));

       EXPECT_CALL(mockFoo, getValue()).WillOnce(Return(string("HelloWorld")));

对于这样的期望行为的定义,我何时调用mockFoo.getValue()或者何时mockFoo.getSize()都可以的。

但有时候我们需要定义有序的(Ordered的调用方式,即序列 (Sequences) 指定预期的顺序. 在同一序列里的所有预期调用必须按它们指定的顺序发生; 反之则可以是任意顺序.

 1

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) {

       ::testing::InitGoogleMock(&argc, argv);

 

       Sequence s1, s2;

       MockFoo mockFoo;

       EXPECT_CALL(mockFoo, getSize()).InSequence(s1,s2).WillOnce(Return(1));

       EXPECT_CALL(mockFoo,getValue()).InSequence(s1).WillOnce(Return(

              string("Hello World!")));

       cout << "First:t"<< mockFoo.getSize()<< endl;

       cout << "Second:t"<< mockFoo.getValue()<< endl;

 

       return EXIT_SUCCESS;

}

  • 首先在第8行建立两个序列:s1s2
  • 然后在第11行中,EXPECT_CALL(mockFoo,getSize()).InSequence(s1, s2)说明getSize()的 行为优先于s1s2.
  • 而第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;

       cout << "First:t"<< mockFoo.getSize()<< 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'tmatch:

FooMain.cc:29: EXPECT_CALL(mockFoo, getValue())...
Expected: all pre-requisites are satisfied
Actual: the following immediate pre-requisites are notsatisfied:
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的顺序而自动地识别调用顺序,这种方式可能更为地通用。

 1

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) {

       ::testing::InitGoogleMock(&argc, argv);

 

       InSequence dummy;

       MockFoo mockFoo;

       EXPECT_CALL(mockFoo, getSize()).WillOnce(Return(1));

       EXPECT_CALL(mockFoo, getValue()).WillOnce(Return(string("HelloWorld")));

 

       cout << "First:t"<< mockFoo.getSize()<< endl;

       cout << "Second:t"<< mockFoo.getValue()<< endl;

 

       return EXIT_SUCCESS;

}

(本文作者:garcia.wul)

0 0
原创粉丝点击