我在使用cmocka、测试malloc故障(模拟)和使用gcov时,很难找到一个nitch案例的答案。
关于cmocka+gcov的更新:我注意到当我在我的cmocka测试中模拟一个函数时,我就得到了空的gcda文件。为什么?谷歌搜索cmocka和gcov会给出人们谈论将两者结合使用的结果。似乎大多数人都在使用CMake,我将在后面讨论这一点,但应该没有理由(我能想到的)需要我使用cmake。为什么我不能只使用带有--coverage/-lgcov标志的cmocka?
原始问题:
我尝试了无数的组合,主要基于两个主要想法:
我尝试使用-Wl,--wrap=malloc,这样就可以封装对malloc的调用。在我的cmocka测试中,我尝试使用will_return(__wrap_malloc,(void*)NULL)来模拟malloc故障。在我的wrap函数中,我使用mock()来确定我应该返回__real_malloc()还是NULL。这有理想的效果,但是我发现gcov无法创建gcda文件,这是使用包装malloc的部分原因,因此我可以测试malloc失败并获得代码覆盖率结果。我觉得我用符号玩了个肮脏的游戏,搞乱了从其他编译单元调用的malloc()调用(gcov?cmocka?)。
我尝试的另一种方式是让我们使用# -include for malloc定义"my malloc“,然后编译要用mymalloc.c测试的目标代码(定义"my malloc")。因此,#define malloc _mymalloc帮助我从目标测试代码中只调用“特殊的malloc”,而不去调用其他被调用的malloc (也就是,让其他编译单元单独运行,这样它们就总是调用真正的malloc)。但是,我不知道如何正确使用will_return()和mock()来检测失败案例与成功案例。如果我测试malloc()失败,我得到我想要的东西,我会根据mock()返回NULL,从" malloc“返回NULL-这都是在malloc的包装函数中完成的,该函数只在目标代码中调用。但是,如果我想返回真正的malloc的结果,那么cmocka将失败,因为我没有从mock()返回结果。我希望我能让cmocka从mock()宏中将结果出队,然后不关心我没有返回结果,因为我需要来自malloc()的真实结果,这样测试下的代码才能正常工作。
我觉得应该可以将malloc测试与cmocka结合起来,并获得gcov结果。
无论答案是什么,我都想从下面或者类似的东西中提取出来。
int business_code()
{
void* d = malloc(somethingCalculated);
void* e = malloc(somethingElse);
if(!d) return someRecovery();
if(!e) return someOtherRecovery();
return 0;
}然后进行cmocka测试,比如
cmocka_d_fail()
{
will_return(malloc, NULL);
int ret = business_code();
assert_int_equal(ret, ERROR_CODE_D);
}
cmocka_e_fail()
{
will_return(malloc, __LINE__); // someway to tell wrapped malloc to give me real memory because the code under test needs it
will_return(malloc, NULL); // I want "d" malloc to succeed but "e" malloc to fail
int ret = business_code();
assert_int_equal(ret, ERROR_CODE_E);
}我接近了一些我尝试过的#定义/包装的想法,但最后我要么搞砸了malloc并导致gcov不输出我的覆盖率数据,要么我没有办法让cmocka运行malloc case并返回实际内存,即不能从mock()调用中返回。一方面,我可以从我的测试驱动程序中调用真正的malloc,但是将它传递给will_return,但是我的test_code不知道所需的内存大小,只有被测试的代码知道。
考虑到时间限制,我不想离开cmocka和我当前的测试基础架构。不过,如果我想要的东西不可能实现,我会在未来考虑其他想法。我正在寻找的东西,我知道不是新的,但我正在尝试使用cmocka/gcov解决方案。
谢谢
发布于 2015-12-30 13:44:16
这一切都归结于我使用了-lW、--wrap或聪明的#defines处理了哪些符号。在这两种情况下,我要么重击了其他调用点的符号,破坏了代码,要么混淆了cmocka和没有将排队的返回出列。
另外,我的gcda文件没有正确生成的原因是我试图使用-Wl,--wrap=fseek和cmocka的mock()把我搞得一团糟。
在你的包装器实现中调用的符号的巧妙的#定义与mock()相结合,可以简而言之地查询测试套件,看看你是否应该返回一些虚假的东西来导致测试失败或返回真实的结果。有点老生常谈,但很管用。
发布于 2016-08-31 15:45:26
这个变通方法适用于我:用_test_malloc()代替malloc()。
工作示例可以在https://github.com/CESNET/Nemea-Framework/blob/2ef806a0297eddc920dc7ae71731dfb2c0e49a5b/libtrap上找到。tests/test_trap_buffer.c包含一个包装函数__wrap__test_malloc()的实现(注意名称中的4x '_‘)
void *__real__test_malloc(const size_t size, const char* file, const int line);
void *__wrap__test_malloc(size_t size)
{
int fail = (int) mock();
if (fail) {
return NULL;
} else {
return __real__test_malloc(size, __FILE__, __LINE__);
}
}以及例如用于测试使用3x malloc()的tb_init()函数的test_create_destroy()
static void test_create_destroy(void **state)
{
trap_buffer_t *b = NULL;
(void) state; /* unused */
b = tb_init(0, 0);
assert_null(b);
b = tb_init(0, 1);
assert_null(b);
b = tb_init(1, 0);
assert_null(b);
will_return(__wrap__test_malloc, 0);
will_return(__wrap__test_malloc, 0);
will_return(__wrap__test_malloc, 0);
b = tb_init(10, 100000);
assert_non_null(b);
tb_destroy(&b);
tb_destroy(&b);
tb_destroy(NULL);
}为了完整起见,tb_init()在src/trap_buffer.c行146。
编译可以像这样运行(来自Makefile的示例):
buffer:
gcc --coverage -g -O0 -DUNIT_TESTING -c tests/test_trap_buffer.c
gcc --coverage -g -O0 -DUNIT_TESTING -c src/trap_buffer.c
gcc -g -O0 -Wl,--wrap=_test_malloc -lcmocka --coverage -DUNIT_TESTING -o test_buffer test_trap_buffer.o trap_buffer.o请参阅为cmocka定义的UNIT_TESTING预处理器宏,这一点很重要,因为它可以在我们的代码中测试分配函数。
最后,运行测试为我们生成*.gcda文件,因此我们可以可视化代码覆盖率。测试的tb_init()的输出:https://codecov.io/gh/CESNET/Nemea-Framework/src/775cfd34c9e74574741bc6a0a2b509ae6474dbdb/libtrap/src/trap_buffer.c#L146
https://stackoverflow.com/questions/34503110
复制相似问题