单元测试–Mockito之spy

1. apy

* mockito中实现部分mock的方式,及使用Mockito mock当前类【同一类】中的部分方法
* 部分mock是说一个类的方法有些是实际调用,有些是使用mockito的stubbing(桩实现)
  • spy和mock的相同点和区别:
  • 1.得到的对象同样可以进行“监管”,即验证和打桩。
  • 2.如果不对spy对象的methodA打桩,那么调用spy对象的methodA时,会调用真实方法。
  • 3.如果不对mock对象的methodA打桩,将doNothing,且返回默认值(null,0,false)。

2. @SpyBean 和 @MockBean 区别,以及@Spy 和 @Mock的区别

  1. 默认行为的不同
  • 对于未进行mock的方法,@Spy和@SpyBean生成的对象默认会调用真实的方法,有返回值的返回真实的返回值
  • 而@Mock和@MockBean生成的对象对于未进行mock的方法,默认不执行,有返回值的,默认返回null
  1. mock的使用方式不同
    @Mock和@MockBean生成的对象的使用 when/then: 包括when(…).thenReturn(…)/when(…).thenAnswer(…)方式,@spy对象这样使用会直接调用该方法,但有返回值的返回为then后的返回值
//when().thenReturn第一次调用methodA()会真是调用,但返回值为thenReturn的返回值
	 when(testSpy.methodA()).thenReturn(0);

对@Spy和@SpyBean生成的对象的mock时,要先执行do等方法,调用时才不会调用真实的方法
do/when:包括doThrow(…).when(…)/doReturn(…).when(…)/doAnswer(…).when(…)

  1. @spy和@mock生成的对象不受spring管理
  2. @spy调用真实方法时,其它bean是无法注入的,要使用注入,要使用@SpyBean
  3. @SpyBean和@MockBean生成的对象受spring管理,相当于自动替换对应类型bean的注入,比如@Autowired等注入

3. 代码实例

public class TestSpy {
    public int methodA(){
        //根据某成员变量的值去计算得出一个value,这个过程包含了复杂的逻辑和层层方法嵌套调用
        int a = 100;
        System.out.println("methodA");
        return a;
    }

    public void methodB(){
        int key = methodA();
        switch(key){
            case 0:
                System.out.println("case 0");
                //do something
                break;
            case 1:
                System.out.println("case 1");
                //do something
                break;
            case 2:
                System.out.println("case 2");
                //do something
                break;
        }
    }


}

Test

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.junit4.SpringRunner;

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestSpyTest {


    @SpyBean
   private TestSpy testSpy;

    //此用例中使用testSpy的原因是我要测试的是TestSpy 的methodB方法,所以需要
    //调用真实对象的methodB,methodB的输入来自methodA的返回值。但是methodA的计算十分复杂,
    //那么想要methodA返回你想要的值就不那么容易,别人看起来也不直观,不确定methodA否是真的
    //返回0,1,2。那么就可以对methodA打桩,对真实对象打桩,就要用到testSpy.
    @Test
    public void testMethodB(){
        //TestSpy t = new TestSpy();
        //TestSpy spyT  = Mockito.spy(t);
        /*when().thenReturn第一次调用methodA()会真是调用,但返回值为thenReturn的返回值
         第一次,第二次,第三次调用methodA时,分别返回0,1,2*/
   	 	when(testSpy.methodA()).thenReturn(0,1,2);

        /*doReturn().when() 和不会真是调用methodA()方法
        第一次,第二次,第三次调用methodA时,分别返回0,1,2*/
       Mockito.doReturn(0,1,2).when(testSpy).methodA();
        for(int i=0; i<=2; i++){
            testSpy.methodB();
        }
        //assert && verify
    }

}

输出结果

使用when(testSpy.methodA()).thenReturn(0,1,2);打桩

SpringBootTest 比较慢_spring

使用 Mockito.doReturn(0,1,2).when(testSpy).methodA();打桩

SpringBootTest 比较慢_spring_02