c++ - 在 Linux 上测试网络代码的最准确方法是什么?

标签 c++ c linux unit-testing network-programming

我想用单元测试来覆盖我的代码。这是好事。但我有一个问题 - 我有一个网络代码。该代码确实从主机名解析 IPv4 和 IPv6 地址、绑定(bind)到接口(interface)、监听、连接等。

我假设存在一些可以部署在几乎任何工作站上的 C/C++ 测试框架或一些允许我执行以下操作的编程技术:

  • 使用 IPv4 和 IPv6 地址设置和拆除自定义网络接口(interface)
  • 模拟不同的干扰行为,如丢包、超时、连接断开等。
  • 将主机名绑定(bind)到接口(interface)并解析它们。

主要目标不是与机器上的真实网络接口(interface)进行交互或弄乱。


你有什么建议?

最佳答案

在 ELF 系统上,您可以使用 elf_hook用您自己的模拟版本临时替换各种函数的真实版本。

它允许您将共享库中对任何函数的调用重定向到您自己的任意函数。

  • 创建一个包含被测代码的共享库
  • 在您的测试中动态加载共享库 (dlopen)
  • 将要模拟的符号重定向到测试函数(elf_hook)
  • 现在对库中真实函数(被测代码)的任何调用都将重定向到您的模拟函数

此方法的一个优点是您仍然可以在需要时调用原始函数。

  • 如果您希望调用某些测试,例如 getaddrinfo,成功,您可以调用系统版本。
  • 在其他测试中,您可以使用自己的模拟版本,例如 mocked_getaddrinfo,并让它返回您想要的任何内容。
  • 您可以根据需要创建任意数量的 mocked_getaddrinfo 函数,以测试多个场景

elf_hook 具有以下签名:

void* elf_hook(char const* library_filename, 
               void const* library_address, 
               char const* function_name, 
               void const* substitution_address);

你会这样使用它:

#include <dlfcn.h>
#include "elf_hook.h"

void do_stuff(); // from the library under test (do_stuff calls getaddrinfo)

// our mocked function which will alter the behaviour inside do_stuff()
int mocked_getaddrinfo(const char* node, 
                       const char* service,
                       const struct addrinfo* hints,
                       struct addrinfo** res)
{
    // return a broken value to test a getaddrinfo failure
    return 42;
}

// another version which actually calls the real function
int real_getaddrinfo(const char* node, 
                     const char* service,
                     const struct addrinfo* hints,
                     struct addrinfo** res)
{
    // the real getaddrinfo is available to us here, we only replace it in the shared lib
    return getaddrinfo(node, service, hints, res);
}

int main()
{
    const char* lib_path = "path/to/library/under/test.so";

    // load the library under test
    void* lib_handle = dlopen(lib_path, RTLD_LAZY);

    // test 1: getraddrinfo is broken
    //--------------------------------
    // replace getaddrinfo with our 'mocked_getaddrinfo' version
    elf_hook(lib_path, LIBRARY_ADDRESS_BY_HANDLE(lib_handle), 
             "getaddrinfo", mocked_getaddrinfo);

    // call a function in the library under test where getaddrinfo fails
    do_stuff();

    // test 2: getraddrinfo is the system version
    //--------------------------------
    // replace getaddrinfo with our 'real_getaddrinfo' version 
    elf_hook(lib_path, LIBRARY_ADDRESS_BY_HANDLE(lib_handle), 
             "getaddrinfo", real_getaddrinfo);

    // call the same function in the library, now getaddrinfo works
    do_stuff();

    dlclose(lib_handle);
    return 0;
}

从被测库中对 getaddrinfo 的任何调用现在都将调用 mocked_getaddrinfo

elf_hook 作者 Anthony Shoumikhin 的综合文章是 here .

关于c++ - 在 Linux 上测试网络代码的最准确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27278878/

相关文章:

c++ - boost::signals2 仍然向引用死亡的对象发出信号

c++ - 如何模拟原始输入/以正确的方式向应用程序发送 WM_INPUT 消息?

linux - 我的 Perl 有多糟糕?获取 IP 地址并返回完全限定域名的脚本

Linux X session 脚本

linux - 如何在 Mac OS X 和 Linux 上对鼠标点击进行编程?

c++ - SQL Server 2012 通过 native C++(无 ATL)从 Windows 首选访问方法

c++ - QJsonDocument::toJson() 生成超大文本。有办法解决吗?

c - putc() 在 c 中返回什么?

c - 将 char* 拆分为 char * 数组

客户端收不到服务器消息?