C 中 exit() 的单元测试

Unit testing for exit() in C

我使用 CUnit 框架来显示测试结果。 (我是一名编程 & S.O。新手所以一步一步的回答真的很感激)。

当我测试我希望退出的函数时,有什么方法可以使用相同的 CUnit 框架吗?对我来说似乎不是这样,但我还是很想问 - 它会显示 pass/fail 结果以及我的其他 CUnit 测试,所以它是理想的。

如果没有,我一直在寻找其他对新手友好的解决方案(例如this SO post),但我不能使用GOTO/setjmp/longjmp。该解决方案还需要便携。

我正在使用 Mac & gcc 命令行来 运行 这段代码。

编辑 建议的解决方案之一是使用 C 预处理器 (CPP) 指令 /"mocking",这看起来很理想?我在 test.c 文件中使用了以下代码:

#define ERROR(PHRASE) {fprintf(stderr,"Fatal Error %s occurred in %s, line %d\n",PHRASE, FILE, LINE); exit(2);} 
#ifdef ERROR(PHRASE)
#define ERROR(PHRASE) {printf("In test phase");} 
#endif 
#ifndef ERROR(PHRASE #define ERROR(PHRASE) {printf("Not In test phase");} 
#endif

这是终端给我的错误信息:

test.c:30:9: warning: 'ERROR' macro redefined [-Wmacro-redefined]
#define ERROR(PHRASE) {printf("In test phase");}
        ^
test.c:26:9: note: previous definition is here
#define ERROR(PHRASE) {fprintf(stderr,"Fatal Error %s occured in %s, lin...
        ^
test.c:32:14: warning: extra tokens at end of #ifndef directive
      [-Wextra-tokens]
#ifndef ERROR(PHRASE) {printf("Not In test phase");}

删除 (PHRASE) 仍然会出现相同的错误。

编辑 如果对其他人有帮助,使用 #ifdef 进行模拟是最终解决此问题的最简单方法。 This website 也很有帮助。

为了让您知道要搜索什么,您要做的是 "mock" exit() 调用。基本思想是为退出函数选择不同的实现,通常是在编译时。坦率地说,C 并没有使这变得特别容易,但是有一些选项具有不同级别的可移植性和侵入性。

This article 描述了一些非常便携,但也相当侵入性的东西。基本上,您使用宏 and/or 函数指针来回切换,这意味着稍微修改您的代码,但老实说,这没什么大不了的。

对于可能不那么侵入但也不太便携的东西,this article 有几个想法(我相信两者都适用于 MacOS)。在这里,您可以让链接器将 exit() 调用重定向到您提供的另一个函数。好消息是它不需要对您的代码进行任何修改。坏消息是它需要你获得链接器的合作,并且不会在任何地方工作(LD_PRELOAD 不会在 Windows 上工作,AFAIK --wrap 需要 GNU ld 或兼容的东西)。

如果在测试方面有 issues/increased 努力,可能会考虑的一个方面是是否有任何范围可以以某种方式更改正在测试的程序,这将有助于测试而不显着增加程序的复杂性代码。

在这种情况下,是否可以使用函数中的错误 return 代码替换对 exit() 的调用,以便调用者可以在实际退出之前执行诸如整理或记录状态之类的操作?如果是这样,这既简化了测试,也可能简化了代码在 release/production 中实际使用时的故障查找,因为要弄清楚为什么一个程序只是在你身上运行和死亡是非常棘手的,特别是如果代码隐藏在库函数中!

如果你想做一些非侵入性的事情,你可以运行将被测函数作为一个单独的进程。您可以使用 CreateProcess (Windows) 或 fork(并且可能在 Max 和 Linux 上使用 execv。您的测试代码然后使用 wait 来测试退出代码,如果创建的进程正确退出则通过。