在具有继承和虚函数的面向对象语言中,从单元测试代码中删除依赖项(例如数据库,API调用等)可以简单到将这些依赖项封装在自己的方法中,然后覆盖这些方法中的那些依赖项。测试类继承自要测试的类。
然而,当尝试为程序代码(特别是C)做类似的事情时,我遇到了一个问题。没有继承我不能覆盖那些调用,那么在单元测试过程代码时如何提供类似的依赖删除呢?
一种选择是提供对这些依赖项的调用的替代方法,并用#ifdef
包围它们,但理想的方法是将单元测试应用于与进入最终构建时相同的代码。这可能吗?
答案 0 :(得分:7)
获取Working Effectively with Legacy Code并阅读标题为“我的应用程序是所有API调用”的章节。
基本上,Feathers描述了两个选项:
“链接器接缝”:您可以在不需要更改代码的情况下为您尝试存根的API调用编译不同的实现集 - 基本上更改makefile / .sln以在函数的不同实现中进行编译
如果这不起作用,他会谈到“皮肤和包装”,你基本上将所有API函数移动到一个抽象基类中,创建两个派生类 - 一个生产和一个单元测试实现,转发调用适当的方法 - 然后使用依赖注入来传递适当的函数集。
答案 1 :(得分:0)
条件编译可行,我以前自己做过。尽管有纪律,因为它可能很容易说“那一点太难以测试”,然后就是不测试它。
我认为另一个选择是构建包含DB / API调用的这些库的特殊测试版本(它们在库中,不是吗?)。测试版本可以维护相同的界面(显然是一个手动过程,因为你没有继承的对象/接口),但是会调用你的单元测试框架并通过你的单元测试框架查询。我为创建FitNesse版本的库做了类似的事情,我认为没有理由不能用于单元测试。
缺点是你需要为每个被测对象提供一个单独的可执行文件和编译,但是根据你的测试框架可能就是这种情况。
祝你好运!答案 2 :(得分:0)
我经常面对这种情况,这是我在编写/维护测试套件方面非常落后的最大原因之一。在某些情况下,条件编译会有所帮助,但并非总是如此。
例如,如果套件应该测试较低级别接口的包装器以与虚拟机管理程序通信,则需要在虚拟机管理程序下测试套件..或者将一堆聪明的宏/内联函数写入'伪造'管理程序,实际上根本没有测试任何东西。
使用旧版dbms API或典型的acme小部件API时,它更容易实现。
对于旧版测试,我强烈建议从ccan下载点按(测试任何协议)并保持这些测试的隔离。
通常,80%的测试必须像这样包装,并且非常乏味且难以维护。希望你只有一些奇怪的东西可以应对。
在有人写一些魔杖从理智中提取测试条件和参数之前,你会被困在同一张飞纸上。
祝你好运,我真的很同情。