注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Koala++'s blog

计算广告学 RTB

 
 
 

日志

 
 

Google Mock进阶篇 [1] (Google Mock Cookbook译文)  

2012-03-27 14:15:48|  分类: C++ |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

                                        Google C++ Mocking Cookbook

Version: 0.32

作者:Adrian Alexander

译者:Koala++ / 屈伟

最新pdf版下载

    你来对地方了,这里你可以找到Google Mock的使用方法,但如果你还没有读过启蒙篇,建议你还是先去读一下吧,了解些基本知识。

    注意,Google Mock定义在testing命名空间中。你可以用using ::testing::Foo来让代码有更好的可读性。在本文中为了简洁起见,并不采用这种写法,但是在你自己的代码中应该用using

Create Mock Classes

Mocking Private or Protected Methods

    你必须将Mock函数定义( MOCK_METHOD* )放到Mock类的public:部分中,无论被Mock的函数在基类中是publicprotected,还是private。这样做是为了让ON_CALLEXPECT_CALL可以从Mock类外引用Mock函数。( 是的,C++允许子类改变一个基类虚函数的访问权限)。比如:

class Foo {

 public:

  ...

  virtual bool Transform(Gadget* g) = 0;

 

 protected:

  virtual void Resume();

 

 private:

  virtual int GetTimeOut();

};

 

class MockFoo : public Foo {

 public:

  ...

  MOCK_METHOD1(Transform, bool(Gadget* g));

 

  // The following must be in the public section, even though the

  // methods are protected or private in the base class.

  MOCK_METHOD0(Resume, void());

  MOCK_METHOD0(GetTimeOut, int());

};

Mocking Overloaded Methods

    Mock重载函数的方法也是一样的,不需要使用别的方式:

class Foo {

  ...

 

  // Must be virtual as we'll inherit from Foo.

  virtual ~Foo();

 

  // Overloaded on the types and/or numbers of arguments.

  virtual int Add(Element x);

  virtual int Add(int times, Element x);

 

  // Overloaded on the const-ness of this object.

  virtual Bar& GetBar();

  virtual const Bar& GetBar() const;

};

 

class MockFoo : public Foo {

  ...

  MOCK_METHOD1(Add, int(Element x));

  MOCK_METHOD2(Add, int(int times, Element x);

 

  MOCK_METHOD0(GetBar, Bar&());

  MOCK_CONST_METHOD0(GetBar, const Bar&());

};

    注意:如果你并不Mock所有的重载函数,编译器会警告你基类中的一些函数被隐藏了。修正的方法是用using将它们引入域中:

class MockFoo : public Foo {

  ...

  using Foo::Add;

  MOCK_METHOD1(Add, int(Element x));

  // We don't want to mock int Add(int times, Element x);

  ...

};

Mocking Class Templates

    Mock一个模板类,需要在MOCK_*宏后加上_T

template <typename Elem>

class StackInterface {

  ...

  // Must be virtual as we'll inherit from StackInterface.

  virtual ~StackInterface();

 

  virtual int GetSize() const = 0;

  virtual void Push(const Elem& x) = 0;

};

 

template <typename Elem>

class MockStack : public StackInterface<Elem> {

  ...

  MOCK_CONST_METHOD0_T(GetSize, int());

  MOCK_METHOD1_T(Push, void(const Elem& x));

};

Mocking Non-virtual Methods

    Google Mock可以Mock非虚函数用在hi-perf dependency injection中。

    Mock非虚函数时并不与真实的类共享一个公共的基类,你的Mock类与真实类将毫无关系,但两者所定义的函数却是一致的。Mock非虚函数与Mock虚函数的语法是一致的:

// A simple packet stream class.  None of its members is virtual.

class ConcretePacketStream {

 public:

  void AppendPacket(Packet* new_packet);

  const Packet* GetPacket(size_t packet_number) const;

  size_t NumberOfPackets() const;

  ...

};

 

// A mock packet stream class.  It inherits from no other, but defines

// GetPacket() and NumberOfPackets().

class MockPacketStream {

 public:

  MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number));

  MOCK_CONST_METHOD0(NumberOfPackets, size_t());

  ...

};

    注意与真实类不同的是Mock类没有定义AppenPacket(),但只要测试中没有调用到这个函数,这种写法是没有问题的。

    接下来,你需要想出一种在正式代码中使用ConcretePacketStream,在测试代码中使用MockPacketStream的方法。因为函数是非虚的,而两个类也是毫无关系的,所以你必须在编译时( 而不是运行时 )决定你使用的类。

    其中一种方法是模板化需要用Packet Stream的代码。具体一点,你在代码中使用一个针对packet stream模板参数。在正式代码中,你可以用ConcretePacketStream来实例化,在测试中你用MockPacketStream来实例化。下面是一个例子:

template <class PacketStream>

void CreateConnection(PacketStream* stream) { ... }

 

template <class PacketStream>

class PacketReader {

 public:

