GoogleMock模拟非虚拟功能

时间:2018-07-18 17:48:36

标签: c++ unit-testing c++11 googlemock

我们正在为现有代码库编写单元测试。我们正在使用Google Test / Google Mock进行测试,并使用带有gcc编译器的C ++ 11和Eclipse CDT。

我们的一个类聚集了一个Boost Socket。它使用它作为实例,但是幸运的是我们可以修改现有的代码库,我将其更改为指针,并将套接字作为依赖项注入。因此,我开始模拟对套接字的调用,但是有一个问题:Boost函数是非虚拟的。

我找到了说明如何使用 hi-perf dependency injection 模拟非虚函数的文档。但是,尝试如图所示实施它并没有成功。例如,文档说“模板化您的代码”。因此,对于使用boost套接字的类,我遵循其示例。我插入了:

template <class boost::asio::ip::udp::socket>

这应该是让我们插入模拟类而不是具体的Boost类。我在类之前和头和实现文件中分别在接受套接字的构造函数之前尝试过它。在每个地方,我都会遇到很多错误,其中大多数都是类似“没有匹配函数调用”构造函数的调用。

很显然,我做错了什么。有人知道某个地方有完整的例子吗?

更新: 根据要求,这是我们目前拥有的:

GoogleMock模拟非虚拟功能

class PIngester : public IPIngester{
public:
    // this is the method that takes the socket. It is the constructor, and the socket
    // is a default parameter so the existing code will still work. We added the socket 
    // as a parameter specifically for unit testing. If no socket is provided, the 
    // constructor creates one. It only will ever create a concrete Boost
    // Socket, not a mock one.
    PIngester(boost::asio::io_service& ioService, Band band,
              std::unique_ptr<boost::asio::ip::udp::socket> socket = std::unique_ptr<boost::asio::ip::udp::socket>(nullptr));
    ...

更新2

我为模板定义了一个通用类类型,但是这破坏了现有代码。这是我当前的版本:

class PIngester : public IPIngester{
public:
    template <class Socket>
    PIngester(boost::asio::io_service& ioService, Band band,
              std::unique_ptr<Socket> socket = std::unique_ptr<Socket>(nullptr));
    ...

我认为这可能是对默认参数的质疑,但是我不确定。错误消息不是很有帮助:

 error: no matching function for call to ‘foonamespace::PIngester::PIngester(boost::asio::io_service&, foonamespace::Band&)’                                     
          new PIngester(ioService, band));

此错误消息来自现有代码;它似乎无法识别默认参数。

更新3

我放弃了这种方法,而是决定编写一个Boost Socket Wrapper。包装器将保存实际的Socket实例,并且其方法将直接传递到实际的Socket。包装器的功能将是虚拟的,而我的模拟对象将从包装器继承。然后,我的模拟对象将模拟包装程序的虚拟功能。

1 个答案:

答案 0 :(得分:2)

您已经注意到,问题是编译器无法推断出Socket所代表的类型:

class PIngester : public IPIngester{
public:
    template <class Socket>
    PIngester(boost::asio::io_service& ioService, Band band,
              std::unique_ptr<Socket> socket = std::unique_ptr<Socket>(nullptr));
    ...

如果您尝试在不指定第三个参数的情况下构造此类的对象(如new PIngester(ioService, band)),Socket到底是什么?

现在,在调用构造函数时无法显式指定任何模板参数,因此,如果对模板构造函数进行模板化,则无法执行类似new PIngester<boost::asio::ip::udp::socket>(ioService, band)的操作。


有几种方法(可能有多种方法)来解决此问题:

  1. 您可以对PIngester类本身进行模板化:

    template <class Socket>
    class PIngester : public IPIngester{
    public:
        PIngester(boost::asio::io_service& ioService, Band band,
                  std::unique_ptr<Socket> socket = std::unique_ptr<Socket>(nullptr));
        ...
    

    然后调用new PIngester<boost::asio::ip::udp::socket>(ioService, band)(或您的模拟类代替boost::asio::ip::udp::socket)即可。

  2. 您可以定义默认的模板参数:

    class PIngester : public IPIngester{
    public:
        template <class Socket = boost::asio::ip::udp::socket>
        PIngester(boost::asio::io_service& ioService, Band band,
                  std::unique_ptr<Socket> socket = std::unique_ptr<Socket>(nullptr));
        ...
    

    然后PIngester(ioService, band)将始终使用此默认的Boost类,并且如果您想在测试中使用它,则需要显式传递一些socket,该<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>gstreamer playout</title> </head> <body> <video width=1920 height=1080 autoplay controls> <source src="http://localhost:8080" type="video/webm"> </video> </body> </html> 表示模拟类的唯一指针。