我想用 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);
}
我想写一个这样的测试:
/* foo_test.c */
#include "foo.h"
static int square(int x) { return x + 1; }
int main(void) {
assert(myfunction(0, 0) == 2);
return 0;
}
有没有什么方法可以让 myfunction
使用 foo_test.c
中 square
的定义,而不是foo.c
,仅在链接可执行文件foo_test
时?也就是说,我想将 foo.c
编译成一个库(我们称它为 libfoo.so
),然后用 foo_test.c
编译libfoo.so
和一些魔法,这样我就可以得到一个可执行文件 foo_test
,它使用 square
的不同实现。
听到 square
未声明为 static
时的解决方案会很有帮助,但解决上述情况会更好。
编辑:这似乎没有希望,但有一个想法:假设我用 -O0 -g
编译,所以 square
不太可能被内联,我应该显示符号解决调用的地方。有没有办法潜入目标文件并换出已解析的引用?
最佳答案
我写了Mimick ,一个用于解决此问题的 C 函数的模拟/ stub 库。
假设 square 既不是静态的也不是内联的(因为否则它会绑定(bind)到编译单元和使用它的函数)并且你的函数是在一个名为“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);
}
不过,这是一个成熟的模拟解决方案,如果您只想 stub 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);
}
Mimick 的工作原理是对正在运行的可执行文件使用一些内省(introspection),并在运行时对全局偏移表进行中毒,以将函数重定向到我们选择的 stub 。
关于c - C 中的函数模拟(用于测试)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8959132/