什么是mock测试,如何进行mock测试?

4747 1814 2023-07-04


本文介绍了什么是mock测试,如何进行mock测试?

什么是mock测试

1.png

Mock测试就是在测试活动中,对于某些不容易构造或者不容易获取的比较复杂的数据/场景,用一个虚拟的对象(Mock对象)来创建用于测试的测试方法。

image.png

2、为什么要进行Mock测试

Mock是为了解决不同的单元之间由于耦合而难于开发、测试的问题。所以,Mock既能出现在单元测试中,也会出现在集成测试、系统测试过程中。

Mock最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。

3、Mock适用场景

1、需要将当前被测单元和其依赖模块独立开来,构造一个独立的测试环境,不关注被测单元的依赖对象,只关注被测单元的功能逻辑。

2、被测单元依赖的模块尚未开发完成,而被测单元需要依赖模块的返回值进行后续处理。

3、前后端项目中,后端接口开发完成之前,接口联调

4、依赖的上游项目的接口尚未开发完成,需要接口联调测试

5、被测单元依赖的对象较难模拟或者构造比较复杂

如: 支付业务的异常条件很多,但是模拟这种异常条件很复杂或者无法模拟.

4、代码实例

新建测试工程

package com.echo.mockito;

public class demo {

    //新建一个测试方法

    public int add(int a,  int b){

        return a + b;

    }

}

构建mock测试方法

选中测试类,右键选中generate

2.png

点击test

3.png

点击ok后就会在test目录下生成对应的测试方法,和真实的目录是对应的

4.png

5、参数方法说明

@BeforeEach

用在测试前准备,测试前会构建很多的环境配置或者基础配置,都可以在这里设置。

@AfterEach

用于测试后设置。

@Mock

注解可以理解为对 mock 方法的一个替代,不会走真实的方法,模拟真实方法的行为。使用该注解时,要使用MockitoAnnotations.openMocks(this)  方法,让注解生效。

@Spy

1、被Spy的对象会走真实的方法,而mock对象不会,

2、spy方法的参数是对象实例,mock的参数是class。

@InjectMocks

用于将@Mock标记的模拟变量注入到测试类中。

MockitoAnnotations.openMocks(this)

开启mock,配合以上两个注解进行测试。一般放在@BeforeEach 中,在测试前开启,这样不用在每个方法中都的开启了。

Mockito.when(demo.add(1,2)).thenReturn(3):打桩

mock核心,可以设置要测试的方法的结果,这样就会忽略真实方法的执行结果,后续的测试都是基于打桩结果执行。

Mockito.when(demo.add(1,2)).thenThrow(new RuntimeException());

用于模拟异常。

Assertions.assertEquals(3,demo.add(1,2)):断言

测试的主要方式,结果基于此判断。(期望值,实际值)。

1、什么是Mock测试?

Mock 测试就是在测试过程中,对于某些不容易构造(如 HttpServletRequest 必须在Servlet 容器中才能构造出来)或者不容易获取的比较复杂的对象(如 JDBC 中的ResultSet 对象),用一个虚拟的对象(Mock 对象)来创建以便测试的测试方法。

2、为什么要进行Mock测试?

Mock是为了解决不同的单元之间由于耦合而难于开发、测试的问题。所以,Mock既能出现在单元测试中,也会出现在集成测试、系统测试过程中。Mock 最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。比如一段代码有这样的依赖:

当我们需要测试A类的时候,如果没有 Mock,则我们需要把整个依赖树都构建出来,而使用 Mock 的话就可以将结构分解开,像下面这样:

3、Mock对象适用场景

(1)需要将当前被测单元和其依赖模块独立开来,构造一个独立的测试环境,不关注被测单元的依赖对象,只关注被测单元的功能逻辑。

  —–比如被测代码中需要依赖第三方接口返回值进行逻辑处理,可能因为网络或者其他环境因素,调用第三方经常会中断或者失败,无法对被测单元进行测试,这个时候就可以使用mock技术来将被测单元和依赖模块独立开来,使得测试可以进行下去。

(2)被测单元依赖的模块尚未开发完成,而被测单元需要依赖模块的返回值进行后续处理。

1)前后端项目中,后端接口开发完成之前,接口联调;

