lei*_*eif 12 c linker unit-testing mocking
我想在C中编写C库的测试.我想模拟测试的一些函数.
假设我的库是从以下源编译的:
/* foo.h */
int myfunction(int x, int y);
/* foo.c */
#include "foo.h"
static int square(int x) { return x * x; }
int myfunction(int x, int y) {
return square(x) + square(y);
}
Run Code Online (Sandbox Code Playgroud)
我想写一个这样的测试:
/* foo_test.c */
#include "foo.h"
static int square(int x) { return x + 1; }
int main(void) {
assert(myfunction(0, 0) == 2);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有没有什么方法可以编译,只有在链接可执行文件时myfunction才会使用squarein 的定义foo_test.c而不是in 的定义?也就是说,我想编译成一个库(让我们调用它),然后用一些魔法进行编译,这样我就可以获得一个使用不同实现的可执行文件.foo.cfoo_testfoo.clibfoo.sofoo_test.clibfoo.sofoo_testsquare
听到square没有宣布何时的解决方案会很有帮助static,但解决上述情况会更好.
编辑:这似乎没有希望,但这里有一个想法:假设我编译-O0 -g所以它不太可能square会被内联,我应该有符号显示调用的地方.有没有办法潜入目标文件并换出已解决的参考?
我写了一个Mimick,一个用于解决这个问题的C函数的模拟 /存根库.
假设square不是静态的也不是内联的(因为否则它会绑定到编译单元和使用它的函数)并且你的函数被编译在名为"libfoo.so"的共享库中(或者你的平台的任何命名约定是),这就是你要做的:
#include <stdlib.h>
#include <assert.h>
#include <mimick.h>
/* Define the blueprint of a mock identified by `square_mock`
that returns an `int` and takes a `int` parameter. */
mmk_mock_define (square_mock, int, int);
static int add_one(int x) { return x + 1; }
int main(void) {
/* Mock the square function in the foo library using
the `square_mock` blueprint. */
mmk_mock("square@lib:foo", square_mock);
/* Tell the mock to return x + 1 whatever the given parameter is. */
mmk_when(square(mmk_any(int)), .then_call = (mmk_fn) add_one);
/* Alternatively, tell the mock to return 1 if called with 0. */
mmk_when(square(0), .then_return = &(int) { 1 });
assert(myfunction(0, 0) == 2);
mmk_reset(square);
}
Run Code Online (Sandbox Code Playgroud)
这是一个完整的模拟解决方案,如果你只想存根square(而不关心测试交互),你可以做类似的事情:
#include <stdlib.h>
#include <assert.h>
#include <mimick.h>
static int my_square(int x) { return x + 1; }
int main(void) {
mmk_stub("square@lib:foo", my_square);
assert(myfunction(0, 0) == 2);
mmk_reset(square);
}
Run Code Online (Sandbox Code Playgroud)
Mimick通过对正在运行的可执行文件使用一些内省并在运行时中毒全局偏移表来将函数重定向到我们选择的存根.
看起来您正在使用GCC,因此可以使用weak属性:
弱属性导致声明以弱符号而不是全局符号的形式发出。尽管它也可以与非函数声明一起使用,但它在定义可以在用户代码中覆盖的库函数时非常有用。使用GNU汇编器和链接器时,ELF目标和a.out目标均支持弱符号。
http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html