如何对依赖Asio的代码进行单元测试?

时间:2016-10-20 13:56:55

标签: c++ unit-testing sockets network-programming boost-asio

我有一个包装Asio的课程。它旨在模拟域和tcp套接字上的通信,但我不知道自动化单元测试。我查看了FakeIt,但它只测试虚拟方法,GoogleMocks suggests模板化我的代码,以便我可以在生产中传递MockAsio实现单元测试和真正的Asio。

有没有其他方法可以对网络代码进行单元测试?假冒域和tcp套接字而不是运行整个堆栈?如果我使用GoogleMock,为什么要使用一个使用GoogleMock的课程,而不是我自己的实现,它可以满足我的需求?

2 个答案:

答案 0 :(得分:1)

我最近遇到了同样的问题。由于Asio服务的方法(例如套接字的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_socketmake_timer等方法。

然后,构造您的类的实例将类似于:

AsioFactory asio_factory(io_context);
MyClass my_class(asio_factory);

最后,关于:

  

如果我使用GoogleMock,为什么要使用使用GoogleMock的类,而不是使用自己的实现所需功能的实现?

请参见this,以了解模拟对象与伪造对象之间的区别。一般来说,我认为模拟对象需要更少的精力。 另请参阅this,了解如何将Google模拟类与伪类合并。

答案 1 :(得分:-1)

我假设您要模拟应用程序使用的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)第一个选项有时可能比编写自己的测试模拟更麻烦,在这种情况下编写自己的测试模拟可以让你获得更多控制是完全可以接受的。我说更多的控制因为模拟框架是通用的,它们可以在大多数常见场景中提供帮助,但复杂的场景可能需要定制的测试虚拟/模拟。