  void ReadPackets(PacketStream* stream, size_t packet_num);

};

    然后你可以在正式代码中使用CreateConnection<ConcretePacketStream>()PacketReader<ConcretePacketStream>,在测试代码中使用CreateConnection<MockPacketStream>PacketReader<MockPacketStream>

  MockPacketStream mock_stream;

EXPECT_CALL(mock_stream, ...)...;

.. set more expectations on mock_stream ...

PacketReader<MockPacketStream> reader(&mock_stream);

... exercise reader ...

Mocking Free Functions

    可以使用Google MockMock一个自由函数( 比如,普通C风格函数或是静态函数 )。但你需要一个接口( 抽象类 )重写你的代码。

    Mock并不直接调用自由函数( 暂且称之为OpenFile ),而是为它引入一个接口,并需要针对这个接口实现对函数对自由函数的调用:

class FileInterface {

 public:

  ...

  virtual bool Open(const char* path, const char* mode) = 0;

};

 

class File : public FileInterface {

 public:

  ...

  virtual bool Open(const char* path, const char* mode) {

    return OpenFile(path, mode);

  }

};

    你的代码可以通过FileInterface打开一个文件,现在函数更容易被Mock

    这看起来太麻烦了,但在现实中你通常可以将多个相关的函数放到一个接口中,所以为每个函数定义一个接口这种额外工作会少很多。

Nice Mocks and Strict Mocks

    如果一个没有指定EXPECT_CALLMock函数被调用了,Google Mock会打印一个”uninteresting call”警告。这样做的合理性如下:

l  当测试写完之后,可能有新的函数加入到接口中。而我们不能仅因为一个测试它不知道某个函数要被调用就失败。

l  但是,这种情况也可能意味着测试中有bug,所以Google Mock也不能什么都不提示。如果用户认为这些调用是无关的,它可以加入一个EXPECT_CALL来消除警告。

但是,有时你可能想消除所有的”uninteresting call”警告,但有时你可能想做刚好相反的事,即认为所有的”uninteresting call”都是错误。Google Mock能让你在Mock对象这个级别上选择你的决定。

TEST(...) {

  MockFoo mock_foo;

  EXPECT_CALL(mock_foo, DoThis());

  ... code that uses mock_foo ...

}

    如果mock_foo中一个不是DoThis的函数被调用了,Google Mock会给出一个警告,但是你用NiceMock<MockFoo>重写你的测试,警告会消失,你会得到一个更清爽的输出:

using ::testing::NiceMock;

 

TEST(...) {

  NiceMock<MockFoo> mock_foo;

  EXPECT_CALL(mock_foo, DoThis());

  ... code that uses mock_foo ...

}

    NiceMockMockFoo的一个子类,所以它在任何接受MockFoo类型的地方使用。

    MockFoo的构造函数是有参数的时候也是可以用的,因为NiceMock<MockFoo>“继承”了MockFoo的构造函数。

using ::testing::NiceMock;

 

TEST(...) {

  NiceMock<MockFoo> mock_foo(5, "hi");  // Calls MockFoo(5, "hi").

  EXPECT_CALL(mock_foo, DoThis());

  ... code that uses mock_foo ...

}

    StickMock的用法也是相似的,只是它的目的是让所有“uninteresting call”失败:

using ::testing::StrictMock;

 

TEST(...) {

  StrictMock<MockFoo> mock_foo;

  EXPECT_CALL(mock_foo, DoThis());

  ... code that uses mock_foo ...

 

  // The test will fail if a method of mock_foo other than DoThis()

  // is called.

}

    下面还有一些说明( 我不太喜欢这些说明,但遗憾的是它们是C++限制的副作用 ):

1.  NiceMock<MockFoo>StickMock<MockFoo>仅在直接MockFoo类中使用MOCK_METHOD*定义的Mock函数。如果一个Mock函数在MockFoo基类中定义,那么“nice”或是“strict”是否会影响它则取决于编译器。特别要指出的是,嵌套的NiceMockStrickMock是不支持的( 比如,NiceMock<StrictMock<MockFoo> >)

2.  Mock基类( MockFoo )不能传递非常量引用给构造函数,因为这种做法被Google C++ 编码规范禁止了。

3.  在构造函数和析构函数运行中,Mock对象不是nice也不是strict。如果在这个对象的构造函数或是析构函数中调用一个Mock函数,可能会因为这个原因造成意外。( 译注:Effective C++ Item 8)

最后,你必须在使用这个特性时特别小心,因为你所做的这个决定会应用到Mock类未来所有的改动上。如果你所Mock的接口做了一个重要的改变,它会让你的测试( 如果你用StrictMock )失败或是在没有警告提示的情况下让bug溜过( 如果你使用NiceMock )。所以,应该显式地调用EXPECT_CALL来指定mock的行为,仅在最后将Mock对象换为NiceMock或是StrictMock的。
  评论这张
 
阅读(6812)| 评论(1)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017