Mockito 单元测试

  1. Mockito 简介

     Mockito是一个java仿冒架构,所谓的仿冒就是创建一个“虚拟”的java类来模拟一个java类的行为。之所以使用仿冒可能出于以下几个原因:

  •      某个类已经进入单元测试,但是协作的类还没有开发完成;
  •      协作类可能有缺陷,使用仿冒机制隔离缺陷;
  •      模拟在单元测试阶段难以获得的对象,这些对象往往与环境和容器相关,如:HttpServletRequest

     Mockito的三个事件,mock仿冒、验证(verification)和打桩(stubbing)。所谓的验证就是断言预期的行为,所谓的打桩就是mock对象在特定情况下的入参和返回

    2.  Maven 配置 

     

<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>1.9.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.kubek2k</groupId>
            <artifactId>springockito</artifactId>
            <version>1.0.9</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.kubek2k</groupId>
            <artifactId>springockito-annotations</artifactId>
            <version>1.0.9</version>
            <scope>test</scope>
        </dependency>

       3.使用

      

 // 引用的静态资源
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

       1.简单的例子演示验证和打桩

@Test
public void test(){
        //制造一个mock 类
        Map<String, Object> map = mock( Map.class );

        map.put( "key", "value" );
        map.clear();
        //验证mock类是否调用
        verify( map ).put( "key", "value" );// 只进行equals匹配

        //验证clear至少调用过一次
        verify( map, atLeast( 1 ) ).clear();

        //打桩,尚未进行打桩的参数返回null
        Assert.assertEquals( null, map.get( "any" ) );
        // 进行打桩后
        when( map.get( "Hello" ) ).thenReturn( "World" );
        Assert.assertEquals( "World", map.get( "Hello" ) );
    }

  通过上面示例我们可以看出mock的没次调用我们都能进行监控,相应的mock可以准确的模拟对象的行为,忽略对象行为的实现细节。

   mock未打桩时对象的返回值

  •     返回Object的方法,mock默认返回null;
  •     返回集合的方法,mock默认返回空;
  •     返回数字的方法,mock默认返回0;
  •     返回boolean的方法,mock默认返回false;

   mock可以进行多次打桩,没次打桩都会覆盖前一个的值

    参数匹配

@Test
    public void test(){
        List list = mock( List.class );
        //任何整数参数
        when( list.get( anyInt() ) ).thenReturn( null );
        //两个任意参数
        when( list.addAll(anyInt(), anyCollection() ) ).thenReturn( false );
    }
   mock除了支持任意整数和人与集合 还用 anyBoolean()、anyByte()、anyLong()等

   参数捕获

@Test
    public void test(){
        List list = mock( List.class );
        ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass( Integer.class );
        list.add( 1 );//这个参数会被捕获
        verify( list ).add( argument.capture() ); //执行捕获
        //后续对参数进行进一步验证
        Assert.assertEquals( new Integer( 1 ), argument.getValue() );
    }

 返回值设定

@Test
    public void test(){
        List list = mock( List.class );
        when( list.get( 0 ) ).thenReturn( 10 );
        // 设置多个返回值,没次调用返回值不一样
        when( list.get( 0 ) ).thenReturn( 1, 2, 3 );
        //设置异常返回
        when( list.get( 0 ) ).thenThrow( new RuntimeException() );
        //依据入参决定返回值
        when( list.get( anyInt() ) ).then( new Answer<Object>() {

            public Object answer( InvocationOnMock invocation ) throws Throwable
            {
                return "El-" + invocation.getArguments()[0];
            }
        } );
        //连续仿冒
        when( list.get( 0 ) )
                .thenReturn( 1 ) //第一次调用的返回值
                .thenReturn( 2 )//第二次调用的返回值
                .thenThrow( new RuntimeException() ); //以后调用的返回值

        //设置未打桩方法的默认返回值
        mock( List.class, new Answer<Object>() {

            @Override
            public Object answer( InvocationOnMock invocation ) throws Throwable
            {
                return null;
            }
        } );
    }

 验证调用次数

List list = mock( List.class );
//验证基于某个精确实参的调用发生的次数
verify( list, times( 1 ) ).add( 1 ); //一次
verify( list, times( 2 ) ).add( 2 ); //二次
verify( list, atLeastOnce() ).add( 1 ); //至少一次
verify( list, atLeast( 3 ) ).add( 3 ); //至少三次
verify( list, atMost( 3 ) ).add( 3 ); //至多三次
//参数匹配也适用于验证的时候:
verify( list, atMost( 3 ) ).add( argThat( new ArgumentMatcher<Object>() {
    public boolean matches( Object argument )
    {
        return false;
    }
} ) );
 
//断言Mock上没有发生任何未验证的调用
verifyNoMoreInteractions( list );

 调用真是方法

List<Integer> list = new ArrayList<Integer>();
List<Integer> spy = spy( list );
 
//对真实对象进行打桩
when( spy.size() ).thenReturn( 100 );
 
//另外一种打桩方式,防止异常
doReturn( 1 ).when( spy ).get( 0 );
//下面这种方式是不行的,因为未打桩前会调用真实方法,导致IndexOutOfBoundsException 
when( spy.get( 0 ) ).thenReturn( 1 );
 
 
spy.add( 1 );//调用真实的方法
spy.size();//调用仿冒的方法
verify( spy ).add( 1 ); //验证调用了一次

 启动支持注解

//如果要启用注解支持,可以使用该运行类
//或者手工调用MockitoAnnotations.initMocks(this)
@RunWith ( MockitoJUnitRunner.class )
public class MockitoTest
{
    //自动创建Mock
    @Mock
    private List<Object> list;
 
}

 其他

List mock = mock(List.class);
when(mock.size()).thenReturn(10);
 
reset(mock);  //重置仿冒
 
//单行调用即完成的Mock
Car boringStubbedCar = when(mock(Car.class).shiftGear()).thenThrow(EngineNotStarted.class).getMock();

猜你喜欢

转载自lianpeng0011.iteye.com/blog/2414765