我想在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
将使用的定义 square
在 foo_test.c
而不是那个 foo.c
,仅在链接可执行文件时 foo_test
?也就是说,我想编译 foo.c
进入图书馆(让我们称之为 libfoo.so
),然后编译 foo_test.c
同 libfoo.so
和一些魔法,以便我得到一个可执行文件 foo_test
它使用不同的实现 square
。
听取何时解决方案会很有帮助 square
没有宣布 static
,但解决上述情况会更好。
编辑:似乎没有希望,但这是一个想法:假设我编译 -O0 -g
所以不太可能 square
将被内联,我应该有符号显示呼叫被解决的位置。有没有办法潜入目标文件并换出已解决的参考?
看起来您正在使用GCC,因此您可以使用weak属性:
weak属性导致声明以弱的形式发出
符号而不是全球。 这主要用于定义
可以在用户代码中重写的库函数, 虽然它可以
也可以与非函数声明一起使用。弱符号是
支持ELF目标,以及使用时的a.out目标
GNU汇编器和链接器。
http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
不,没有解决方案。如果范围内的函数的名称与源文件中的函数调用匹配,则将使用该函数。没有声明技巧会将编译器与它进行对话。当链接器处于活动状态时,名称引用将已经解析。
我写了 模拟天生,一个用于解决此问题的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);
}
这是一个完整的模拟解决方案,如果你只想要存根 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通过对正在运行的可执行文件使用一些内省并在运行时中毒全局偏移表来将函数重定向到我们选择的存根。
您正在寻找的内容在本文中描述: 使用C中的模拟对象进行单元测试
在像你这样的情况下,我使用 Typemock Isolator ++ API。
它允许您通过自己的实现替换方法的原始行为。
但是,由于语言的具体细节,您应该避免测试下的函数和相同的名称。
#include "foo.h"
static int square_test(int x) { return x + 1; }
TEST_CLASS(ArgumentTests)
{
public:
TEST_METHOD_CLEANUP(TearDown)
{
ISOLATOR_CLEANUP();
}
TEST_METHOD(TestStaticReplacedStatic)
{
PRIVATE_WHEN_CALLED(NULL, square).DoStaticOrGlobalInstead(square_test, NULL);
Assert::IsTrue(myfunction(0, 0) == 2);
}
};
希望它对你有用,祝你好运!