• mockito的用法


    well,说来惭愧,之前一直知道有这么个东西,但总是看不进去。刚好趁着这次迭代间隙有些闲暇,认真看了下,大概明白是怎么回事了。

    首先,mock是个概念,这个词的本意就是“虚假的”、“模仿的”。在测试的时候,很多情况下都无法获取真正的对象,如Servlet对象,但测试又需要这个对象,怎么办?

    当然是弄个假的给糊弄一下啦。

    其次,mock的实现有很多,本文只关心Mockito,其他的请自行百度哈。

    看到所有的资料都说Mockito有两方面的作用:1. 验证方法调用; 2. 指定特定条件下某个方法的返回值,或者执行特定的动作。

    废话少说,直接上代码验证一下。

    1. 先上pom文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>win.larryzeal</groupId>
        <artifactId>mockito-study</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging>
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
        </properties>
        
        <dependencies>
            <!--2.x not good 呵呵-->
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-all</artifactId>
                <version>1.10.19</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
        </dependencies>
    </project>

    2. 再提供一个接口 Processor,不提供实现。

    package win.larryzeal.mockito.study;
    
    public interface Processor {
        void process();
        
        int get();
        
        void cb(int a, int b,  Callback cb);
    }
    
    package win.larryzeal.mockito.study;
    
    public interface Callback {
        int onSuccess();
        int onFail();
    }

    3. 然后看一下怎么验证调用 - 需要特别指出的是,mock的对象相当于加了一层代理,可以认为是实现。如下:

    package win.larryzeal.mockito.study;
    
    import org.junit.Test;
    import org.mockito.Mockito;
    import org.mockito.invocation.InvocationOnMock;
    import org.mockito.stubbing.Answer;
    
    //1. 验证方法调用
    public class MockTest {
    
        @Test
        public void r1() {
    
            Processor mock = Mockito.mock(Processor.class);
            mock.process();
    
            //注意,这里相当于验证之前的调用!
            Mockito
                    .verify(mock) //Alias to verify(mock, times(1))  验证是否调用一次
                    .process();
    
        }
    
        @Test
        public void r2() {
    
            Processor mock = Mockito.mock(Processor.class);
            mock.process();
    
            //注意,这里相当于验证之前的调用!
            Mockito
                    .verify(mock, Mockito.times(3)) //Alias to verify(mock, times(1))  验证是否调用n次
                    .process();
    
        }
    
    
    }

    上面的验证很简单,就是验证指定mock的特定方法的调用 - 可以是调用次数,也可以是超时等,还可以是复合的验证条件,如Mockito.timeout(1000).times(3)。

    4. 再来看看怎么定制特定方法的返回结果 - 很有用噢,特别是针对远程调用、接口调用等情况。

    package win.larryzeal.mockito.study;
    
    import org.junit.Test;
    import org.mockito.Mockito;
    import org.mockito.invocation.InvocationOnMock;
    import org.mockito.stubbing.Answer;
    
    //2. 指定某个方法的返回值
    public class MockTest {
    
        @Test
        public void r3() {
    
            Processor mock = Mockito.mock(Processor.class);
    
            //注意,这里相当于设定mock里某个方法的返回值!在测试遇到嵌套方法,且嵌套方法不便于调用时,非常有用。
            Mockito
                    .when(mock.get()) 
                    .thenReturn(0xff); //这里是可变参数,多次调用的情况下,依次返回相应的数值;如果超出次数,返回最后一个值。
    
            System.out.println(mock.get());
        }
    
    }

    嗯嗯,when用于指定调用的方法,thenXxx用于指定返回结果 或者 抛出异常。

    5. 再来看看回调的情况 - 传入的参数是条件,根据条件来调用特定的回调。

    package win.larryzeal.mockito.study;
    
    import org.junit.Test;
    import org.mockito.Mockito;
    import org.mockito.invocation.InvocationOnMock;
    import org.mockito.stubbing.Answer;
    
    
    //2. 指定某个方法的返回值,或者是执行特定的动作
    public class MockTest {
    
        @Test
        public void r4() {
            Processor mock = Mockito.mock(Processor.class);
    
            //这里,是设定在特定条件下调用特定的回调! - 这个特定的条件是不同的参数,可以是具体的,也可以是Mockito.anyXxx。
            Mockito
                    .doAnswer((InvocationOnMock invocation) -> {
                        Callback cb = invocation.getArgumentAt(2, Callback.class);
                        cb.onFail();
                        return null; //嗯?这里的返回值是?
                    })
                    .when(mock)
                    .cb(Mockito.eq(1), Mockito.eq(-1), Mockito.any(Callback.class)); //TODO 如果用matcher,那所有的参数都需要是matcher
    
            //实际的调用
            mock.cb(1, -1, new Callback() {
                @Override
                public int onSuccess() {
                    System.out.println("ok");
                    return 200;
                }
    
                @Override
                public int onFail() {
                    System.out.println("fail");
                    return 500;
                }
            });
            mock.cb(1, 1, null);
        }
    
    }

    前面设定条件,然后实际调用下,就是这么简单!

    ps:暂时不明白那个Invocation的返回值是干嘛用的,稍后再说。

    6. 最后看看 spy,Mockito 除了mock()方法,还提供了spy,简单的说就是可以不指定方法的返回值,而是返回类型的默认值(零值)。如下:

    package win.larryzeal.mockito.study;
    
    import org.junit.Test;
    import org.mockito.Mockito;
    import org.mockito.invocation.InvocationOnMock;
    import org.mockito.stubbing.Answer;
    
    public class MockTest {
    
    
        @Test
        public void r5() {
    
            //spy,除非设定,返回返回默认值
            Processor spy = Mockito.spy(Processor.class);
    
            //多次调用的情况下,依次返回相应的数值;如果超出次数,返回最后一个值。
            //Mockito.when(spy.get()).thenReturn(3, 5, 9); //不指定的情况,返回0
    
            System.out.println(spy.get());
            System.out.println(spy.get());
            System.out.println(spy.get());
            System.out.println(spy.get());
    
            //同样可以校验执行次数
    //        Mockito.verify(spy).get(); //一次
            Mockito.verify(spy, Mockito.times(4)).get();
        }
    
    }

    ok,至此基本就算大功告成了,赶快去试试吧?

  • 相关阅读:
    IIS7运行.NET Framework 4 报500错误
    祝大家新年快乐,兔年行大运
    生成高清缩略图; 添加图片、文字水印; 图片、文字水印透明
    NHibernate中使用Guid作为主键、项目中NHibernate与Log4net共存
    使用split进行大数据分割时内存溢出解决方案
    about server.MapPath
    Lucene 如何实现高性能 GroupBy <一>
    理解委托(delegate)及为什么要使用委托
    观亚运会开幕式有感
    c#中的new、override
  • 原文地址:https://www.cnblogs.com/larryzeal/p/10915548.html
Copyright © 2020-2023  润新知