我想用单元测试来覆盖我的代码。这是好事。但我有一个问题 - 我有一个网络代码。该代码确实从主机名解析 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/