【項目經驗】Mockito教程

1、教程

轉載:https://blog.csdn.net/sdyy321/article/details/38757135/html

官網: http://mockito.orgjava

源碼分析:http://www.javashuo.com/article/p-cspppwgm-gn.htmlgit

屬性默認值:https://yanbin.blog/mockito-mocked-default-fields-method-returns/#more-8359github

API文檔:http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.htmlspring

項目源碼:https://github.com/mockito/mockito
使用案例:https://blog.csdn.net/Christopher36/article/details/81036683app

首先添加maven依賴maven

 <dependency>
          <groupId>org.mockito</groupId>
          <artifactId>mockito-all</artifactId>
          <version>1.9.5</version>
          <scope>test</scope>
      </dependency>
View Code

固然mockito須要junit配合使用ide

<dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
      </dependency>
View Code

而後爲了使代碼更簡潔,最好在測試類中導入靜態資源源碼分析

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
View Code

下面咱們開始使用mockito來作測試單元測試

package com.spring.sxf.mockito;



import org.junit.Test;
import org.mockito.ArgumentMatcher;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.exceptions.verification.NoInteractionsWanted;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;


import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

/**
 * @author <a href="mailto:shangxiaofei@meituan.com">尚曉飛</a>
 * @date 7:52 PM 2019/4/26
 */
public class MockitoTest {

    //驗證要mock的對象,是否發生過某些行爲
    @Test
    public void testArrayList() {
        //生成mock對象
        ArrayList<String> mockList = mock(ArrayList.class);
        //使用mock的對象
        mockList.add("SXF");
        mockList.add("456");


        //驗證行爲add("SXF"),add("123")是否發生過
        verify(mockList).add("SXF");
        verify(mockList).add("456");
    }

    //模擬咱們所指望的結果
    @Test
    public void testArrayList1() {
        //生成mock對象
        ArrayList<String> mockList = mock(ArrayList.class);
        //
        when(mockList.size()).thenReturn(2);
        int size = mockList.size();
        assertEquals(2, size);


    }

    //模擬咱們指望的結果
    @Test(expected = NullPointerException.class)
    public void when_thenThrow() throws IOException {
        OutputStream outputStream = mock(OutputStream.class);
        OutputStreamWriter writer = new OutputStreamWriter(outputStream);
        //預設當流關閉時拋出異常
        doThrow(new IOException()).when(outputStream).close();
        outputStream.close();
    }

    //參數匹配
    @Test
    public void with_arguments() {
        Comparable comparable = mock(Comparable.class);
        //預設根據不一樣的參數返回不一樣的結果
        when(comparable.compareTo("Test")).thenReturn(1);
        when(comparable.compareTo("Omg")).thenReturn(2);
        assertEquals(1, comparable.compareTo("Test"));
        assertEquals(2, comparable.compareTo("Omg"));
        //對於沒有預設的狀況會返回默認值
        assertEquals(0, comparable.compareTo("Not stub"));
    }


    //除了匹配製定參數外,還能夠匹配本身想要的任意參數
    @Test
    public void with_unspecified_arguments() {
        List list = mock(List.class);
        //匹配任意參數
        when(list.get(anyInt())).thenReturn(1);
        when(list.contains(argThat(new IsValid()))).thenReturn(true);
        assertEquals(1, list.get(1));
        assertEquals(1, list.get(999));
        assertTrue(list.contains(1));
        assertTrue(!list.contains(3));
    }

    private class IsValid extends ArgumentMatcher<List> {
        @Override
        public boolean matches(Object o) {
            return (Integer) o == 1 || (Integer) o == 2;
        }
    }


    //須要注意的是若是你使用了參數匹配,那麼全部的參數都必須經過matchers來匹配
    @Test
    public void all_arguments_provided_by_matchers() {
        Comparator comparator = mock(Comparator.class);
        comparator.compare("nihao", "hello");
        //若是你使用了參數匹配,那麼全部的參數都必須經過matchers來匹配
        verify(comparator).compare(anyString(), eq("hello"));
        //下面的爲無效的參數匹配使用
        //verify(comparator).compare(anyString(),"hello");
    }

    //驗證確切的調用次數
    @Test
    public void verifying_number_of_invocations() {
        List list = mock(List.class);
        list.add(1);
        list.add(2);
        list.add(2);
        list.add(3);
        list.add(3);
        list.add(3);
        //驗證是否被調用一次,等效於下面的times(1)
        verify(list).add(1);
        verify(list, times(1)).add(1);
        //驗證是否被調用2次
        verify(list, times(2)).add(2);
        //驗證是否被調用3次
        verify(list, times(3)).add(3);
        //驗證是否從未被調用過
        verify(list, never()).add(4);
        //驗證至少調用一次
        verify(list, atLeastOnce()).add(1);
        //驗證至少調用2次
        verify(list, atLeast(2)).add(2);
        //驗證至多調用3次
        verify(list, atMost(3)).add(3);

    }

    //模擬方法體拋出異常
    @Test(expected = RuntimeException.class)
    public void doThrow_when() {
        List list = mock(List.class);
        doThrow(new Exception()).when(list).add(1);
        list.add(1);
    }

    //驗證執行順序
    @Test
    public void verification_in_order() {
        List list = mock(List.class);
        List list2 = mock(List.class);
        list.add(1);
        list2.add("hello");
        list.add(2);
        list2.add("world");
        //將須要排序的mock對象放入InOrder
        InOrder inOrder = inOrder(list, list2);
        //下面的代碼不能顛倒順序,驗證執行順序
        inOrder.verify(list).add(1);
        inOrder.verify(list2).add("hello");
        inOrder.verify(list).add(2);
        inOrder.verify(list2).add("world");
    }


    //確保模擬對象上無互動發生
    @Test
    public void verify_interaction(){
        List list = mock(List.class);
        List list2 = mock(List.class);
        List list3 = mock(List.class);
        list.add(1);
        verify(list).add(1);
        verify(list,never()).add(2);
        //驗證零互動行爲
        verifyZeroInteractions(list2,list3);
    }

    //找出冗餘的互動(即未被驗證到的)
    @Test(expected = NoInteractionsWanted.class)
    public void find_redundant_interaction(){
        List list = mock(List.class);
        list.add(1);
        list.add(2);
        verify(list,times(2)).add(anyInt());
        //檢查是否有未被驗證的互動行爲,由於add(1)和add(2)都會被上面的anyInt()驗證到,因此下面的代碼會經過
        verifyNoMoreInteractions(list);

        List list2 = mock(List.class);
        list2.add(1);
        list2.add(2);
        verify(list2).add(1);
        //檢查是否有未被驗證的互動行爲,由於add(2)沒有被驗證,因此下面的代碼會失敗拋出異常
        verifyNoMoreInteractions(list2);
    }

    //九、使用註解來快速模擬
    //在上面的測試中咱們在每一個測試方法裏都mock了一個List對象,爲了不重複的mock,是測試類更具備可讀性,咱們可使用下面的註解方式來快速模擬對象:
    @Mock
    private List mockList;
    //構造方法
    public MockitoTest(){
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void shorthand(){
        mockList.add(1);
        verify(mockList).add(1);
    }


}
View Code

 

2、spring項目+單元測試使用mockito

1、單元測試類

@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring/applicationContext.xml"})
public class RouteServiceTest {

    //要被mock的接口
    @Mock
    private IChannelQueueCountService iChannelQueueCountService;

    //使用了要被mock對象的類,須要注入mock對象
    @InjectMocks
    @Autowired
    private ChannelChooseService channelChooseService;

    //發起調用的接口
    @Autowired
    private TRouteService.Iface tRouteService;

    //mock對象注入
    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void test01() throws TException {

        when(iChannelQueueCountService.getChannelQueueCounts(anyList(), anyLong(), anyBoolean())).thenAnswer(new Answer<Map<Integer, Integer>>() {

            @Override
            public Map<Integer, Integer> answer(InvocationOnMock invocation) throws Throwable {
                HashMap<Integer, Integer> map = new HashMap<>();
                Object[] args = invocation.getArguments();
                List<Integer> ids = (List<Integer>) args[0];
                for (Integer id : ids) {
                    map.put(id, 1);
                }
                return map;
            }
        });


        TChooseChannelReq tChooseChannelReq = new TChooseChannelReq(56789, 219, 999, 6000, "shangxiaofei", "6212260200052453285", TPPType.PRIVATE, 10, 34, 99999);
        TChooseChannelRes res = tRouteService.chooseChannel(tChooseChannelReq);
        System.out.println("接口調用返回:" + res.getLogicalChannelId());

    }
}
View Code
相關文章
相關標籤/搜索