简体   繁体   English

GoogleMock 模拟非虚拟函数

[英]GoogleMock mocking non-virtual functions

We're writing unit tests for an existing code base.我们正在为现有代码库编写单元测试。 We're using Google Test/Google Mock for the tests, C++11 and Eclipse CDT with the gcc compiler.我们使用 Google Test/Google Mock 进行测试,C++11 和带有 gcc 编译器的 Eclipse CDT。

One of our classes aggregates a Boost Socket.我们的一个类聚合了一个 Boost Socket。 It used it as an instance, but luckily we can modify the existing code base, and I changed it to a pointer and injected the socket as a dependency.它使用它作为实例,但幸运的是我们可以修改现有的代码库,我将其更改为指针并将套接字作为依赖项注入。 So I went about mocking the calls to the socket, but there's a problem: the Boost functions are non-virtual.所以我开始模拟对套接字的调用,但有一个问题:Boost 函数是非虚拟的。

I found documentation showing how to mock non-virtual functions using hi-perf dependency injection .我找到了展示如何使用高性能依赖注入来模拟非虚拟函数的文档。 Trying to implement it as shown, though, has been unsuccessful.然而,试图按所示实施它,但没有成功。 For example, the doc says to "templatize your code".例如,文档说“模板化你的代码”。 So for our class that uses the boost socket, I followed their example.所以对于我们使用boost socket的类,我遵循了他们的例子。 I inserted:我插入:

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

That is supposed to let us insert our mock class instead of the concrete Boost class.这应该让我们插入我们的模拟类而不是具体的 Boost 类。 I tried it before the class and separately just before the constructor that accepts the socket, in the header and the implementation file.我在类之前和在接受套接字的构造函数之前分别尝试过,在头文件和实现文件中。 In each place, I just get tons of errors, most of which are along the lines of "no matching function call for " the constructor call.在每个地方,我都会遇到大量错误,其中大部分都与构造函数调用“没有匹配的函数调用”类似。

Clearly, I'm doing something wrong.显然,我做错了什么。 Does anyone know of a complete example somewhere?有人知道某个地方的完整示例吗?

Update: Per request, here is what we currently have:更新:根据请求,这是我们目前拥有的:

GoogleMock mocking non-virtual functions 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));
    ...

Update 2更新 2

I defined a generic class type for the template, but that breaks the existing code.我为模板定义了一个泛型类类型,但这破坏了现有的代码。 Here is my current version:这是我当前的版本:

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));
    ...

I think it might be barfing on the default parameter, but I can't be sure.我认为它可能会对默认参数产生影响,但我不能确定。 The error messages aren't very helpful:错误消息不是很有帮助:

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

This error message is from existing code;此错误消息来自现有代码; it doesn't seem to recognize the default parameter.它似乎无法识别默认参数。

Update 3更新 3

I've abandoned this approach and decided to write a Boost Socket Wrapper instead.我已经放弃了这种方法,而是决定编写一个 Boost Socket Wrapper。 The wrapper will hold the actual Socket instance, and its methods will be direct pass-throughs to the actual Socket.包装器将保存实际的 Socket 实例,其方法将直接传递到实际的 Socket。 The wrapper's functions will be virtual, and my mock object will inherit from the wrapper.包装器的功能将是虚拟的,我的模拟对象将从包装器继承。 Then my mock object will mock the wrapper's virtual functions.然后我的模拟对象将模拟包装器的虚函数。

The issue, as you've noticed, is that the compiler cannot deduce whatever type Socket is meant to represent here:正如您所注意到的,问题在于编译器无法推断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));
    ...

If you try to construct an object of this class without specifying the third argument (as in new PIngester(ioService, band) ), what would Socket be exactly?如果您尝试构造此类的对象而不指定第三个参数(如new PIngester(ioService, band) ),那么Socket究竟是什么?

Now, there's no way to explicitly specify any template parameter when calling the constructor, so you can't do something like new PIngester<boost::asio::ip::udp::socket>(ioService, band) if the constructor is templatized.现在,有没有办法来明确指定调用构造函数时任何模板参数,所以你不能这样做new PIngester<boost::asio::ip::udp::socket>(ioService, band)如果构造器模板化。


Here are a couple ways (out of potentially many) to work around this:这里有几种方法(可能有很多)来解决这个问题:

  1. You could templatize the PIngester class itself:您可以模板化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)); ...

    Then calling new PIngester<boost::asio::ip::udp::socket>(ioService, band) (or your mock class in place of boost::asio::ip::udp::socket ) would work.然后调用new PIngester<boost::asio::ip::udp::socket>(ioService, band) (或者你的模拟类代替boost::asio::ip::udp::socket )会起作用。

  2. You could define a default template parameter:您可以定义一个默认模板参数:

     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)); ...

    Then PIngester(ioService, band) would always use this default Boost class, and you'd need to explicitly pass in some socket that represents a unique pointer to your mock class if you want to use this in tests.然后PIngester(ioService, band)将始终使用这个默认的 Boost 类,如果你想在测试中使用它,你需要显式传入一些代表模拟类的唯一指针的socket

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM