zoukankan      html  css  js  c++  java
  • Mockito的简单使用方法演示样例

    Mockito是一个流行的Mocking框架。它使用起来简单,学习成本非常低。并且具有非常简洁的API,測试代码的可读性非常高。因此它十分受欢迎,用 户群越来越多。非常多的开源的软件也选择了Mockito。

    要想了解很多其它有关Mockito的信息。请訪问它的官方网 站:http://mockito.org/

    一、简单演示样例

    /*
     * Creation : 2015年8月14日
     */
    package com.tan.test;
    
    import static org.junit.Assert.assertArrayEquals;
    import static org.junit.Assert.assertEquals;
    import static org.mockito.Matchers.anyInt;
    import static org.mockito.Matchers.anyString;
    import static org.mockito.Matchers.eq;
    import static org.mockito.Mockito.inOrder;
    import static org.mockito.Mockito.mock;
    import static org.mockito.Mockito.never;
    import static org.mockito.Mockito.spy;
    import static org.mockito.Mockito.times;
    import static org.mockito.Mockito.verify;
    import static org.mockito.Mockito.verifyNoMoreInteractions;
    import static org.mockito.Mockito.when;
    
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    
    import org.junit.Test;
    import org.mockito.ArgumentCaptor;
    import org.mockito.InOrder;
    import org.mockito.invocation.InvocationOnMock;
    import org.mockito.stubbing.Answer;
    
    import edu.emory.mathcs.backport.java.util.LinkedList;
    
    public class MockitoTest {
        /**
         * 通过when(mock.someMethod()).thenReturn(value) 来设定mock对象某个方法调用时的返回值
         */
        @Test
        public void simpleTest() {
            // arrange
            Iterator i = mock(Iterator.class);
            when(i.next()).thenReturn("Hello").thenReturn("World");
            // act
            String result = i.next() + " " + i.next();
            // 验证i.next()是否被调用了2次。不关心返回值
            verify(i, times(2)).next();
            // 断言结果是否和预期一样
            assertEquals("Hello World", result);
        }
    
        /**
         * 參数匹配器--Argument matchers test.
         */
        @Test
        public void argumentMatchersTest() {
            List<String> mock = mock(List.class);
            // anyInt()參数匹配器来匹配不论什么的int 类型的參数
            when(mock.get(anyInt())).thenReturn("Hello").thenReturn("World");
    
            // 所以当第一次调用get方法时输入随意參数为100方法返回”Hello”,第二次调用时输入随意參数200返回值”World”。

    String result = mock.get(100) + " " + mock.get(200); // verfiy 验证的时候也可将參数指定为anyInt()匹配器,那么它将不关心调用时输入的參数的详细參数值。

    verify(mock, times(2)).get(anyInt()); assertEquals("Hello World", result); /* 注意:假设使用了參数匹配器。那么全部的參数须要由匹配器来提供,否则将会报错。 */ } /** * 參数匹配器--Argument matchers test2. */ @SuppressWarnings("unchecked") @Test public void argumentMatchersTest2() { Map<Integer, String> mapMock = mock(Map.class); when(mapMock.put(anyInt(), anyString())).thenReturn("world"); mapMock.put(1, "hello"); // 注:在最后的验证时假设仅仅输入字符串”hello”是会报错的,必须使用Matchers 类内建的eq方法。

    // 假设将anyInt()换成1进行验证也须要用eq(1)。 verify(mapMock).put(anyInt(), eq("hello")); } /** * 3.Mock对象的行为验证--Verify test. */ @Test public void verifyTest() { List<String> mock = mock(List.class); List<String> mock1 = mock(List.class); when(mock.get(0)).thenReturn("hello"); mock.get(0); mock.get(1); mock.get(2); mock1.get(0); /* 方法的调用不关心是否模拟了get(2)方法的返回值。仅仅关心mock 对象后,是否运行了mock.get(2),假设没有运行。測试方法将不会通过。 */ verify(mock).get(2); // 验证对象mock是否调用了get(2)方法 verify(mock, never()).get(3); // 方法中能够传入never()方法參数来确认mock.get(3)方法不曾被运行过 /* 确认mock1对象没有进行不论什么交互===>測试不通过 */ verifyNoMoreInteractions(mock1); // 将其放在 mock1.get(0);之前就可以通过。 } /** * 验证方法的调用顺序. */ @Test public void testInvokeOrder() { List<String> firstMock = mock(List.class); List<String> secondMock = mock(List.class); firstMock.add("was called first"); firstMock.add("was called first"); secondMock.add("was called second"); secondMock.add("was called third"); /* 假设mock方法的调用顺序和InOrder中verify的顺序不同。那么測试将运行失败。

    */ InOrder inOrder = inOrder(secondMock, firstMock); inOrder.verify(firstMock, times(2)).add("was called first"); inOrder.verify(secondMock).add("was called second"); // 由于在secondMock.add("was called third")之后已经没有多余的方法调用了。 inOrder.verify(secondMock).add("was called third"); inOrder.verifyNoMoreInteractions();// 表示此方法调用后再没有多余的交互 } /** * 自己定义Answer接口(方法预期回调接口)的应用 */ @Test public void customAnswerTest() { List<String> mock = mock(List.class); when(mock.get(4)).thenAnswer(new Answer() { public String answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); Integer num = (Integer) args[0]; if (num > 3) { return "yes"; } throw new RuntimeException(); } }); System.out.println(mock.get(4)); } /** * 利用ArgumentCaptor(參数捕获器)捕获方法參数进行验证 */ @Test public void argumentCaptorTest() { List mock = mock(List.class); List mock2 = mock(List.class); mock.add("John"); mock2.add("Brian"); mock2.add("Jim"); /* * 首先构建ArgumentCaptor须要传入捕获參数的对象,样例中是String。接着要在 verify 方法的參数中调用argument.capture()方法来捕获输入的參数, <br> 之后 * argument变量中就保存了參数值,能够用argument.getValue()获取。 */ ArgumentCaptor argument = ArgumentCaptor.forClass(String.class); verify(mock).add(argument.capture()); assertEquals("John", argument.getValue()); verify(mock2, times(2)).add(argument.capture()); assertEquals("Jim", argument.getValue()); /* argument.getAllValues()。它将返回參数值的List。 */ assertArrayEquals(new Object[] { "John", "Brian", "Jim" }, argument.getAllValues().toArray()); } /** * Spy-对象的监视<br> * Mock 对象仅仅能调用stubbed 方法。调用不了它真实的方法。

    但Mockito 能够监视一个真实的对象。这时对它进行方法调用时它将调用真实的方法。<br> * 同一时候也能够stubbing 这个对象的方法让它返回我们的期望值。

    另外不论是否是真实的方法调用都能够进行verify验证。<br> * 和创建mock对象一样。对于final类、匿名类和Java的基本类型是无法进行spy的。 */ @Test public void spyTest2() { List list = new LinkedList(); List spy = spy(list); // optionally, you can stub out some methods: when(spy.size()).thenReturn(100); // using the spy calls real methods spy.add("one"); spy.add("two"); // prints "one" - the first element of a list System.out.println(spy.get(0)); // size() method was stubbed - 100 is printed System.out.println(spy.size()); // optionally, you can verify verify(spy).add("one"); verify(spy).add("two"); } }


    二、注解用法
    Mockito对Annotation的支持
    Mockito 支持对变量进行注解,比如将mock 对象设为測试类的属性,然后通过注解的方式@Mock 来定义它。这样有利于降低反复代码。增强可读性,易于排查错误等。除了支持@Mock,Mockito支持的注解还有@Spy(监视真实的对象),@Captor(參数捕获器),@InjectMocks(mock对象自己主动注入)。
    Annotation的初始化仅仅有Annotation还不够,要让它们工作起来还须要进行初始化工作。初始化的方
    法为:MockitoAnnotations.initMocks(testClass)參数testClass是你所写的測试类。普通情况下在Junit4的@Before 定义的方法中运行初始化工作,例如以下:

    @Before
    public void initMocks() {
    MockitoAnnotations.initMocks(this);
    }

    除了上述的初始化的方法外,还能够使用Mockito 提供的Junit Runner:
    MockitoJUnitRunner这样就省略了上面的步骤。

    @RunWith(MockitoJUnit44Runner.class)
    public class ExampleTest {
    ...
    }

    @Mock 注解
    使用@Mock注解来定义mock对象有例如以下的长处:
    1. 方便mock对象的创建
    2. 降低mock对象创建的反复代码
    3. 提高測试代码可读性
    4. 变量名字作为mock对象的标示。所以易于排错
    @Mock注解也支持自己定义name 和answer属性。以下是官方给出的@Mock使用的样例:

    public class ArticleManagerTest extends SampleBaseTestCase {
    @Mock
    private ArticleCalculator calculator;
    @Mock(name = "dbMock")
    private ArticleDatabase database;
    @Mock(answer = RETURNS_MOCKS)
    private UserProvider userProvider;
    private ArticleManager manager;
    @Before
    public void setup() {
    manager = new ArticleManager(userProvider, database,
    calculator);
    }
    }
    public class SampleBaseTestCase {
    @Before
    public void initMocks() {
    MockitoAnnotations.initMocks(this);
    }
    }

    @Spy 注解
    Spy的用法请參阅前面的章节,在此不再赘述。以下是用法:

    public class Test{
    @Spy
    Foo spyOnFoo = new Foo();
    @Before
    public void init(){
    MockitoAnnotations.initMocks(this);
    }
    ...
    }

    @Captor 注解
    @Captor是參数捕获器的注解,有关用法见前章。通过注解的方式也能够更便捷
    的对它进行定义。使用样例例如以下:

    public class Test {
    @Captor
    ArgumentCaptor<AsyncCallback<Foo>> captor;
    @Before
    public void init() {
    MockitoAnnotations.initMocks(this);
    }
    @Test
    public void shouldDoSomethingUseful() {
    // ...
    verify(mock.doStuff(captor.capture()));
    assertEquals("foo", captor.getValue());
    }
    }

    @InjectMocks 注解
    通过这个注解,可实现自己主动注入mock 对象。

    当前版本号仅仅支持setter 的方式进行
    注入,Mockito 首先尝试类型注入,假设有多个类型同样的mock 对象。那么它
    会依据名称进行注入。当注入失败的时候Mockito不会抛出不论什么异常,所以你可
    能须要手动去验证它的安全性。


    例:

    @RunWith(MockitoJUnit44Runner.class)
    public class ArticleManagerTest {
    @Mock
    private ArticleCalculator calculator;
    @Mock
    private ArticleDatabase database;
    @Spy
    private UserProvider userProvider = new ConsumerUserProvider();
    @InjectMocks
    private ArticleManager manager = new ArticleManager();
    @Test
    public void shouldDoSomething() {
    manager.initiateArticle();
    verify(database).addListener(any(ArticleListener.class));
    }
    }

    上例中, ArticleDatabase 是ArticleManager 的一个属性, 由于
    ArticleManager 是注解@InjectMocks 标注的。所以会依据类型自己主动调用它的
    setter方法为它设置ArticleDatabase

  • 相关阅读:
    大话数据结构—散列表查找(哈希表)
    全栈project师?给把瑞士军刀你去砍鬼子好不好!?
    合作开发带来的思考
    女码农献丑-企业智能机器人客服(图灵机器人)
    Elasticsearch聚合 之 Date Histogram聚合
    Elasticsearch聚合 之 Terms
    Elasticsearch聚合初探——metric篇
    AngularJS API之$injector ---- 依赖注入
    AngularJS API之extend扩展对象
    AngularJS API之equal比较对象
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/6807209.html
Copyright © 2011-2022 走看看