作者:京东物流 杨建民

1.什么是Mock

Mock有模拟、伪造的含意。Mock测试就是在测试过程中,对于某些不容易结构或者不容易获取的对象,用一个虚构的对象来创立以便测试的测试方法。mock工具应用领域:

  • 实在对象具备不确定的行为,产生不可预测的成果。
  • 实在对象很难被创立。
  • 实在对象的某些行为很难被触发。
  • 实在对象实际上还不存在。

MockIto和PowerMock是泛滥Mock框架中的两种,相似的还有:JMock,EasyMock,大多 Java Mock 库如 EasyMock 或 JMock 都是 expect-run-verify (冀望-运行-验证)形式,而 Mockito 则应用更简略,更直观的办法:在执行后的互动中发问。应用 Mockito,你能够验证任何你想要的。而那些应用 expect-run-verify 形式的库,你经常被迫查看无关的交互。非 expect-run-verify 形式 也意味着,Mockito无需筹备低廉的后期启动。他们的指标是通明的,让开发人员专一于测试选定的行为。

2.解决的问题

咱们在写单元测试时,总会遇到相似这些问题:

1. 结构的入参,对于极值、异样边界场景不好复现,相干的逻辑测不到,只能依附测试环境或预发跑,运气不好可能要改好几次代码重启机器验证,费时费力;

2. 依赖他人接口,可能须要他人帮助测试环境数据库插数能力跑通;

3. 依赖的他人的接口还没有开发完,为了不影响提测,如何实现单元测试?

4. 编写的单元测试依赖测试数据库的数据,每次跑都要数据库改数?

5. 对service层加了逻辑,跑单元测试本地验证的时候,因为种种原因,本地环境跑不起来,折腾半天跑起来验证完了,下次开发需要又遇到了另一个问题本地环境启动报错???

6. 我就想dubug到某一行代码,然而逻辑简单,七拼八凑的参数就是走不到,本人看代码逻辑还要去问他人接口的返回值逻辑??(未完待续……)引入Mockito和PowerMock使得编写单元测试更轻松,更省时,更省力。

3.如何解决问题

3.1  应用mock的意义 

简略说就是无论谁的本地环境,无论判断条件如许刻薄,无论本地数据库的测试数据被谁删了改了,无论他人接口的返回值逻辑多简单,无论本人代码逻辑多简单,都能独立的、可反复执行的、行级别笼罩的单元测试用例。

3.2 Mockito和PowerMock   

一句话说Mockito和PowerMock。当所测逻辑里有动态工具类办法或公有办法咱们心愿他返回特定值时(极值边界、异样测试场景),咱们要用到PowerMock去补救Mockito的有余,除此之外,用Mockito去写单测能实现咱们日常工作95%的场景。

3.3  应用Mcokito和PowerMock的最佳实际

3.3.1  引入pom文件

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
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还有一些个性能够自行学习如:

5.遇到的一些问题及解决

  • 打桩逻辑判断是通过equals办法判断的
  • 测试的预期是抛出异样间接在注解上加:@Test(expected=BusException.class)
  • 模仿的参数为null:Mockito.isNull() 
  • PowerMock mock动态和公有final会有一些格局区别
  • PowerMockmock静态方法时也能够应用spy的形式使代码更优雅
  • mock中发现,mock没有失效,能够尝试降级Mockito版本解决,另外与junit反射工具类联合应用,成果更佳。
  • 波及多层嵌套的应用场景,读者先思考”单元“选取是否正当,多层嵌套场景将@InjectMocks和@Spy(或@Mock)联结应用即可

结束语:

文章写于早些时候,目前有些较新技术涌入,如:Spock、TestableMock等,但上述技术仍然实用于大型零碎品质内建,读者可依据本身状况选择性选用。