【问题标题】:Removing dependencies when unit testing procedural code单元测试过程代码时删除依赖项
【发布时间】:2009-02-24 02:36:24
【问题描述】:

在具有继承和虚函数的面向对象语言中,从单元测试代码中删除依赖项(例如数据库、API 调用等)可以简单到将这些依赖项封装在它们自己的方法中,然后在一个测试类继承自要测试的类。

但是,我在尝试对过程代码(特别是 C)执行类似操作时遇到了问题。如果没有继承,我就无法覆盖这些调用,那么在对过程代码进行单元测试时,如何提供类似的依赖删除?

一种选择是提供对这些依赖项的调用的替代方法,并用#ifdefs 包围它们,但理想的方法是将单元测试应用于与最终构建相同的代码。这可能吗?

【问题讨论】:

  • 我不明白你的问题。 C++一种具有继承和虚函数的面向对象语言。
  • C++ 可以以类似 C 的形式在程序上编写。这可能并不理想,但可以做到。我将把问题更新为只说“C”以避免混淆,因为大概适用于 C 的任何内容也将适用。

标签: c unit-testing


【解决方案1】:

获取Working Effectively with Legacy Code 并阅读标题为“我的应用程序是所有 API 调用”的章节。

基本上,Feathers 描述了两个选项:

“链接器接缝”:您可以为您尝试存根的 API 调用编译不同的实现集,而无需更改代码 - 基本上更改 makefile/.sln 以在函数的不同实现中编译.

如果这不起作用,他谈到“皮肤和包装”,您基本上将所有 API 函数移动到一个抽象基类中,创建两个派生类 - 一个生产和一个单元测试实现,并将调用转发到适当的方法 - 然后使用依赖注入来传递适当的函数集。

【讨论】:

  • “皮肤和包装”是否不适用于程序/非 OO 代码?
  • 我绝对赞成购买这本书。教育自己如何解决(和摆脱)这种情况是您能做的最好的事情。现在,我们团队中的每个人都拥有这本书的副本,它是我们认为必不可少的两本书之一。
  • “skin and wrap”可以通过创建带有#ifdefs的包装器来模拟生产或单元测试行为。
【解决方案2】:

条件编译可以,我之前自己做过。不过需要遵守纪律,因为说“那一点太难测试”然后不去测试会变得很诱人。

在我看来,另一种选择是构建这些库的特殊测试版本,其中包含您的 DB/API 调用(它们在库中,不是吗?)。测试版本可以维护相同的接口(显然是一个手动过程,因为您没有要继承的对象/接口),但会调用您的单元测试框架并可以通过您的单元测试框架进行查询。我为创建 FitNesse 版本的库做了类似的事情,我认为它没有理由不能用于单元测试。

缺点是每个被测对象都需要一个单独的可执行文件和编译器,但取决于您的测试框架,无论如何可能都是这种情况。

祝你好运!

【讨论】:

    【解决方案3】:

    我经常遇到这个问题,这是我在编写/维护测试套件方面落后的最大原因之一。在某些情况下,条件编译会有所帮助,但并非总是如此。

    例如,如果套件应该围绕较低级别的接口测试包装器以与虚拟机管理程序通信,则您需要在虚拟机管理程序下测试套件。或者编写一堆聪明的宏/内联函数来“伪造”虚拟机管理程序实际上根本不测试任何东西。

    在使用旧版 dbms API 或典型的 acme 小部件 API 时,这样做会更容易一些。

    对于旧版测试,我强烈建议从 ccan 下载 Tap(测试任何协议)并隔离这些测试。

    通常,我 80% 的测试都必须像这样包装,而且维护起来非常乏味且令人沮丧。希望你只有几个怪人要对付。

    除非有人写了一些神奇的魔杖从 cmets 中提取测试条件和参数,否则你会被困在同一张纸上。

    祝你好运,我真的很同情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-04
      • 2014-07-01
      • 2014-10-10
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多