当前位置: 首页 > 科技观察

干货!用大白话告诉你什么是Mock测试

时间:2023-03-15 23:33:09 科技观察

干货!通俗易懂告诉你什么是Mocktest转载请联系LoveSmile的架构师公众号。作为动词,mock有模拟、模仿的意思;作为名词,mock是一种模拟对象,可以模仿真实对象的行为。在软件测试中,mock的模拟对象是什么?一定不是我们测试的对象,而是SUT的依赖。也就是说,mock的作用是模拟SUT依赖对象的行为。测试的对象一般称为SUT(SoftwareUnderTest)。文字不容易看懂。我们画个图,如下图,被测对象是A,A依赖B,B依赖C。而我们要mock的是B的行为,图中的A就是SUT。为什么需要模拟B的行为?(1)提高A的测试覆盖率。A依赖B,本质上依赖于B的返回结果,也就是说B的返回结果会影响A的行为。通过mockB,我们可以构造各种正常和B的异常返回结果,从而更全面地检验A的行为。(2)避免B的因素影响A。依靠真实的B来检验A可能会出现很多问题:B未完成;B有阻塞性bug时无法测试A;当B的依赖C有阻塞性bug时,A无法测试;(3)提高A测试效率。B的真实行为可能很慢,而B的模拟行为非常快,从而加快了A的测试执行速度。mockrace常见的mock类型如下图所示:从下到上解释:(1)方法级mock:mock的对象是函数调用,比如获取系统环境变量。(2)类级mock:mock的对象是类,比如HTTP服务器。(3)接口级mock:mock对象是一个API接口。(4)服务级mock:mock的对象是整个服务。比如前端工程师在自测的时候,可以说mock了整个后端服务,其实相当于mock了后端的所有接口。接口mock注入的五种方法在使用mock进行接口测试时,一般要做两件事,即打桩和调桩。piling其实就是创建mockpile,指定API请求的内容和映射到的mock响应内容;所谓打桩,就是被测服务请求模拟桩,接收模拟响应。其实在打桩和调桩之间隐藏着一个不起眼却又极其重要的东西,那就是mockinjection。什么是模拟注入?mock的本质是用mockstub代替真正的依赖。所谓mockstub注入就是阻断被测服务与真实服务之间的链接,建立被测服务与mock之间的链接的过程。如何注入模拟?一般来说,mockpile的注入方式和被测服务的架构、架构等因素有关。实践中常见的模拟桩注浆方法包括但不限于以下五种。(1)API请求构造在mock接口中,被测服务是API的请求者,即客户端;依赖服务是API的响应者,即服务器。根据mock发挥作用的地方,mock可以分为客户端mock和服务端mock。Clientmock:mock工作在被测服务内部,直接拦截被测服务的API请求方法(如HTTPClient方法),当被测服务调用API时,直接从方法内部返回一个预定义的mock响应请求方法。Server-sidemock:mock工作在被测服务之外,充当HTTP服务器,接收被测服务发送的API请求,返回预定义的mock响应。clientmock的注入实际上是对被测服务的API请求方法进行改造,即在API请求方法中加入mock处理逻辑。满足一定条件时执行mock分支,不满足时执行real分支。可以通过两种方式实现,一种是直接对源代码进行改造,另一种是利用字节码增强技术对字节码进行改造(Java语言)。API请求修改的注入方式适用于client-sidemocks。它的优点是性能优异,缺点是实现成本比较高。(2)本地配置对于服务器mock,打桩后会生成一个唯一的mock堆地址。如果被测服务想要调用这个存根,它需要知道存根地址。如何让被测服务知道存根地址?一种最直接的方法就是被测服务提供一个依赖的服务地址配置项,在使用mock时将依赖的服务地址改成mock地址。本地配置的优点是易于实现。缺点是修改配置项需要重启被测服务,需要在模拟服务和真实服务之间切换时不方便。(3)配置中心在服务端mock中。为了避免依赖服务地址配置项被修改导致被测服务重启,可以使用配置中心(如SpringCloudConfigServer)存储和管理依赖服务地址配置,或者注册中心(如SpringCloudConfigServer)如SpringCloudEureka)记录了服务与服务地址的映射关系。在使用配置或注册中心时,mock注入方式是修改配置中心,将依赖的服务地址改为mock地址。这种注入方式不需要重启被测服务,但是从配置更改到配置生效可能会有一定的延迟。(4)反向代理在微服务架构下,被测服务和依赖服务可能不是直连的,而是通过一层反向代理,比如API网关。在这种情况下,被测服务通过调用API网关间接调用依赖服务的接口。API网关模式下,mock注入的具体方法是修改API网关配置,将依赖服务的API网关接口绑定的地址改为mock地址。这种注入的好处是对被测服务没有侵入,实现了更细粒度(接口级)的mock。当然,根据API网关的实现情况,可能还是会有一定的延迟。AmazonAWS的APIGateway就是用这个方法来mock的。(5)正向代理服务器mock除了作为HTTP服务器,还可以作为HTTP代理。这种架构也称为mockproxy,比如mockserverproxy。对于mock代理,它不仅可以返回mock响应,还可以在需要时将API请求转发给依赖服务,将依赖服务的真实响应返回给被测服务。使用正向代理模式,mock注入的方式是将被测服务的依赖地址或网络代理修改为mock地址。这种注入方式需要重启被测服务。它的优点是可以实现细粒度的mocking,并且可以自动生成mock的真实响应。五种注入方式对比一张表总结了mock不可忽视的两大功能关于mock,很多人误以为mock只是模拟返回的结果。其实mock还可以提供两大功能:(1)记录真实的调用信息;(2)生成模拟返回信息;对于测试用例,我们不仅关心mock是否返回预期结果,还需要关心SUT是否按预期调用了mock对象。如果没有以预期的方式调用SUT,例如:没有传递参数或参数错误,则说明SUT有问题。mock需要详细记录来自SUT的调用信息,提供给用例进行验证。例如Javamockito提供了这种验证功能:ListmockedList=mock(MyList.class);mockedList.size();//验证size函数调用只调用verify(mockedList,times(1).size();常用的mock工具单元测试级别mock工具在这个级别有easymock,jMock,Mockito,UnitilsMock、PowerMock、JMockit等,大家可以上网查一下各自的优缺点接口测试级别接口级别的mock工具的主要作用是模拟服务器返回某个接口对用户请求的响应数据。常用的有:WiremockMockserverMocoMock.jsRAPmockisnotasilverbullet说了这么多mocking的好处,其实mocking也有很多缺点,比如:(1)mocking可能会导致问题被遗漏。可能有mock的模拟行为和真实行为之间的差距,导致基于mock的测试通过,但是基于真实对象的测试失败,这意味着问题被遗漏了。mock很难模拟所有真实情况。(2)模拟带来更高的维护成本。基于mock的测试用例结构相对复杂,不易实现和维护。后面被测代码发生变化时,需要对mock代码进行适配。一句话:嘲笑不是灵丹妙药。有态度的总结Mock不是灵丹妙药。模拟有优点也有缺点。用一张图总结一下:说了这么多,工作中如何正确使用mock?这里有两个建议,敲黑板。(1)不要过度使用模拟。掌握在测试用例中使用mock的程度。对于涉及网络访问、数据库读写、操作系统交互的系统级调用,首选mock。(2)不要过分依赖基于模拟的测试结果。无论模拟测试多么充分,都不能保证不会漏掉问题。一个完整的测试策略必须由mock-based测试和non-mock-based测试组成,两者相辅相成,缺一不可。