寻找方法'模拟' POSIX在C/C++中功能代码
我正在尝试找到一些优雅的方法来模拟和存根功能调用标准C库功能。 虽然仅通过链接测试中的其他C文件,但对项目的C文件的固定调用很容易,但标准C函数的固定很难。 它们在链接时就在那里。
当前,我的方法是包括我的test.cpp文件中的代码下测试,并放置这样的定义:
#include <stdio.h>
#include <gtest/gtest.h>
#include "mymocks.h"
CMockFile MockFile;
#define open MockFile.open
#define close MockFile.close
#define read MockFile.read
#include "CodeUnderTestClass.cpp"
#undef open
#undef close
#undef read
// test-class here
这很麻烦,有时我跨过代码,将“打开”用作其他位置的成员名称或导致其他碰撞和其他碰撞和问题。还有一些代码需要不同的定义和包括测试代码的情况。
那么还有其他选择吗?一些链接时间技巧或运行时技巧以覆盖标准C功能?我考虑过运行时挂接功能,但这可能会过度,因为通常将二进制代码加载仅读取。
我的单位测试仅在AMD64上与GCC一起在Debian-Linux上进行。因此,也欢迎GCC,X64或Linux特定技巧。
我知道,在使用C函数的抽象版本的所有代码中重写所有代码是一个选项,但提示对我来说不是很有用。
I am trying to find somewhat elegant ways to mock and stub function calls to the standard C library functions.
While stubbing-off calls to C files of the project is easy by just linking other C files in the tests, stubbing the standard C functions is harder.
They are just there when linking.
Currently, my approach is to include the code-under-test from my test.cpp file, and placing defines like this:
#include <stdio.h>
#include <gtest/gtest.h>
#include "mymocks.h"
CMockFile MockFile;
#define open MockFile.open
#define close MockFile.close
#define read MockFile.read
#include "CodeUnderTestClass.cpp"
#undef open
#undef close
#undef read
// test-class here
This is cumbersome, and sometimes I run across code that uses 'open' as member names elsewhere or causes other collisions and issues with it. There are also cases of the code needing different defines and includes than the test-code.
So are there alternatives? Some link-time tricks or runtime tricks to override standard C functions? I thought about run-time hooking the functions but that might go too far as usually binary code is loaded read-only.
My unit-tests run only on Debian-Linux with gcc on amd64. So gcc, x64 or Linux specific tricks are also welcome.
I know that rewriting all the code-under-test to use an abstracted version of the C functions is an option, but that hint is not very useful for me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
使用库预加载以自己的方式替换系统库。
考虑以下测试程序代码,
mytest.c
:它将从当前目录打开一个名为
file
的文件,打印其描述符号码(通常3
),读取其内容,然后在标准输出(Deciptor0
)上打印它。现在,这是您的测试库代码,
mock.c
:将其编译到共享库,称为
mock.so
:如果您编译了
mytest.c
在mytest
二进制文件中,使用以下命令运行:您应该看到输出:
mock.c.c
中定义的函数。 ,因此执行您的代码,而不是系统库中的代码。更新:
如果要使用“原始”函数,则应使用
dlopen
,dlmap 和
dlclose
函数。因为我不想混乱上一个示例,所以这是新的示例,与以前的mock.c
加上动态符号加载的内容相同:用以下方式编译:
注意
-ldl
在命令末尾。因此:
启动
函数将在main
之前运行(因此,您无需将任何初始化代码放在原始程序中),然后初始化real_write
to to成为原始写
函数。清理
功能将在main
之后运行,因此您也无需在main
函数的末尾添加任何“清洁”代码。除了新实现的
Write
函数外,所有其余的工作原理与上一个示例完全相同。对于几乎所有的描述符,它将用作原始内容,对于文件描述符0,它将在原始内容之前写入一些额外的数据。在这种情况下,该程序的输出将为:Use library preloading to substitute system libraries with your own.
Consider following test program code,
mytest.c
:It will open a file called
file
from the current directory, print it's descriptor number (usually3
), read its content and then print it on the standard output (descriptor0
).Now here is your test library code,
mock.c
:Compile it to a shared library called
mock.so
:If you compiled
mytest.c
to themytest
binary, run it with following command:You should see the output:
Functions defined in
mock.c
were preloaded and used as a first match during the dynamic linking process, hence executing your code, and not the code from the system libraries.Update:
If you want to use "original" functions, you should extract them "by hand" from the proper shared library, using
dlopen
,dlmap
anddlclose
functions. Because I don't want to clutter previous example, here's the new one, the same as previousmock.c
plus dynamic symbol loading stuff:Compile it with:
Note the
-ldl
at the end of the command.So:
startup
function will run beforemain
(so you don't need to put any initialization code in your original program) and initializereal_write
to be the originalwrite
function.cleanup
function will run aftermain
, so you don't need to add any "cleaning" code at the end ofmain
function either.All the rest works exactly the same as in the previous example, with the exception of newly implemented
write
function. For almost all the descriptors it will work as the original, and for file descriptor 0 it will write some extra data before the original content. In that case the output of the program will be: