作者:京东物流杨建民1.什么是MockMock有模仿、伪造的意思。模拟测试是一种测试方法,它使用虚拟对象为测试过程中一些不易构造或获取的对象创建测试方法。mock工具的使用范围:真实对象具有不确定的行为,产生不可预知的效果。真实的对象很难创建。真实对象的某些行为很难触发。真实的对象实际上还不存在。MockIto和PowerMock是众多Mock框架中的两个,还有类似的:JMock、EasyMock,大多数JavaMock库如EasyMock或JMock都是期望运行验证(expect-run-verify)方法,而Mockito使用更多更简单、更直观的方法:在执行后交互中提问。使用Mockito,您可以验证任何您想要的东西。对于使用expect-run-verify方法的库,您通常不得不查看不相关的交互。非预期运行验证方法还意味着Mockito不需要为昂贵的前期启动做准备。他们的目标是保持透明,让开发人员专注于测试选定的行为。2.解决的问题我们在写单元测试的时候,总会遇到类似的问题:1.结构体的输入参数不容易重现极值和异常边界场景,相关逻辑无法测试,所以只能依赖tests环境或者pre-launchrun,运气不好的话可能要改几次代码重启机器验证,费时费力;2.依赖别人的接口,可能需要别人协助测试环境数据库插入才能跑通;3.别人的依赖接口还没有开发好后,为了不影响测试,如何完成单元测试?4、写的单元测试依赖测试数据库的数据,每次运行都要改数据库?5.添加服务层逻辑。在本地验证运行单元测试时,由于各种原因,本地环境无法运行。经过长时间的运行和验证,接下来的开发需求又遇到了问题。本地环境启动报错???6、我只想调试某行代码,但是逻辑复杂,我拼凑的参数也达不到。自己看代码逻辑还得问别人接口的返回值逻辑??(未完待续...)Mockito和PowerMock的引入让编写单元测试变得更简单、更省时、更省力。3.如何解决问题3.1使用mock的意义简单的说,不管本地环境是谁,判断条件有多苛刻,本地数据库的测试数据被谁删改修改,有多复杂别人接口的返回值逻辑,不管别人接口的返回值逻辑多么复杂,判断条件多么苛刻。无论代码逻辑多么复杂,都可以有独立的、可重复的、行级覆盖的单元测试用例。3.2Mockito和PowerMock一句话,Mockito和PowerMock。当被测逻辑中有静态工具类方法或私有方法,我们希望它们返回特定值(极值边界、异常测试场景)时,就需要使用PowerMock来弥补Mockito的不足。另外,使用Mockito编写单机测试可以完成我们95%的日常任务。3.3使用Mcokito和PowerMock的最佳实践3.3.1引入pom文件3.3.2Mockito和PowerMock打桩的两种通用语法:when(XXxService.xxMethod("Expectinputparameters")).thenReturn("Expectoutputparameters");验证:verify(XXxService).xxMethod("预期参数");4.例子4.1SpringBoot项目下Mockito和PowerMock最佳实践类:指定要加载的类属性:指定要设置的属性@InjectMocks:需要注入mock对象的Bean@MockBean或@Mock:需要mockimportX;import的Beanorg.junit.Test;导入org.junit.runner.RunWith;导入org.mockito.InjectMocks;导入org.mockito.MockitoAnnotations;导入org.powermock.api.mockito.PowerMockito;导入org.powermock.core.classloader.annotations.PowerMockIgnore;导入org.powermock.core.classloader.annotations.PrepareForTest;导入org.powermock.modules.junit4.PowerMockRunner;调用服务B和静态实用程序类X*/@RunWith(PowerMockRunner.class)@SpringBootTest(classes={A.class})@PowerMockIgnore({"javax.management.*"})@PrepareForTest({X.class})//模拟静态方法publicclassATest{@InjectMocksprivateAa;@Mock私人Bb;@BeforepublicvoidsetUp()抛出异常{MockitoAnnotations.initMocks(this);}@TestpublicvoidTest(){when(b.someMethodB(any())).thenReturn(someThingB());a.someMethodA(someThingA1(),someThingA2());验证(b).someMethodB(任何());}/***异常边界测试*/@Testpublicvoidtest_ExceptionTest()throwsParseException{PowerMockito.mockStatic(X.class);//模拟异常抛出场景when(X.strToDate(anyString(),anyString())).thenThrow(ParseException.class);当(X.convertLocalDateTime(any())).thenReturn(someThing());when(b.someMethodB(any())).thenReturn(someThingB());a.someThingA(someThingA1(),someThingA2());验证(b).someMethodB(任何());}优雅的mock可以考虑@spy,当然mockito也有一些特性可以自己学习,比如:5.打桩逻辑遇到的一些问题及解决方法判断是通过equals方法判断测试的期望是抛出异常直接在注解中添加:@Test(expected=BusException.class)模拟参数为null:Mockito.isNull()PowerMockmockstatic和privatefinal会有一些格式差异如果生效,可以尝试升级Mockito版本解决。另外结合junit反射工具类使用,效果会更好。对于涉及多层嵌套的场景,读者首先要思考“单元”的选择是否合理。多层嵌套场景会用到@InjectMocks和@InjectMocks@Spy(或@Mock)可以结合使用总结:文章写得比较早,目前有一些比较新的技术在涌入,比如:Spock、TestableMock等.,不过以上技术还是适合大型系统质量内置的,读者可以根据自己的情况选择。
