干货!用大白话告诉你什么是Mock测试,mock测试
本文讲述了干货!用大白话告诉你什么是Mock测试,mock测试。
初识mock
作为一个动词,mock是模拟、模仿的意思;作为一个名词,mock是能够模仿真实对象行为的模拟对象。
在软件测试中,mock所模拟的对象是什么呢?
它一定不是我们所测试的对象,而是 SUT 的依赖(dependency)。换句话说,mock 的作用是模拟 SUT 依赖对象的行为。
测试的对象一般称之为SUT(Software Under Test)
文字不好理解,我们画个图,如下图所示,被测试对象是 A,A 依赖的是B,B 依赖的是 C。而我们要 mock 的是 B 的行为。图中 A 就是 SUT。
为什么需要模拟 B 的行为呢?
(1)提高 A 的测试覆盖率。A 依赖 B,本质上依赖的是 B 的返回结果,也就是说 B 的返回结果会影响 A 的行为。通过 mock B 我们可以构造各种正常和异常的来自 B 的返回结果,从而更充分测试 A 的行为。(2)避免 B 的因素从而对 A 产生影响。依赖真实的 B 去测试 A 可能有很多问题:B 的开发没有完成时无法测试 A;B 有阻塞性bug 时无法测试 A;B 的依赖 C 有阻塞性 bug 时无法测试 A;(3)提高 A 的测试效率。B 的真实行为可能很慢,而 B 的模拟行为是非常快的,因此可以加快 A 的测试执行速度。mock 种族
常见的 mock 类型如下图所示:
从下往上依次解释一下:
(1)方法级别 mock:mock 的对象是一个函数调用,例如获取系统环境变量。(2)类级别 mock:mock 的对象是一个类,例如一个 HTTP server。(3)接口级别 mock:mock 的对象是一个 API 接口。(4)服务级别 mock:mock 的对象是整个服务。比如前端工程师自测试时,可以讲后端整个服务都 mock 掉,这其实等同于将后端的所有接口都 mock。接口mock注入的五种方式
在使用 mock 进行接口测试时,一般要做两件事情,即打桩和调桩。
其实打桩就是创建mock 桩,指定 API 请求内容及其映射的 mock 响应内容;所谓调桩就是被测服务来请求 mock 桩并接收 mock 响应。
事实上,在打桩和调桩之间还隐藏着一件不显山露水、但是及其重要的事情,那就是 mock 桩的注入(mock injection)。
什么是 mock 注入?
mock 的本质就是用模拟桩来替换真实的依赖。所谓 mock 桩注入就是阻断被测服务与真实服务之间的链路,建立被测服务与 mock 之间的链路过程。
如何注入 mock?
总的来说 mock 桩的注入方式与架构、被测服务的架构等因素相关,在实际中常见的 mock 桩注入方式包括但不限于以下五种。
(1)API 请求构造
在 mock 接口中被测服务是 API 的请求方,即客户端;依赖服务是 API 的响应方,即服务端。根据 mock 工作的位置,mock 可以分为客户端 mock 和服务端 mock。
客户端 mock:mock 在被测服务内部工作,直接拦截被测服务的 API 请求方法(比如 HTTP Client方法),在被测服务调用 API 请求方法时,直接从方法内部返回预定义的 mock 响应。
服务端 mock:mock 在被测服务外部工作,作为 HTTP 服务器接收被测服务发送的 API 请求,并返回预定义的 mock 响应。
客户端 mock 的注入其实就是改造被测服务的 API 请求方法,即在 API 请求方法中加入 mock 处理逻辑。当满足某些条件时执行 mock 分支,不满足时执行真实分支。
可以通过两种方式实现,一种是直接改造源代码,另一种是利用字节码增强技术对字节码进行改造(Java 语言)。
API 请求改造这种注入方式适用于客户端 mock,其优势性能极好,其不足是实现成本较高。
(2)本地配置
对于服务端 mock,打桩之后会生成唯一的 mock 桩地址。被测服务要想调用这个桩需要知道桩地址,如何让被测服务知道桩地址呢?一种最直接的方法就是被测服务提供一个依赖服务地址配置项,在需要使用 mock 时将依赖服务地址修改成 mock 地址。
本地配置的优势是实现简单,不足之处是修改配置项需要重启被测服务,在需要进行 mock 服务与真实服务切换时不方便。
(3)配置中心
在服务端 mock 中,为了避免修改依赖服务地址配置项导致被测服务重启,可以采用配置中心(如 Spring Cloud Config Server)存储和管理依赖服务地址配置,或者使用注册中心(如 Spring Cloud Eureka)记录服务与服务地址的映射关系。
使用配置或者注册中心时,mock 注入的方法是修改配置中心,将依赖服务地址改成 mock 地址。这种注入方法不需要重启被测服务,但是从配置改变到配置生效可以存在一定的延时。
(4)反向代理
在微服务架构下,被测服务与依赖服务之间可能不是直连的,而是经过了一层反向代理,例如 API 网关。在这种情况下,被测服务是通过调用 API 网关来间接调用依赖服务的接口。
在 API 网关模式下,mock 注入的具体做法就是修改 API 网关配置,将依赖服务 API 网关接口绑定的地址改成 mock 地址。
这种注入的优势是对被测服务无侵入,并且实现更细粒度(接口级)的 mock。当然,根据 API 网关的实现不同,仍然可能存在一定的时延。亚马逊 AWS 的 API 网关就是采用这种方式进行 mock。
(5)前向代理
服务端 mock 除了作为 HTTP 服务器,还可以兼备 HTTP 代理的功能,这种架构又叫做 mock 代理,例如 mock server proxy。对于 mock 代理来说,它不仅能够返回 mock 响应,而且能够在需要的时候将 API 请求转发给依赖服务,并将依赖服务的真实响应返回给被测服务。
使用前向代理模式,mock 注入的方式是将被测服务的依赖地址或网络代理修改为 mock 地址,这种注入方法需要重启被测服务,其优势是能够实现细粒度的 mock,并且能够根据录制的真实响应自动生成 mock。
五种注入方式对比
一张表格总结一下
不可忽视的mock两大功能
关于 mock,经常容易被误解的是:认为 mock 只是模拟返回的结果而已。
实际上 mock 还可以提供两大功能:(1)记录真实的调用信息;(2)生成模拟的返回信息;
对于测试用例来说,我们不仅关心 mock 是否返回了期望的结果,还需要关心 SUT 是否以期望的方式调用了 mock 对象。
如果 SUT 没有以期望的方式调用,比如:没有传参或者参数不对,那么 SUT 就存在问题。
mock 需要详细记录来自SUT 的调用信息,并提供给用例来校验。比如 Java mockito 就提供了此类校验功能:
List<String> mockedList = mock(MyList.class);mockedList.size();// 校验 size 函数调用且只调用了1次verify(mockedList, times(1)).size();常用 mock 工具
单元测试级别
这个级别的mock工具有easymock、jMock、Mockito、Unitils Mock、PowerMock、JMockit等,关于各自优劣势大家可以上网查询。
接口测试级别
接口级别的mock工具完成的主要功能是对一个用户的请求,模拟server返回一个接口的响应数据。常用的有:
WiremockMockserverMocoMock.jsRAPmock 不是银弹
说了这么多 mock 的好处,实际上 mock 也有很多不足,比如:
(1)mock 可能导致问题遗漏。mock 的模拟行为与真实行为可能存在 GAP,导致基于 mock 的测试虽然通过了,但是基于真实对象的测试却失败了,这意味着问题被遗漏了。mock 很难模拟所有的真实情况。(2)mock 带来较高的维护成本。基于 mock 的测试用例结构比较复杂,实现和维护都不容易,后期被测代码有变动时需要适配 mock 代码。简单一句话:mock 不是银弹。
有态度的总结
mock 不是银弹,mock 是有利有弊的,一张图总结一下:
说了这么多,在工作中如何正确使用 mock 呢?这里提两点建议,敲黑板啦。
(1)不要过度使用 mock。测试用例中掌握好使用 mock 的度。在涉及网络访问、数据库读写、操作系统交互等系统级调用,优先使用 mock。
(2)不要过度依赖基于 mock 的测试结果。基于 mock 的测试无论多么充分,这都不能保证不出现问题的遗漏。一个完整的测试策略一定是由基于 mock 的测试和基于非 mock 的测试共同组成的,二者相辅相成缺一不可。
Mock对象适用场景:
(1)需要将当前被测单元和其依赖模块独立开来,构造一个独立的测试环境,不关注被测单元的依赖对象,只关注被测单元的功能逻辑。
-----比如被测代码中需要依赖第三方接口返回值进行逻辑处理,可能因为网络或者其他环境因素,调用第三方经常会中断或者失败,
无法对被测单元进行测试,这个时候就可以使用mock技术来将被测单元和依赖模块独立开来,使得测试可以进行下去。
(2)被测单元依赖的模块尚未开发完成,而被测单元需要依赖模块的返回值进行后续处理。
1)前后端项目中,后端接口开发完成之前,接口联调;
2)依赖的上游项目的接口尚未开发完成,需要接口联调测试;
3)被测单元依赖的对象较难模拟或者构造比较复杂。
-----比如,支付宝支付的异常条件有很多,但是模拟这种异常条件很复杂或者无法模拟,
比如,查询聚划算的订单结果,无法在测试环境进行模拟。
Mock测试的优势:
(1) 团队可以并行工作
(2)开启TDD模式,即测试驱动开发
(3)可以模拟那些无法访问的资源(外网资源等)
(4)隔离系统
Mock测试方式:(相关工具或者脚本)
1. Mock Server-Moco
这是一个jar包,只要执行该jar包,指定配置文件,就可开启一个http服务器提供服务,并且修改配置文件后也无需重启服务,支持动态加载。我使用的是moco-runner-0.10.2-standalone.jar,运行方式如下:
```java -jar moco-runner-0.10.2-standalone.jar start -p 8080 -c XXX.json```
moco不足:
Moco的使用很简单,配置也很方便,目前更是提供了http、rest、socket服务。但是也仅仅是能stub出接口,模拟出简单的场景。如果接收到请求后需要做一些处理,如需查询数据库、进行运算、或者一些复杂的操作,就无能为力了。
2. fiddler(Fiddler的 AutoResponder)
fiddler大家都很熟了,在windows环境可以随便自定义返回内容,但一个很大的缺点是,它不跨平台,
而我们平时的很多场景下,是需要在Linux下进行mock的。
3、还有一些其他mock工具,大多都是通过编写js代码或者python、java等代码来达到mock目的
也可以通过编写C#来返回请求(根据会的C#远程接口工具)
4、Apifox-超强接口管理神器
Apifox 是 API 文档、调试、Mock、测试一体化协作平台,定位Postman + Swagger + Mock + JMeter
。通过一套系统、一份数据,解决多个系统之间的数据同步问题。只要定义好 API 文档,API 调试、API 数据 Mock、API 自动化测试就可以直接使用,无需再次定义;API 文档和 API 开发调试使用同一个工具,API 调试完成后即可保证和 API 文档定义完全一致。高效、及时、准确!
上文是小编为大家整理的干货!用大白话告诉你什么是Mock测试,mock测试。
国内(北京、上海、广州、深圳、成都、重庆、杭州、西安、武汉、苏州、郑州、南京、天津、长沙、东莞、宁波、佛山、合肥、青岛)推荐eolink。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~