简介
一说到测试替身,我们总会不由自主的想到mock,我们在上一章简单提了一下,测试替身是 桩(Stub) 伪造对象(fake)测试间谍(spy) 模拟对象(mock)的总称。而使用测试替身的根本目的是使用替身替换一个模块的真实协作者,以期隔离被测试对象。
我们说,引入测试替身的根本原因就是:将测试代码和周围隔离开。
下面我们先分别看一下几种类型的测试替身:
测试替身的类型1:桩
桩(Stub) 测试桩是单元测试中常用的技术,我们经常能看到所谓的“打桩”。桩是指用最简单的代码来替代真实实现。
换句话说,如果A依赖了B的一个很复杂的方法的返回值,而我们要测试A,这个返回值是多少我们并不太关心,就可以写出一个B1(桩函数),只是用了B的桩而不是B,这样就可以完成测试,这里我们注意,使用桩可以达到下面三个效果:
- 隔离。如果A依赖了B,B依赖了C D,通过对于B打桩,就切断了A和C D的联系
- 补齐。如果A依赖了B,而B是其他语言写的,或者必须依赖某运行环境,就可以对B打桩替代B,让A可以运行下去
- 控制。如果A依赖B的某个返回值,通过对B打桩,直接设定返回值可以让A运行下去。
我们看一个桩的例子:假设我们要测试的类A需要向服务器写入日志,写日志需要调用继承自ILogger的实现的Log方法,而写入日志需要服务器的支持,那我们想要测试A,就可以对于测试的对象“打桩”。
public class LoggerStub : ILogger
{
public LogLevel GetLevel()
{
return LogLevel.WRAN;
}
public void Log(LogLevel level, string message)
{
}
}
如上面的代码,LoggerStub就是一个测试桩,他是ILogger的最简单实现,既不调用服务器打印日志,也不做任何事情,仅仅是为了A的测试而存在,当然这适用于要测试A而不关心打印什么日志的情况。
测试替身的类型2:伪造对象
伪造对象是真实协作者的简单版本,它看起来像鸭子,叫起来像鸭子,却不是鸭子本身。
我们举个例子说,如果我们的数据存储在一个大型的数据库中,数据库给我们提供了API,但是这个数据库本身需要部署环境,需要有网络&