在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。
(不是重复,但这可能有帮助吗?)http://stackoverflow.com/questions/2924440/advice-on-mocking-system-calls – IdeaHat 2014-12-03 18:32:41
是我还是你想要的行为在单元测试范围之外进行测试,并进行集成测试?我想,这是一个迂腐点,但可以改变答案的范围。对大多数开发者来说,这是两个非常不同的话题 – ChrisCM 2014-12-03 18:38:56
@ChrisCM在我看来,这不是一个集成测试,因为我不想做一个真正的部署,或者使用多台机器。此外,我不想测试整个产品,但只有一些实现部分,如事件循环,网络服务,流媒体。它应该是一个单一的二进制文件,完成所有的工作。你认为它看起来像集成测试吗? – 2014-12-03 18:46:33