c++ - 您如何将单元测试引入大型的遗留 (C/C++) 代码库?

标签 c++ c unit-testing unix legacy

我们有一个用 C 编写的大型多平台应用程序。(使用少量但不断增长的 C++)它经过多年发展,具有许多您期望在大型 C/C++ 应用程序中具有的功能:

  • #ifdef hell
  • 导致难以隔离可测试代码的大文件
  • 函数过于复杂,难以测试

由于此代码是针对嵌入式设备的,因此在实际目标上运行它会产生很多开销。因此,我们希望在本地系统上以快速的周期进行更多的开发和测试。但我们想避免“复制/粘贴到系统上的 .c 文件、修复错误、复制/粘贴回去”的经典策略。如果开发人员要不厌其烦地这样做,我们希望以后能够重新创建相同的测试,并以自动化的方式运行。

这是我们的问题:为了将代码重构为更加模块化,我们需要它更加可测试。但为了引入自动化单元测试,我们需要它更加模块化。

一个问题是,由于我们的文件太大,我们可能有一个文件中的函数调用同一文件中的函数,我们需要将其 stub 以进行良好的单元测试。随着我们的代码变得更加模块化,这似乎不再是一个问题,但这还有很长的路要走。

我们想做的一件事是用注释标记“已知可测试”的源代码。然后我们可以为可测试代码编写脚本扫描源文件,将其编译到单独的文件中,并将其与单元测试链接。随着我们修复缺陷并添加更多功能,我们可以慢慢引入单元测试。

但是,有人担心维护此方案(以及所有必需的 stub 函数)会变得非常麻烦,并且开发人员将停止维护单元测试。所以另一种方法是使用一个工具,自动为所有代码生成 stub ,并将文件与它链接起来。 (我们发现可以做到这一点的唯一工具是昂贵的商业产品)但是这种方法似乎要求在我们开始之前,我们所有的代码都更加模块化,因为只有外部调用可以被淘汰了。

就个人而言,我宁愿让开发人员考虑他们的外部依赖关系并智能地编写他们自己的 stub 。但是,对于一个 10,000 行的文件来说,这可能是为了消除所有依赖关系而难以承受的。可能很难说服开发人员他们需要为所有外部依赖项维护 stub ,但这是正确的方法吗? (我听到的另一个论点是子系统的维护者应该为他们的子系统维护 stub 。但我想知道“强制”开发人员编写他们自己的 stub 是否会导致更好的单元测试?)

#ifdefs 当然为问题增加了另一个维度。

我们查看了几个基于 C/C++ 的单元测试框架,其中有很多看起来不错的选项。但是我们还没有找到任何东西来缓解从“没有单元测试的毛球代码”到“可单元测试的代码”的过渡。

以下是我对其他经历过此问题的人的问题:

  • 什么是好的起点?我们是在朝着正确的方向前进,还是我们遗漏了一些明显的东西?
  • 哪些工具可能有助于过渡? (最好是免费/开源,因为我们现在的预算大约是“零”)

请注意,我们的构建环境是基于 Linux/UNIX 的,因此我们不能使用任何仅限 Windows 的工具。

最佳答案

we have not found anything to ease the transition from "hairball of code with no unit tests" to "unit-testable code".

多么可悲——没有奇迹般的解决方案——只是努力纠正多年积累的technical debt .

没有简单的过渡。你有一个大的、复杂的、严重的问题。

您只能分几步解决它。每一个微小的步骤都涉及以下内容。

  1. 选择一段绝对必要的离散代码。 (不要在垃圾的边缘蚕食。)选择一个重要的组件,并且——不知何故——可以从其余部分中剔除。虽然单个函数是理想的,但它可能是一组错综复杂的函数,也可能是一个完整的函数文件。可以从对可测试组件来说不太完美的东西开始。

  2. 弄清楚它应该做什么。弄清楚它的界面应该是什么。为此,您可能必须进行一些初始重构以使您的目标片段实际上是离散的。

  3. 编写一个“整体”集成测试——现在——或多或少地测试你发现的离散代码。在你尝试改变任何重要的事情之前先让这件事通过。

  4. 将代码重构为整洁、可测试的单元,这些单元比当前的毛球更有意义。您将不得不(目前)与您的整体集成测试保持一些向后兼容性。

  5. 为新单元编写单元测试。

  6. 一切都通过后,停用旧 API 并修复更改将破坏的内容。如有必要,返工原始集成测试;它测试旧的 API,你想测试新的 API。

迭代。

关于c++ - 您如何将单元测试引入大型的遗留 (C/C++) 代码库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/748503/

相关文章:

使用 ngxs/store @select 进行 Angular Testing 会给出错误 : "SelectFactory not connected to store!"

c++ - 使用 OpenGL 进行实时逐像素过滤的最佳方法?

C++:使用迭代器替换部分字符串不起作用

c - 为什么我会遇到段错误(strcmp 或 fgets)?

java - 使用正则表达式查找 C 风格注释 block (/* */) 但不是字符串内部的注释 block ?

java - 字段没有私有(private) setter - 单元测试遗留代码

c# - 如何在 .NET Core 中对 Startup.cs 进行单元测试

android - 如何在真实设备上调试 Android native 代码

c++ - 在 unordered_map 中,C2440 'type cast' : cannot convert . .. 当定义了 operator== 和 hash_value

c - 在结构中定义和使用 char 字符串