2)依赖的上游项目的接口尚未开发完成,需要接口联调测试;

  —–比如service层的代码中,包含对Dao层的调用,但是,DAO层代码尚未实现

(3)被测单元依赖的对象较难模拟或者构造比较复杂。

  —–比如,支付宝支付的异常条件有很多,但是模拟这种异常条件很复杂或者无法模拟,比如,查询聚划算的订单结果,无法在测试环境进行模拟。

4、Mock测试的优势

(1) 团队可以并行工作

有了Mock,前后端人员只需要定义好接口文档就可以开始并行工作,互不影响,只在最后的联调阶段往来密切;后端与后端之间如果有接口耦合,也同样能被Mock解决;测试过程中如果遇到依赖接口没有准备好,同样可以借助Mock;不会出现一个团队等待另一个团队的情况。这样的话,开发自测阶段就可以及早开展,从而发现缺陷的时机也提前了,有利于整个产品质量以及进度的保证。

(2)开启TDD模式,即测试驱动开发

单元测试是TDD实现的基石,而TDD经常会碰到协同模块尚未开发完成的情况,但是有了mock,这些一切都不是问题。当接口定义好后,测试人员就可以创建一个Mock,把接口添加到自动化测试环境,提前创建测试。

(3)可以模拟那些无法访问的资源

比如说,你需要调用一个“墙”外的资源来方便自己调试,就可以自己Mock一个。

(4)隔离系统

假如我们需要调用一个post请求,为了获得某个响应,来看当前系统是否能正确处理返回的“响应”,但是这个post请求会造成数据库中数据的污染,那么就可以充分利用Mock,构造一个虚拟的post请求,我们给他指定返回就好了。

(5)可以用来演示

假如我们需要创建一个演示程序,并且做了简单的UI,那么在完全没有开发后端服务的情况下,也可以进行演示。说到演示了,假如你已经做好了一个系统,并且需要给客户进行演示,但是里面有些真实数据并不想让用户看到,那么同样,你可以用Mock接口把这些敏感信息接口全部替换。

(6)测试覆盖度

假如有一个接口,有100个不同类型的返回,我们需要测试它在不同返回下,系统是否能够正常响应,但是有些返回在正常情况下基本不会发生,比如,我们需要测试在当接口发生500错误的时候,app是否崩溃,别告诉我你一定要给服务端代码做些手脚让他返回500 。而使用mock,这一切就都好办了,想要什么返回就模拟什么返回,不用再担心我的测试覆盖度了!

5、Mock测试存在的问题

使用Mock测试有时可以提高团队的开发效率,但当B、C都开发完成代码后,这时应该把E2E测试代码从使用Mock测试改为调用真实的模块,以避免出现模块之间集成部分漏测的问题。这里说mock存在的问题,主要是让开发和测试不要过分的依赖/相信mock接口。

使用mock时,切记的几点:

1)测试人员不应该被覆盖率高的E2E自动化测试所迷惑,覆盖率高不代表没有问题。尤其在接手新项目中,需要查看E2E测试中有没有使用Mock测试,进一步去判断这些地方使用Mock测试是否合理,这些Mock测试是否应该换成真实模块间的调用和集成。

2)当把mock接口换成实际接口后,测试/开发也必须把之前的测试重新做一遍。

ps: 当你使用mock接口来提高效率,请注意:你的工作量其实是比 直接只用实际接口 多了 一倍的。如果测试时,偷懒,替换成实际接口后,只是简单测试,那么 当实际接口和mock预期接口有差异时,故障便和你相遇了。

建议: mock接口只能主流程联调/ 异常返回测试,不要过分依赖mock接口进行测试。

3)测试完毕,上线前,请一定确保 为了mock而做的相关代码/配置文件的修改,已经完全恢复了。

建议:上线checklist中条条列出,并上线前review

初识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测试?

国内(北京、上海、广州、深圳、成都、重庆、杭州、西安、武汉、苏州、郑州、南京、天津、长沙、东莞、宁波、佛山、合肥、青岛)API测试平台软件分析、比较及推荐。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:浅谈静态变量、成员变量、局部变量三者的区别
下一篇:PHP抓取HTTPS内容和错误处理的方法
相关文章

 发表评论

暂时没有评论,来抢沙发吧~