Google C++ Mocking Framework使用简介

安装:
下载Google C++ Mocking Framework,解压...
发现它自带了Google Test的全部源代码,也就是说有了这个那个Google Test就不用去下载了
注意,Google Mock的编译对编译器的C++支持要求很高,并且需要有tr1的支持。

 

Linux/Unix下的GCC编译:
 注意:Google Mock的Readme里说它要求4.0版以上(不过版本低也没事,毕竟gcc是支持C++标准最好的编译器了,见Mingw3.45的安装)
 传统过程: ./configure make
 
Windows:
 Windows下的编译器自带tr1的还不多,我知道的也就BCB2009了,所以需要去下载一个Boost下来,好在gmock只用到了几个简单功能,所以不用编译Boost,直接包含Boost的目录,以及/boost/tr1/tr1即可。

VC2005 SP1:
 打开msvc目录里的sln工程
 设置包含路径,加入Boost, 加入Boost/tr1/tr1, 加入gtest所在路径
 编译,搞定(跟着MS就是好混啊)


Mingw3.45:
 主要是google test要作一点修改,同样过几天可以到http://www.cpp-prog.com/下载

注:google mock文档说要gcc4.0以上版本,而现在Mingw还没出4.0以上的稳定版,所以我在3.45版里发现使用时需要屏蔽gmock-matcher.h里的template<typename T> Matcher<T>::Matcher<T value>才行(在175行和1675行)。不过这样就有个缺点,象EXPECT_CALL(turtle, Turn(90))就得改成EXPECT_CALL(turtle, Turn(Eq(90)))了。
 
