什么是 Mock?
作为动词,Mock 是模拟、模仿的意思。
作为名词,Mock 是能够模仿真实对象行为的模拟对象。
那么,在软件测试中,Mock 所模拟的对象是什么呢?
模拟的是 SUT(System Under Test:被测系统) 的依赖,而不是其本身。
比如,我要测试 A,但 A 依赖 B,要模拟的对象就是 B。
为什么要模拟 B 呢?
提高 A 的测试覆盖率:通过 Mock 模拟 B 返回的正常和异常的结果,使用 A 的测试更充分。
避免 B 的因素对 A 产生影响:当 B 因各种原因无法正常使用时,导致 A 无法测试。
提高 A 的测试效率:B 的真实行为可能很慢,但模拟可以很快。
Mock 的两大功能:
记录真实的调用信息
生成模拟的返回信息
使用 Mock 的问题是什么?
可能导致问题遗漏:毕竟是模拟的,是理想可预见的情况,真实的情况可能更复杂。
可能导致维护成本变高:接口变更 Mock 用例要跟着改,改错和漏改都可能出问题。
常见的 Mock 类型:
方法级别:Mock的对象是一个函数调用,例如:获取系统环境变量。
类级别:Mock 的对象是一个类,例如:一个 HTTP server。
接口级别:Mock 的对象是一个 API 接口。
服务级别:Mock 的对象是整个服务。
使用 Mock 做接口测试时,一般分二步:
1.打桩:创建 Mock 桩,指定 API 请求内容及其映射的响应内容。
2. 调桩:被测服务来请求 Mock 桩并接收 Mock 响应。
在这二步之间还有一个 Mock 桩的注入,啥是 Mock 注入?
Mock 的本质就是用模拟桩来替换真实的依赖。所谓Mock 桩注入就是阻断被测服务与真实服务之间的链路,建立被测服务与 Mock 之间的链路过程。
如下图所示:
如何注入 Mock?
常见的方式包括但不限于以下五种:
API 请求构造
客户端 Mock:在被测服务内部工作,直接拦截被测服务的 API 请求方法,直接从方法内部返回预定义的 Mock 响应。
服务端 Mock:在被测服务外部工作,作为 HTTP 服务器接收被测服务发送的 API 请求,并返回预定义的 Mock 响应。
本地配置:
对于服务端 Mock,打桩之后会生成唯一的 Mock 桩地址,被测服务提供一个依赖服务地址配置项,在需要使用 Mock 时将依赖服务地址修改成 Mock 地址。
配置中心
对于服务端 Mock,为了避免修改依赖服务地址配置项导致被测服务重启,可以采用配置中心存储和管理依赖服务地址配置,或者使用注册中心记录服务与服务地址的映射关系。
反向代理
在微服务架构下,被测服务与依赖服务之间可能不是直连的,而是经过了一层反向代理,例如 API 网关。在这种情况下,被测服务是通过调用 API 网关来间接调用依赖服务的接口。
前向代理
服务端 Mock 除了作为 HTTP 服务器,还可以兼备 HTTP 代理的功能,这种架构又叫做 Mock 代理。
对比:
常用 Mock 工具:
单元测试级别:
easymock、jMock、Mockito、Unitils Mock、PowerMock、JMockit..
接口测试级别
Wiremock、Mockserver、Moco、Mock.js、RAP...