创建可测试的代码

时间:2009-10-27 18:04:44

标签: c++ unit-testing refactoring testability

我有一个文件 - 在一个大型遗留代码库中 - 包含访问数据库的方法。 没有使用类,只有带有方法声明的头文件和带有实现的源文件。

我希望覆盖这些方法以消除单元测试期间的数据库访问。

我想到了以下几个选项:

  1. 将文件转换为类并覆盖方法 这里的主要负面因素是它会在整个代码库中产生很多变化 虽然它确实改善了代码,但并不理想......
  2. #ifdef PRODUCTION_CODE包装整个源文件并创建一个包含存根的新源文件,并用相反的方式包装它,即使整个事件编译依赖。这里的问题是,在执行回归测试的构建系统中,我必须编译两次,一次是为了创建应用程序并进行回归测试,还有一段时间来创建单元测试可执行文件。

任何推荐的方法吗?

4 个答案:

答案 0 :(得分:1)

如何获取现有函数,将代码移入新类并从现有函数中调用新方法,然后在测试期间覆盖此类?

像这样:

 static DBAccessClass dac = new DBAccessClass ();

 void origFunction() { dac.origFunction(); }

在测试中:

 dac = new DBAccessMockup();

答案 1 :(得分:1)

您可以尝试在链接器级别覆盖。有两个不同的.cpp文件,用于实现描述数据库接口的标题中的功能 - 一个调用真实数据库,一个调用伪接口。链接单元测试时,将其替换为另一个(GNU中的目标特定变量可能有帮助)。

答案 2 :(得分:0)

您可能还想看看Michael Feathers的书Working Effectively with Legacy Code。他不仅讨论了这些类型的问题,而且还包括C ++中的大量例子(除了Java,C和C#之外)。 Feathers也是CppUnit的原创者。

答案 3 :(得分:0)

  
      
  1. 将文件转换为类并覆盖方法。 [...]
  2.   
  3. 用#ifdef [...]
  4. 包装整个源文件   

如果可能,请使用1,因为您将有一个集中的方式来引用数据库代码(类指针而不是X函数)。这意味着模块化,易于替换实现(使用存根或其他数据库后端)和更多封装的代码。

如果选择2,请考虑替换函数的实现。也就是说,在原始函数内部,使用测试代码(基于if)。

如果在测试环境中运行,您测试的代码是完全不可知的,性能损失可以忽略不计(在大多数情况下if(booleanFlagHere)成本可以忽略不计)并且您根本不需要修改测试代码)。