在编译时重写或破坏 C 单元测试的函数链接

Posted

技术标签:

【中文标题】在编译时重写或破坏 C 单元测试的函数链接【英文标题】:Rewriting or breaking function linkage for C unit testing at compile time 【发布时间】:2011-11-11 02:35:57 【问题描述】:

对于 C 中的单元测试,我想做的是在生产源中构建两个目标文件(A 和 B),它们相互调用函数。然后为单元测试提供 A 和 B 的 mock/fake 实现,可以在运行时切换进出以进行单元测试。

我想要做的是将 A、B、fake_A 和 fake_B 链接到一个大的测试二进制文件中,该二进制文件可以在运行时在模块的生产和假实现之间切换,以对两者进行单元测试。 这是因为最好避免为每个案例构建多个不同的测试二进制文件并且必须合并结果。

我将专门为单元测试编译 A 和 B,因此可以强制额外的标头、定义、编译器标志等在运行时不存在。

我想知道是否可以通过某种重写或链接时间技巧来打破 A 和 B 中的函数之间的链接。

让我试着说明一下。假设我有文件 a.c、b.c、fake_a.c 和 fake_b.c:

交流

void a_work(void) 
  b_work();

b.c

void b_work(void) 
  do_some_work();

fake_b.c

/* for test, when a_work() calls b_work() I want this to be run */
void b_work(void) 
  if (fake_b_enabled)
    do_fake_b_work();
  else
    // call the real b_work() somehow

通常 a_work() 对 b_work() 的调用会在链接时链接到真正的 b_work(),这就是我要拦截或重写的。

我正在考虑用函数指针层进行某种包装,但我不知道怎么做。

【问题讨论】:

为什么不直接链接到不同的目标文件? @OliCharlesworth 你什么意思? 【参考方案1】:

使用共享对象(在 *nix 上,或在 Windows 上的 DLL)。以测试和生产方式实现您的功能,但为每种方式构建一个共享库。然后,如果您想要一个在它们之间切换的二进制文件,请使用LD_LIBRARY_PATH 使二进制文件加载一个不同于您构建它的二进制文件。

【讨论】:

有趣的想法。不过,重点是获得一个我可以调用一次并执行所有测试的二进制文件。我想知道我是否可以使用运行时加载和卸载来做到这一点。 使用脚本多次运行测试。

以上是关于在编译时重写或破坏 C 单元测试的函数链接的主要内容,如果未能解决你的问题,请参考以下文章

Django SECURE_SSL_REDIRECT 破坏了使用内置客户端的单元测试

第六章:单元测试框架unittest

使用 URLRequestConvertible 的单元测试中的链接错误

使用 Gradle 对 JavaScript 进行单元测试?

Visual Studio单元测试调试

验证属性或配置的单元/集成测试