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

时间:2014-12-03 18:20:17

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

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

我认为存在一些可以部署在几乎任何工作站上的C / C ++测试框架或者允许我使用的编程技术:

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

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


你能提出什么建议?

2 个答案:

答案 0 :(得分:4)

在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

答案 1 :(得分:0)

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

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

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

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