我有一个包裹Asio的课程。它旨在模拟域和tcp套接字上的通信,但我不知道自动化单元测试。我查看了FakeIt,但它只测试虚拟方法,GoogleMocks suggests模板化我的代码,这样我就可以通过MockAsio实现单元测试和真正的Asio生产。
有没有其他方法来单元测试网络代码?假冒域和tcp套接字而不是运行整个堆栈?如果我使用GoogleMock,为什么要使用一个使用GoogleMock的课程,而不是我自己的实现,它可以满足我的需要?
我最近遇到了同样的问题。由于Asio服务的方法(例如socket的read_some
)通常不是虚拟的,因此简单的依赖注入是不可能的。据我了解,有两种可能的方法,它们都在Google Mock Cook Book中讨论过:
讨论了here。
这是@ruipacheco在他的问题中已经提到的选项。
此选项需要对您的类进行模板化,但它会引入最少的代码开销。
例如,如果您的类使用Asio tcp套接字,则构造它的实例将类似于:
asio::io_context io_context;
MyClass<asio::ip::tcp::socket> my_class(io_context);
讨论了here。
这或多或少是@NiladriBose所建议的。
此选项需要为每种服务类型(套接字,定时器等)编写Asio接口和Asio具体适配器!然而,它是最通用和最强大的(并且它不需要像你之前的选项那样对你的类进行模板化)。
例如,如果您的类使用Asio tcp套接字,则构造它的实例将类似于:
asio::io_context io_context;
AsioSocket socket(io_context);
MyClass my_class(socket);
如果您的类使用多个Asio服务实例(多个套接字,定时器等...),那么创建一个抽象的Asio服务工厂可能会更好。这个工厂将在其构造函数中收到io_context
,并导出make_socket
,make_timer
等方法。
然后,构建一个类的实例看起来像:
AsioFactory asio_factory(io_context);
MyClass my_class(asio_factory);
最后,关于:
如果我使用GoogleMock,为什么要使用一个使用GoogleMock的课程,而不是我自己的实现,它可以满足我的需要?
请参阅this以了解模拟和假对象之间的区别。一般来说,我认为模拟对象需要更少的努力。另请参阅this以了解如何将Google模拟类与假类合并。
我假设你想模拟你的应用程序使用的ASIO包装器类。如果我的假设是正确的,那么说包装器有一个接口(过于简单 - 但大多数模拟框架需要一个纯粹的抽象,包括gmock) -
class Iasio
{
virtual ~Iasio()
{
}
virtual void send(std::vector<unsigned char> dataToSend) = 0;
virtual std::vector<unsigned char > rcv() = 0;
};
然后你有两个选项 - 1)模拟使用模拟框架,并在你的单元测试中使用模拟(将模拟注入使用contructor或accessor注入使用它的类)。对于每个单元测试场景,您需要设置模拟对象以返回预期的数据。
2)第一个选项有时可能比编写自己的测试模拟更麻烦,在这种情况下编写自己的测试模拟可以完全接受,从而为您提供更多控制。我说更多的控制因为模拟框架是通用的,它们可以在大多数常见场景中提供帮助,但复杂的场景可能需要定制的测试虚拟/模拟。