C FFF 模拟重新定义

问题描述 投票:0回答:1

我正在尝试使用 C 的 FFF 模拟库 (https://github.com/meekrosoft/fff) 对 C 代码进行单元测试。我遇到的问题是 gcc 将我的模拟对象视为原始函数的重新定义,并因此抛出编译器错误。

我创建了 2 个模仿我的用例的测试文件。

my_lib.c
有一些内部函数的定义。
test.c
正在导入
my_lib.c
,因为目的是测试源文件中的所有功能。

//my_lib.c

int thing = 0;

int get_thing () {
    return thing;
}

int do_thing (void) {
    return thing;
}

int set_thing (int x) {
    thing = x;
    return do_thing();
}

//test.c
#include "fff.h"
#include "my_lib.c"

DEFINE_FFF_GLOBALS;

FAKE_VALUE_FUNC0(int, do_thing);

void setup(void)
{
    // Reset the FFF call history between tests
    FFF_RESET_HISTORY();

    // Reset the FFF mock objects between tests
    RESET_FAKE(do_thing);
}

void test_do_thing(void)
{
    set_thing(11);

    ASSERT_EQ(1, do_thing_fake.call_count);
}

void test_nested_mock(void)
{
    do_thing_fake.return_val = -2;

    int ret = set_thing(11); //set_thing() returns do_thing() which is mocked to return -2

    ASSERT_EQ(-2, ret);
}

我正在编译成这样的目标文件,但这给了我一个立即编译错误:

$ gcc -g -c test.c -o test.o
In file included from test.c:1:0:
test.c:7:23: error: redefinition of ‘do_thing’
 FAKE_VALUE_FUNC0(int, do_thing);
                       ^
fff.h:1632:45: note: in definition of macro ‘DEFINE_FAKE_VALUE_FUNC0’
     RETURN_TYPE FFF_GCC_FUNCTION_ATTRIBUTES FUNCNAME(void){ \
                                             ^
test.c:7:1: note: in expansion of macro ‘FAKE_VALUE_FUNC0’
 FAKE_VALUE_FUNC0(int, do_thing);
 ^
In file included from test.c:3:0:
my_lib.c:12:1: note: previous definition of ‘do_thing’ was here
 do_thing (void)
 ^

我需要能够从源文件中模拟出函数,同时能够测试遗留源文件,而无需修改任何源文件或头文件。我对 fff 和/或 gcc 缺少什么? 编辑:让我添加这个。我可以从

my_lib.c

中删除 do_thing() 的定义,然后我的编译、模拟和测试完全按照预期工作,因为对 do_thing 的所有调用现在都转到我的模拟对象。我希望能够模拟在测试的源代码中已经定义的函数。

    

c unit-testing gcc mocking fake-function-framework
1个回答
1
投票

选项 1:

如果您只想在测试中模拟该函数而不使用其原始实现,那么解决方案很简单:

在原始函数定义(在 c 文件中)之前添加

weak

语句。例如,使用 GCC,您可以在函数定义之前编写:

__attribute((weak))
。 之前:
void foo(void)

之后:

__attribute((weak)) void foo(void)

这告诉编译器,如果代码中同一函数有另一个定义,则具有 
weak

属性的定义将被忽略。

此外,如果您不想更改源代码,可以使用 

#ifdef UNIT_TEST_ENABLED

添加它,并确保定义 UNIT_TEST_ENABLED 仅在单元测试项目中定义,而不是在生产代码项目中定义。 例如:

#ifdef UNIT_TEST_ENABLED 
__attribute((weak)) 
#endif 
void foo(void)

选项2:

如果您想在某些测试中使用原始实现,但也能够在其他测试中进行模拟,那么我建议您按照我在此处编写的说明进行操作:

https://stackoverflow.com/a/65814339/4441211

© www.soinside.com 2019 - 2024. All rights reserved.