《C++代码整洁之道:C++17 可持续软件开发模式实践》 —2.5.12 测试替身
2.5.12 测试替身
单元测试应该只被称为“单元测试”,被测试单元在单元测试执行期间,与依赖系统完全无关,也就是说,被测试单元不依赖其他单元或外部系统。例如,虽然在系统集成测试的时候,数据库的测试不是必要的,但是这是集成测试的目的,所以禁止在实际单元测试期间访问数据库(如查询,参见2.5.9节“如何处理数据库的访问”)。因此,要测试的单元与其他模块或外部系统的依赖性应该被所谓的测试替身(Test Doubles)替换,测试替身也被称为伪对象(Fake Objects)或假模型(Mock-Ups)。
为了以一种优雅的方式使用测试替身,尽量达到被测试单元之间的松耦合(参见3.7节“松耦合原则”)。例如,抽象(如纯抽象类形式的接口)可以在访问单元测试不关心的合作者的时候被引入,如图2-4所示。
图2-4 通过接口很容易地用XMock替换X
假设你想开发一个应用程序,该应用程序使用外部的Web服务进行货币转换。在单元测试期间,不能正常使用外部服务,因为货币转换因子每秒都在发生变化。此外,通过互联网查询服务是比较慢的,很有可能失败,而且也不能模拟边界值的情况。因此,在单元测试期间,必须用测试替身替换实际货币转换服务。
首先,我们必须在代码中引入一个可变点,可以用一个测试替身替换与货币转换服务的通信模块,通常可以使用一个接口达到这个目的,该接口在C++中是一个仅包含纯虚成员函数的抽象类。
代码2-9 一个货币转换的抽象接口
通过Internet访问被封装在实现CurryNyCurror接口的类中的货币转换服务。
代码2-10 访问实际的货币转换服务的类
第二个实现测试目的的方法是:测试替身CurrencyConversionServiceMock。这个类的对象将返回一个预定义的转换因子,在单元测试的时候需要用到这个预定义的转换因子。此外,这个类的对象还提供了从外部设置转换因子的能力,例如,用于模拟边界情况。
代码2-11 测试替身
产品代码中,在使用货币转换服务的地方,现在用接口来访问货币转换服务。得益于这种抽象,客户端代码在运行时是完全透明的—无论是访问实际的货币转换服务还是货币转换服务的替身。
代码2-12 使用这个服务的类的头文件
在UserOfConversionService类的单元测试中,测试用例能够通过初始化构造函数把伪对象(mock object)传递给这个类的对象。另一方面,在软件正常运行的情况下,也可以通过构造函数把真实的服务传递给这个类的对象。这种技术称为依赖注入模式,在后面第9章“设计模式和习惯用法”会进行详细讨论。
代码2-13 通过UserOfConversionService的构造函数传递它使用的CurrencyConverter对象
- 点赞
- 收藏
- 关注作者
评论(0)