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

aby*_*s.7 12 c c++ linux unit-testing network-programming

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

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

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

主要目标不是与机器上的真实网络接口进行交互或混乱.


你有什么建议吗?

Ste*_*mer 5

在 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);
Run Code Online (Sandbox Code Playgroud)

你会像这样使用它:

#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;
}
Run Code Online (Sandbox Code Playgroud)

getaddrinfo来自被测库内的任何调用现在都将调用mocked_getaddrinfo.

elf_hook 作者 Anthony Shoumikhin 的综合文章在这里


rak*_*hdn 0

如果您愿意花费时间和精力,您可以对任何代码进行单元测试。基本上,通过单元测试,您有兴趣实现代码覆盖率的目标百分比以及某些行业的 MC/DC 覆盖率。在某些情况下,您需要编写模拟代码(将类似于操作系统 API / 套接字 API 的函数导出到被测单元的模块),这将有助于驱动“被测单元”中每个角落和缝隙的执行(a .c/.cpp 文件)通过返回您告诉它的值。

您可能需要为被测单元指定与测试应用程序其余部分不同的包含路径,以避免名称冲突,并且您可能还必须在测试标头中使用预处理器宏,以使模拟 API 看起来像真实的 API到您的“单位”并保持与生产代码中的相同。

您可以测试硬件驱动程序和任何类型的低级代码。

例如,如果您的代码正在写入和读取内存映射寄存器,您希望基于 FPGA 的逻辑能够更改这些寄存器,但您没有硬件(或者您很难在不实际前往火星的情况下生成测试条件),然后您可以编写宏/包装函数来读取和写入寄存器,这些寄存器将返回您的模拟值。以前用过CppUTest,很容易学。我想谷歌搜索会出现很多结果。

  • 你应该专注于解决实际问题...这只是如何进行测试的一般描述 - 几乎任何测试 (2认同)