BCC:
 BCC就比较郁闷了,有太多地方不兼容了,偶搞不定呀呀呀:-(

 

介绍:Google Mock是干什么的?
Google Mock的设计灵感来源于jMock和EasyMock,它的作用是帮你快速地做出一个接口的仿制品。如果你的设计依赖其它的类,而这些类还没有完成或非常昂贵(如数据库);如果你要测试你的模块与其它模块是否能正确结合,并想了解其交互过程;那么Google Mock就能帮助你。

假设我们写好了一个CPainter类,它可以画各种图形。但它用到了一个Turtle类,它是由别人写的,而那小子光顾着和PLMM聊天了,现在还没开始动笔呢-_-
那么想测试这个CPainter只有两个方法,一个是等那家伙把Turtle写好,另一个是自己写一个Turtle的仿制品出来用用先。
如果你选的是方法二,那么Google Mock就可以帮上忙了,假设Turtle定义如下:

  1. struct Turtle {   //这个功能可能是别人做的,现在还没完工
  2.   virtual ~Turtle(){};
  3.   virtual void PenUp() = 0;  //起笔
  4.   virtual void PenDown() = 0;//下笔
  5.   virtual void Forward(int distance) = 0;  //前进
  6.   virtual void Turn(int degrees) = 0;  //转向
  7.   virtual void GoTo(int x, int y) = 0; //直接移动到指定位置
  8.   virtual int GetX() const = 0; //获得当前位置
  9.   virtual int GetY() const = 0;
  10. };

我们现在就用Google Mock写一个Turtle仿制品:
首先加入包含文件
#include <gtest/gtest.h>
#include <gmock/gmock.h>

制作仿制品:

  1. struct MockTurtle : public Turtle {
  2.   MOCK_METHOD0(PenUp, void());
  3.   MOCK_METHOD0(PenDown, void());
  4.   MOCK_METHOD1(Forward, void(int distance));
  5.   MOCK_METHOD1(Turn, void(int degrees));
  6.   MOCK_METHOD2(GoTo, void(int x, int y));
  7.   MOCK_CONST_METHOD0(GetX, int());
  8.   MOCK_CONST_METHOD0(GetY, int());
  9. };

它从Turtle继承,把想要仿制的方法用MOCK_METHODn来定义(如果是const方法,则用MOCK_CONST_METHODn),这里的n是类方法的参数数量,第一个参数是方法名,第二个参数是此方法的函数类型(看看,不是类成员函数类型哦)

 

好了,我们不用写一句代码,Google Mock已经帮我们把Turtle的仿制品准备好了,我们只管调用就可以了。如果接口方法很多,你还可以用scripts/generator/里的gmock_gen.py来帮你做这些工作(你需要安装Python 2.4)。这是一个命令行工具,你给它写有抽象类定义的C++文件,它就给你一个相应的Mock类。

现在可以测试我们的CPainter了,假设我们写的CPainter如下:

  1. //我们写的绘图类,因为要使用Turtle,要测试的这个绘图类就得用上MockTurtle类了
  2. struct CPainter{
  3.     CPainter():m_ptl(NULL){;}
  4.     void SetTurtle(Turtle* ptl){
  5.         m_ptl = ptl;
  6.     }
  7.     void Square(int w) //画正方形
  8.     {
  9.         if(!m_ptl || w<=0) return;
  10.         m_ptl->PenDown();
  11.         m_ptl->Forward(w);
  12.         m_ptl->Turn(90);
  13.         m_ptl->Forward(w);
  14.         m_ptl->Turn(90);
  15.         m_ptl->Forward(w);
  16.         m_ptl->Turn(90);
  17.         m_ptl->Forward(w);
  18.         m_ptl->Turn(90);
  19.         m_ptl->PenUp();
  20.     }
  21. private:
  22.     Turtle *m_ptl;
  23. };

我们测试一下它画正方形的功能是否正常:

  1. using testing::AtLeast;
  2. using testing::Return;
  3. using testing::_;
  4. using testing::Gt;
  5. using testing::Eq;
  6. TEST(PainterTest, SquareTest)
  7. {
  8.     MockTurtle turtle;
  9.     EXPECT_CALL(turtle, Forward(_)) //预计将不再调Forward(),是倒序的,看下一语句
  10.         .Times(0);
  11.     EXPECT_CALL(turtle, Forward(Gt(0))) //预计将会先调用四次Forward(),其中参数大于0,是倒序的
  12.         .Times(4);
  13.     EXPECT_CALL(turtle, Turn(90)) //预计将会调用四次Turn(90)
  14.         .Times(4);
  15.     EXPECT_CALL(turtle, PenUp());
  16.     EXPECT_CALL(turtle, PenDown());
  17.     CPainter pt;
  18.     pt.SetTurtle(&turtle);
  19.     pt.Square(10); //测试输入10的情况,应该会调用四次Forward(10)和四次Turn(90)
  20.     pt.Square(0);  //测试输入0的情况,应该不会再调用Forward才对
  21. }
  22. int main(int argc, char* argv[])
  23. {
  24.   testing::InitGoogleMock(&argc, argv);  //和Google Test使用方法一样,具体参考<Google C++ Testing Framework使用介绍>
  25.   int r = RUN_ALL_TESTS();
  26.   std::cin.get(); 
  27.   return r;
  28. }

运行,测试通过(不知为什么看到一片绿让我想起了股市)

下面来解释一下Google Mock新引入的断言EXPECT_CALL,它就是整个Mock测试的关键:

EXPECT_CALL的语法是:
EXPECT_CALL(mock_object, method(matchers))
    .Times(cardinality)
    .WillOnce(action)
    .WillRepeatedly(action);

看一下这个测试:(EXPECT_EQ的使用见<Google C++ Testing Framework使用介绍>)

  1. TEST(PainterTest, CanDrawSomething) {
  2.     MockTurtle turtle;
  3.     EXPECT_CALL(turtle, GetX())  //这个是写在前面地,就是说预计它应该会
  4.             .Times(AtLeast(5))      //调用至少5次
  5.         .WillOnce(Return(100))  //第一次调用GetX()就返回100
  6.         .WillOnce(Return(150))  //第二次调用GetX()就返回150
  7.         .WillRepeatedly(Return(200)) //接下来的所有调用就返回200
  8.         ;
  9.     EXPECT_EQ(100, turtle.GetX());  //第一次运行turtle.GetX(),返回100
  10.     EXPECT_EQ(150, turtle.GetX());  //第二次返回150
  11.     EXPECT_EQ(200, turtle.GetX());  //第三次返回200
  12.     EXPECT_EQ(200, turtle.GetX());  //第四次返回200
  13.     EXPECT_EQ(20, turtle.GetX());   //第五次返回200,不信写个20试试这次测试是什么结果?
  14. }

 

测试结果:

 

首先EXPECT_CALL是写在所有对turtle的调用之前的,也就是说EXPECT_CALL是一个预测,在这个测试结束时预测必须和实际情况相同,否则就Google Test就会发表意见
这个测试看上去很直观,意思是GetX至少会被调用5次,第一次调用时这个仿制品.GetX()返回100,第二次返回150,接下去就一直返回200。

 

怎样测试带参数的方法呢?

EXPECT_CALL(turtle, Forward(100)); 表示预计将会调用turtle.Forward(100)。
EXPECT_CALL(turtle, Forward(testing::_)); 表示预计将会调用turtle.Forward,里面的参数可以任意。
EXPECT_CALL(turtle, Forward(testing::Ge(100))); 表示预计将会调用turtle.Forward,而且里面的参数都会大于或等于100。

将会被调用多少次?即Times(cardinality)中的cardinality使用方法
test::AtLeast(n)表示至少会调用n次
test::AtMost(n)表示至多会调用n次
更多:http://code.google.com/p/googlemock/wiki/CheatSheet


如果不写Times(cardinality),Google Mock将会自己推断出cardinality:

  1. 如果既没有WillOnce也没有WillRepeatedly,那么相当于Times(1)
  2. 有n个WillOnce但没有WillRepeatedly,那么相当于Times(n)
  3. 有n个WillOnce和一个WillRepeatedly,那么相当于Times(AtLeast(n))

多次预测:
假设有这样一个测试:

  1. using testing::_;...
  2. EXPECT_CALL(turtle, Forward(_));  // #1
  3. EXPECT_CALL(turtle, Forward(10))  // #2
  4.     .Times(2);

如果Forward(10)被调用了3次,那么第三次调用将被指出是一个错误,因为#2的测试不通过(说了是两次嘛,怎么出现三次呢-_-);如果第三次调用改成Forward(20)则没有问题,因为这次与#1匹配了。
再次注意,预测优先级顺序是反着来的,先对比#2再对比#1。

 

接顺序预测:
默认对于多个不同的预测是没有顺序要求的,只要每个预测达到要求就可以。如果你想要精确指定顺序,很简单:

  1. using testing::InSequence;...
  2. TEST(FooTest, DrawsLineSegment) {
  3.   ...
  4.   {
  5.     InSequence dummy;
  6.     EXPECT_CALL(turtle, PenDown());
  7.     EXPECT_CALL(turtle, Forward(100));
  8.     EXPECT_CALL(turtle, PenUp());
  9.   }
  10.   Foo();
  11. }

所有在InSequence生存空间内放入的预测都将严格按顺序测试,如果调用PenDown,Forward,PenUp的顺序不致将报告错误。

所有的预测都是有“粘性”的

  1. using testing::Return;
  2. ...
  3. for (int i = n; i > 0; i--) {
  4.   EXPECT_CALL(turtle, GetX())
  5.       .WillOnce(Return(10*i));
  6. }

如果你认为这段预测代表turtle.GetX()将被调用n次,而且依次是10,20,30...,错!因为预测是有“粘性”的,第二次调用GetX时,还是与最后一次预测(也就是EXPECT_CALL(turtle, GetX()).WillOnce(Return(10))那次)匹配,结果当然是“超出预测的调用次数”;
正确的方法是明确指出预测不该存在粘性,另一种说法是当它们“吃饱”后就尽快“退役”:

  1. using testing::Return;
  2. ...
  3. for (int i = n; i > 0; i--) {
  4.   EXPECT_CALL(turtle, GetX())
  5.     .WillOnce(Return(10*i))
  6.     .RetiresOnSaturation();
  7. }

另外,这种情况下我们还有更好一点的方法来指定序列:

  1. using testing::InSequence;
  2. using testing::Return;
  3. ...
  4. {
  5.   InSequence s;
  6.   for (int i = 1; i <= n; i++) {
  7.     EXPECT_CALL(turtle, GetX())
  8.         .WillOnce(Return(10*i))
  9.         .RetiresOnSaturation();
  10.   }
  11. }

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
Google C++ Mocking Cookbook启蒙篇》是一本关于如何使用Google C++ Mocking框架的入门指南。 Google C++ Mocking Cookbook是Google Test框架的一部分,它提供了一种简单和灵活的方式来模拟和测试C++代码。该书适合那些对C++编程和测试有一定基础的读者。 书中首先介绍了Google Test和Google Mock框架的基本概念和使用方法。读者将学习如何使用Google Test编写单元测试,以及如何使用Google Mock创建和管理模拟对象。同时,该书还详细介绍了Google Mock框架的特性和高级用法,包括模拟函数、模拟类和模拟函数的重载。 在书中,作者通过一系列示例和案例来讲解各种测试和模拟的场景。读者将学习如何编写测试用例、设置预期和断言,并通过模拟对象来验证代码的行为和状态。 此外,书中还涵盖了一些高级主题,例如如何使用Google Mock框架集成到测试框架中,以及如何进行测试双向通信和测试异常情况等。 通过阅读这本书,读者可以深入了解Google C++ Mocking框架的原理和应用场景,掌握高效编写和管理测试用例的技巧,从而提高代码的质量和可维护性。 总之,《Google C++ Mocking Cookbook启蒙篇》是一本对使用Google C++ Mocking框架有兴趣的读者必读的入门指南。通过学习和实践,读者可以掌握基本的测试和模拟技术,为软件开发和测试带来更高的效率和质量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值