如何对依赖于Asio的一段代码进行单元测试

How to unit test a piece of code that relies on Asio?

本文关键字:一段 代码 单元测试 依赖于 Asio      更新时间:2023-10-16

我有一个包装Asio的类。它的目的是模拟通信域和tcp套接字,但我在自动化单元测试的损失。我看了看FakeIt,但它只测试虚拟方法,GoogleMocks建议模板化我的代码,这样我就可以通过MockAsio实现进行单元测试,并在生产中通过真正的Asio。

是否有其他方法对网络代码进行单元测试?伪造一个域名和tcp套接字,而不是运行整个堆栈?如果我用GoogleMock,为什么要用一个使用GoogleMock的类而不是我自己的实现呢?

我最近遇到了同样的问题。由于Asio服务的方法(例如套接字的read_some)通常不是虚拟的,因此简单的依赖注入是没有问题的。据我所知,有两种可能的方法,它们都在Google Mock Cook Book中讨论过:

高性能依赖注入(duck typing)

这里讨论

.

这是@ruipacheco在他的问题中已经提到的选项。

此选项需要模板化您的类,但它引入的代码开销最少。

例如,如果您的类使用Asio tcp套接字,则构造它的实例将看起来像:

asio::io_context io_context;
MyClass<asio::ip::tcp::socket> my_class(io_context);

接口代码

这里讨论

.

这或多或少就是@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,而不是我自己的实现,做任何我需要的?

了解mock和fake对象之间的区别。一般来说,我认为模拟对象需要的工作要少得多。还可以查看下面的内容,了解如何将Google模拟类与伪类合并。

我假设您想模拟应用程序使用的ASIO包装器类。如果我的假设是正确的,那么说包装器有一个接口(过于简化-但大多数mock框架需要一个纯抽象,包括gmock)-

    class Iasio
    {
        virtual ~Iasio()
        {
        }
        virtual void send(std::vector<unsigned char> dataToSend) = 0;
        virtual std::vector<unsigned char > rcv() = 0;
    };

那么你有两个选择-1)使用mock框架进行mock,并在单元测试中使用mock(使用构造函数或访问器注入将mock注入使用它的类中)。为此,对于每个单元测试场景,您都需要设置模拟对象以返回您期望的数据。

2)第一个选项有时可能比编写自己的测试模拟更麻烦,在这种情况下,编写自己的测试模拟是完全可以接受的,这样可以给您更多的控制。我说更多的控制,因为模拟框架是通用的,它们可以帮助大多数常见的场景,但复杂的场景可能需要一个定制的测试假人/模拟。