1.gmock是谷歌推出的开源白盒测试工具,用于编写C++模拟类的框架。通过gmock可以用一些简单的宏描述想要模拟的接口并指定其期望,在测试中有效地去除外部依赖,更方便地测试模块功能。对类里面需要打桩的函数mock.
2.在单元测试、模块的接口测试时,当这个模块需要依赖另外一个或几个类,而这时这些个类还没有开发好,这时我们就可以定义了Mock对象来模拟那些类的行为。也就是自己实现一个假的依赖类,对这个类的方法你想要什么行为就可以有什么行为,你想让这个方法返回什么结果就可以返回怎么样的结果。
使用Mock类的一般流程如下:
using ::testing::Return;
testing::InitGoogleTest(&argc,argv);
return RUN_ALL_TESTS();
class MockFoo: public Foo{
public:
MOCK_METHOD0(count,int());
MOCK_METHOD#1(#2, #3(#4))
// #1表示你要mock的方法共有几个参数,#2是你要mock的方法名称,#3表示这个方法的返回值类型,#4是这个方法具体的参数
//MOCK_METHODn(..., ...); //其中n表示参数的个数
//MOCK_CONST_METHODn(..., ...); //const成员方法用这种
}
MockFoo *mockFoo = new MockFoo();
EXPECT_CALL(MockFoo, getNum())
.Times(3) //! 期望被调两次
.WillOnce(Return(3)) //! 第一次返回值为3
.WillOnce(Return(6)); //! 第二次返回值为6
.WillOnce(Return(5)); //! 第三次返回值为5
基数用于Times()中来指定模拟函数将被调用多少次|
AnyNumber() 函数可以被调用任意次.
AtLeast(n) 预计至少调用n次.
AtMost(n) 预计至多调用n次.
Between(m, n) 预计调用次数在m和n(包括n)之间.
Exactly(n) 或 n 预计精确调用n次. 特别是, 当n为0时,函数应该永远不被调用.
Actions(行为)用于指定Mock类的方法所期望模拟的行为:比如返回什么样的值、对引用、指针赋上怎么样个值,等等。 值的返回
Return() 让Mock方法返回一个void结果
Return(value) 返回值value
ReturnNull() 返回一个NULL指针
ReturnRef(variable) 返回variable的引用.
ReturnPointee(ptr) 返回一个指向ptr的指针
Assign(&variable, value) 将value分配给variable
DoAll(a1, a2, …, an) 每次发动时执行a1到an的所有动作.
Invoke(f) 使用模拟函数的参数调用f, 这里的f可以是全局/静态函数或函数对象.
Invoke(object_pointer,&class::method)
使用模拟函数的参数调用object_pointer对象的mothod方法.
EXPECT_EQ(bar->count(),3);
EXPECT_EQ(bar->count(),6);
EXPECT_EQ(bar->count(),5);
EXPECT_CALL(mock_object, method(matcher1, matcher2, …))
.With(multi_argument_matcher)
.Times(cardinality)
.InSequence(sequences)
.After(expectations)
.WillOnce(action)
.WillRepeatedly(action)
.RetiresOnSaturation();
- EXPECT_CALL声明一个调用期待,就是我们期待这个对象的这个方法按什么样的逻辑去执行。
- mock_object是我们mock的对象,上例中MockFoo就是TestUser的一个对象。
- Method是mock对象中的mock方法,它的参数可以通过matchers规则去匹配。
- With是多个参数的匹配方式指定。
- Times表示这个方法可以被执行多少次。
- InSequence用于指定函数执行的顺序。它是通过同一序列中声明期待的顺序确定的。
- After方法用于指定某个方法只能在另一个方法之后执行。
- WillOnce表示执行一次方法时,将执行其参数action的方法。一般我们使用Return方法,用于指定一次调用的输出。
- WillRepeatedly表示一直调用一个方法时,将执行其参数action的方法。需要注意下它和WillOnce的区别,WillOnce是一次,WillRepeatedly是一直。
- RetiresOnSaturation用于保证期待调用不会被相同的函数的期待所覆盖
TEST(testsuiteName, testcaseName)
TEST宏是gtest最基本的使用单元,一个testsuitName可以包含多个不同的testcaseName。每个testsuiteName和testcaseName构成的TEST宏内部就是该测试样例的具体实现。
testcaseName和testsuiteName内部会经过转换,所以最好不要含有下划线,例如 case1,case1,case_1等,以避免不必要的麻烦
TEST(BarTest,mock_foo_in_bar){
MockFoo *mockFoo = new MockFoo();
Bar *bar = new Bar(mockFoo);
EXPECT_CALL(*mockFoo,count())
.Times(3)
.WillOnce(Return(3))
.WillOnce(Return(6))
.WillOnce(Return(5));
EXPECT_EQ(bar->count(),3);
EXPECT_EQ(bar->count(),6);
EXPECT_EQ(bar->count(),5);
delete bar;
delete mockFoo;
}
编译完gmock后吗,主要生成了一个静态库gmock_main.a。该库中包含了gmock的框架,同时,也包含了gtest框架,可以认为gtest是gmock的一个子集。在gmock_main.a中默认编译了一个main函数,该main函数会初始化gmock和gtest,并且执行所有的TEST或TEST_F宏定义的测试用例,所以使用gmock_main.a进行单元测试时,不能编写main函数,否则会出现多个main冲突。如果需要重写main函数,可以使用命令“make gmock.a”,重新编译,会生成文件gmock.a。那么此时你需要自己编写main函数和初始化gmock框架。