[英]GoogleMock mocking non-virtual functions
我们正在为现有代码库编写单元测试。 我们使用 Google Test/Google Mock 进行测试,C++11 和带有 gcc 编译器的 Eclipse CDT。
我们的一个类聚合了一个 Boost Socket。 它使用它作为实例,但幸运的是我们可以修改现有的代码库,我将其更改为指针并将套接字作为依赖项注入。 所以我开始模拟对套接字的调用,但有一个问题:Boost 函数是非虚拟的。
我找到了展示如何使用高性能依赖注入来模拟非虚拟函数的文档。 然而,试图按所示实施它,但没有成功。 例如,文档说“模板化你的代码”。 所以对于我们使用boost socket的类,我遵循了他们的例子。 我插入:
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。 包装器的功能将是虚拟的,我的模拟对象将从包装器继承。 然后我的模拟对象将模拟包装器的虚函数。
正如您所注意到的,问题在于编译器无法推断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)
如果构造器模板化。
这里有几种方法(可能有很多)来解决这个问题:
您可以模板化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
)会起作用。
您可以定义一个默认模板参数:
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
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.