Mockito的使用及原理浅析

本文深入剖析了Mockito的使用方法及其实现原理,介绍了如何通过@Mock、@Spy和@InjectMocks等注解创建Mock对象,以及when().thenReturn()的内部工作流程。

Mockito的使用及原理浅析

在微服务横行的年代,一个服务可能依赖了若干个其它服务,而这些被依赖的服务,又极可能依赖了别的服务,于是构成了一个复杂的依赖链。而日常开发中,经常会苦恼于某某上游接口没数据而所使得UT达不到预期的目标,所兴现在已经有了多种Mock Toolkit,很好的解决了这一痛点。比较常用的有EasyMock,JMockit,Mockito,PowerMock等,而本文主要介绍Mockito的简单使用,并对其实现原理进行简单分析

Mockito的使用

通常情况下,我们会在UT里使用@Mock、@Spy以及@InjectMocks等注解来Mock掉一些不可控的上下游接口,为了简化说明,我们将例子简单化。
假设有这样的一个服务

public class ServiceA {
   
   

    @Autowired
    private ServiceB serviceB;
    
    public String hello(String name) {
   
   
        return "ServiceA.hello:" + name;
    }
    
    public String helloB(String name) {
   
   
        return serviceB.hello(name);
    }
}

@Mock

现在我们来将它mock掉

public class MockTest {
   
   
    
    @Mock
    private ServiceA seriveA;

    @Before
    public void init() {
   
   
        MockitoAnnotations.initMocks(this);
    }
    
    @Test
    public void testA() {
   
   
        Mockito.when(seriveA.hello("aaa")).thenReturn("111").thenReturn("222");  //打桩
        System.out.println(seriveA.hello("aaa"));   //111                        //真实调用
        System.out.println(seriveA.hello("aaa"));   //222
        System.out.println(seriveA.hello("bbb"));   //null
    }
}

为了便于描述,先简单说明一下:上面serviceA.hello(“aaa”)调用结果做为入参传递给when()方法,我们称为打桩,而后面的调用是我们称为真实调用。
Mockito提供了通俗易用的API,@Mock注释用于对目标对象进行mock,生成立mock对象,when…thenReturn…用于模拟返回结果,当调用某某方法时返回我们想要的预定结果, thenThrow则用于模拟目标方法抛出异常,而我们也可以使用方法链模拟返回多个mock结果,在多次调用目标方法时,Mockito会依次为我们返回预先设定的mock结果。

@InjectMocks

ServiceA依赖了ServiceB,如果我们要mock的不是ServiceA,而是ServiceB,那我们可以在UT里,给ServiceB加注释@Mock,给ServiceA加上注释@InjectMocks,这时Mockito会自动为ServiceA注入mock对象ServiceB

public class MockTest2 {
   
   
    
    @InjectMocks
    private ServiceA serviceA;
    @Mock
    private ServiceB serviceB;
    
    @Before
    public void init() {
   
   
        MockitoAnnotations.initMocks(this);
    }
    
    @Test
    public void testB() {
   
   
        Mockito.when(serviceB.hello("aaa")).thenReturn("111").thenReturn("222");
        System.out.println(serviceA.helloB("aaa"));   //111
        System.out.println(serviceA.helloB("aaa"));   //222
        System.out.println(serviceA.helloB("bbb"));   //null
    }
}

从上面的用法中,整个mock的过程大概可以分为三步:
1)@Mock注解声明了要将对象进行mock
2)使用MockitoAnnotations.initMocks告诉Mockito要对当前对象进行mock处理。当然你用可以使用@RunWith(MockitoJUnitRunner.class),殊途同归。
3)使用when…thenReturn来模拟返回
接下来我们来分析一下其实现原理。

Mockito的实现原理

mock对象的创建

首先我们看看MockitoAnnotations.initMocks到底做了什么?一起进入源码。

public static void initMocks(Object testClass) {
   
   
        if (testClass == null) {
   
   
            throw new MockitoException("testClass cannot be null. For info how to use @Mock annotations see examples in javadoc for MockitoAnnotations class");
        }

        AnnotationEngine annotationEngine = new GlobalConfiguration().getAnnotationEngine();
        Class<?> clazz = testClass.getClass();

        //below can be removed later, when we get read rid of deprecated stuff
        if (annotationEngine.getClass() != new DefaultMockitoConfiguration().getAnnotationEngine().getClass
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值