您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
一文教会你mock(Mockito和PowerMock双剑合璧)
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
一文教会你mock(Mockito和PowerMock双剑合璧)
自猿其说Tech
2021-08-12
IP归属:未知
20240浏览
敏捷
计算机编程
### 1.什么是Mock ![](//img1.jcloudcs.com/developer.jdcloud.com/d9ad45ef-c26b-4032-b2e3-05d7417ad26520210812114505.png) Mock有模仿、伪造的含义。Mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。mock工具使用范畴: - 真实对象具有不确定的行为,产生不可预测的效果。 - 真实对象很难被创建。 - 真实对象的某些行为很难被触发。 - 真实对象实际上还不存在。 ![](//img1.jcloudcs.com/developer.jdcloud.com/e8593cdd-9ad7-4e0e-b334-ff028c8b231e20210812114538.png) MockIto和PowerMock是众多Mock框架中的两种,类似的还有:JMock,EasyMock,大多 Java Mock 库如 EasyMock 或 JMock 都是 expect-run-verify (期望-运行-验证)方式,而 Mockito 则使用更简单,更直观的方法:在执行后的互动中提问。使用 Mockito,你可以验证任何你想要的。而那些使用 expect-run-verify 方式的库,你常常被迫查看无关的交互。非 expect-run-verify 方式 也意味着,Mockito无需准备昂贵的前期启动。他们的目标是透明的,让开发人员专注于测试选定的行为。 ### 2.解决的问题 我们在写单元测试时,总会遇到类似这些问题: 1. 构造的入参,对于极值、异常边界场景不好复现,相关的逻辑测不到,只能依靠测试环境或预发跑,运气不好可能要改好几次代码重启机器验证,费时费力; 1. 依赖别人接口,可能需要别人协助测试环境数据库插数才能跑通; 1. 依赖的别人的接口还没有开发完,为了不影响提测,如何完成单元测试? 1. 编写的单元测试依赖测试数据库的数据,每次跑都要数据库改数? 1. 对service层加了逻辑,跑单元测试本地验证的时候,由于种种原因,本地环境跑不起来,折腾半天跑起来验证完了,下次开发需求又遇到了另一个问题本地环境启动报错??? 1. 我就想dubug到某一行代码,但是逻辑复杂,东拼西凑的参数就是走不到,自己看代码逻辑还要去问别人接口的返回值逻辑??(未完待续……) 引入Mockito和PowerMock使得编写单元测试更轻松,更省时,更省力。 ### 3.如何解决问题 #### 3.1 使用mock的意义 ![](//img1.jcloudcs.com/developer.jdcloud.com/539d1dea-e574-43fc-864e-89195e45186120210812114558.png) 简单说就是无论谁的本地环境,无论判断条件多么苛刻,无论本地数据库的测试数据被谁删了改了,无论别人接口的返回值逻辑多复杂,无论自己代码逻辑多复杂,都能独立的、可重复执行的、行级别覆盖的单元测试用例。 ![](//img1.jcloudcs.com/developer.jdcloud.com/69c29296-efdd-4c24-9b55-30a5e191489520210812114641.png) #### 3.2 Mockito和PowerMock 一句话说Mockito和PowerMock。当所测逻辑里有静态工具类方法或私有方法我们希望他返回特定值时(极值边界、异常测试场景),我们要用到PowerMock去弥补Mockito的不足,除此之外,用Mockito去写单测能完成我们日常任务95%的场景。 #### 3.3 使用Mcokito和PowerMock的最佳实践 ##### 3.3.1 引入pom文件 ![](//img1.jcloudcs.com/developer.jdcloud.com/3398bc34-b3c5-474b-9d6d-893ffcb9a2e220210812114709.png) ##### 3.3.2 Mockito和PowerMock 两条通用语法 - 打桩: when(XXxService.xxMethod("期望入参")).thenReturn("期望出参"); - 验证: verify(XXxService).xxMethod("期望入参"); ### 4.举例说明 #### 4.1 SpringBoot项目下Mockito和PowerMock最佳实践 - classes: 指定要加载的类 - properties: 指定要设置属性 - @InjectMocks: 需要注入mock对象的Bean - @MockBean或@Mock: 需要mock的Bean ```java import X; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.MockitoAnnotations; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; /** * 测试类A,调用服务B和一个静态工具类X */ @RunWith(PowerMockRunner.class) @SpringBootTest(classes = { A.class }) @PowerMockIgnore({"javax.management.*"}) @PrepareForTest({X.class}) //mock 静态方法 public class ATest { @InjectMocks private A a; @Mock private B b; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); } @Test public void Test() { when(b.someMethodB(any())).thenReturn(someThingB()); a.someMethodA(someThingA1(), someThingA2()); verify(b).someMethodB(any()); } /** * 异常边界测试 */ @Test public void test_ExceptionTest() throws ParseException { PowerMockito.mockStatic(X.class); // 模拟异常抛出的场景 when(X.strToDate(anyString(), anyString())).thenThrow(ParseException.class); when(X.convertLocalDateTime(any())).thenReturn(someThing()); when(b.someMethodB(any())).thenReturn(someThingB()); a.someThingA(someThingA1(), someThingA2()); verify(b).someMethodB(any()); } } ``` 优雅的mock可以考虑@spy,当然,mockito还有一些特性可以自行学习如: ![](//img1.jcloudcs.com/developer.jdcloud.com/281ad501-f1c8-44f8-bb85-394db68f61b320210812114831.png) ### 5.遇到的一些问题及解决 - 打桩逻辑判断是通过equals方法判断的 - 测试的预期是抛出异常直接在注解上加:@Test(expected=BusException.class) - 模拟的参数为null:Mockito.isNull() - PowerMock mock静态和私有final会有一些格式区别 - PowerMock mock静态方法时也可以使用spy的方式使代码更优雅 - mock中发现,mock没有生效,可以尝试升级Mockito版本解决,另外与junit反射工具类结合使用,效果更佳。 ------------ ###### 自猿其说Tech-JDL京东物流技术发展部 ###### 作者:中台技术部 杨建民
原创文章,需联系作者,授权转载
上一篇:AspectJ浅析系列(二)-切入点和通知
下一篇:幂等设计详解
相关文章
浅谈对敏捷的认识
架构研究:研发敏捷与中台架构(论前台bp研发敏捷)
敏捷实践 — 估算
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。
01
Taro小程序跨端开发入门实战
为了让小程序开发更简单,更高效,我们采用 Taro 作为首选框架,我们将使用 Taro 的实践经验整理了出来,主要内容围绕着什么是 Taro,为什么用 Taro,以及 Taro 如何使用(正确使用的姿势),还有 Taro 背后的一些设计思想来进行展开,让大家能够对 Taro 有个完整的认识。
01
Flutter For Web实践
Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践
01
配运基础数据缓存瘦身实践
在基础数据的常规能力当中,数据的存取是最基础也是最重要的能力,为了整体提高数据的读取能力,缓存技术在基础数据的场景中得到了广泛的使用,下面会重点展示一下配运组近期针对数据缓存做的瘦身实践。
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号