精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

一文淺談Mockito使用

開發 前端
當我們的待測類開發完成而依賴的類的實現還沒有開發完成。此時,我們就可以用到我們的Mock測試,模擬我們依賴類的返回值,使我們的待測類與依賴類解耦。這樣,我們就可以對我們的待測類進行單元測了。

一、前期準備~

1、準備工作

<!--mockito依賴-->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.7.19</version>
    <scope>test</scope>
</dependency>
<!-- junit依賴 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

2、入門知識

1)Mockito:簡單輕量級的做mocking測試的框架;
2)mock對象:在調試期間用來作為真實對象的替代品;
3)mock測試:在測試過程中,對那些不容易構建的對象用一個虛擬對象來代替測試的方法就叫mock測試;
4)stub:打樁,就是為mock對象的方法指定返回值(可拋出異常);
5)verify:行為驗證,驗證指定方法調用情況(是否被調用,調用次數等);

3、五分鐘入門Demo

@Test
public void test0() {
    //1、創建mock對象(模擬依賴的對象)
    final List mock = Mockito.mock(List.class);

    //2、使用mock對象(mock對象會對接口或類的方法給出默認實現)
    System.out.println("mock.add result => " + mock.add("first"));  //false
    System.out.println("mock.size result => " + mock.size());       //0

    //3、打樁操作(狀態測試:設置該對象指定方法被調用時的返回值)
    Mockito.when(mock.get(0)).thenReturn("second");
    Mockito.doReturn(66).when(mock).size();

    //3、使用mock對象的stub(測試打樁結果)
    System.out.println("mock.get result => " + mock.get(0));    //second
    System.out.println("mock.size result => " + mock.size());   //66

    //4、驗證交互 verification(行為測試:驗證方法調用情況)
    Mockito.verify(mock).get(Mockito.anyInt());
    Mockito.verify(mock, Mockito.times(2)).size();

    //5、驗證返回的結果(這是JUnit的功能)
    assertEquals("second", mock.get(0));
    assertEquals(66, mock.size());
}

二、讓我們開始學習吧!

1、行為驗證

?一旦mock對象被創建了,mock對象會記住所有的交互,然后你就可以選擇性的驗證你感興趣的交互,驗證不通過則拋出異常。

@Test
public void test1() {
    final List mockList = Mockito.mock(List.class);
    mockList.add("mock1");
    mockList.get(0);
    mockList.size();
    mockList.clear();
    // 驗證方法被使用(默認1次)
    Mockito.verify(mockList).add("mock1");
    // 驗證方法被使用1次
    Mockito.verify(mockList, Mockito.times(1)).get(0);
    // 驗證方法至少被使用1次
    Mockito.verify(mockList, Mockito.atLeast(1)).size();
    // 驗證方法沒有被使用
    Mockito.verify(mockList, Mockito.never()).contains("mock2");
    // 驗證方法至多被使用5次
    Mockito.verify(mockList, Mockito.atMost(5)).clear();
    // 指定方法調用超時時間
    Mockito.verify(mockList, timeout(100)).get(0);
    // 指定時間內需要完成的次數
    Mockito.verify(mockList, timeout(200).atLeastOnce()).size();
}

2、如何做一些測試樁stub

?默認情況下,所有的函數都有返回值。mock函數默認返回的是null,一個空的集合或者一個被對象類型包裝的內置類型,例如0、false對應的對象類型為Integer、Boolean;

?一旦測試樁函數被調用,該函數將會一致返回固定的值;

?對于 static 和 final 方法, Mockito 無法對其 when(…).thenReturn(…) 操作。

@Test
public void test2() {
    //靜態導入,減少代碼量:import static org.mockito.Mockito.*;
    final ArrayList mockList = mock(ArrayList.class);

    // 設置方法調用返回值
    when(mockList.add("test2")).thenReturn(true);
    doReturn(true).when(mockList).add("test2");
    System.out.println(mockList.add("test2"));  //true

    // 設置方法調用拋出異常
    when(mockList.get(0)).thenThrow(new RuntimeException());
    doThrow(new RuntimeException()).when(mockList).get(0);
    System.out.println(mockList.get(0));    //throw RuntimeException

    // 無返回方法打樁
    doNothing().when(mockList).clear();

    // 為回調做測試樁(對方法返回進行攔截處理)
    final Answer<String> answer = new Answer<String>() {
        @Override
        public String answer(InvocationOnMock invocationOnMock) throws Throwable {
            final List mock = (List) invocationOnMock.getMock();
            return "mock.size result => " + mock.size();
        }
    };
    when(mockList.get(1)).thenAnswer(answer);
    doAnswer(answer).when(mockList).get(1);
    System.out.println(mockList.get(1));    //mock.size result => 0

    // 對同一方法多次打樁,以最后一次為準
    when(mockList.get(2)).thenReturn("test2_1");
    when(mockList.get(2)).thenReturn("test2_2");
    System.out.println(mockList.get(2));    //test2_2
    System.out.println(mockList.get(2));    //test2_2

    // 設置多次調用同類型結果
    when(mockList.get(3)).thenReturn("test2_1", "test2_2");
    when(mockList.get(3)).thenReturn("test2_1").thenReturn("test2_2");
    System.out.println(mockList.get(3));    //test2_1
    System.out.println(mockList.get(3));    //test2_2

    // 為連續調用做測試樁(為同一個函數調用的不同的返回值或異常做測試樁)
    when(mockList.get(4)).thenReturn("test2").thenThrow(new RuntimeException());
    doReturn("test2").doThrow(new RuntimeException()).when(mockList).get(4);
    System.out.println(mockList.get(4));    //test2
    System.out.println(mockList.get(4));    //throw RuntimeException

    // 無打樁方法,返回默認值
    System.out.println(mockList.get(99));    //null
}

3、參數匹配器

?參數匹配器使驗證和測試樁變得更靈活;

?為了合理的使用復雜的參數匹配,使用equals()與anyX() 的匹配器會使得測試代碼更簡潔、簡單。有時,會迫使你重構代碼以使用equals()匹配或者實現equals()函數來幫助你進行測試;

?如果你使用參數匹配器,所有參數都必須由匹配器提供;

?支持自定義參數匹配器;

@Test
public void test3() {
    final Map mockMap = mock(Map.class);

    // 正常打樁測試
    when(mockMap.get("key")).thenReturn("value1");
    System.out.println(mockMap.get("key"));     //value1

    // 為靈活起見,可使用參數匹配器
    when(mockMap.get(anyString())).thenReturn("value2");
    System.out.println(mockMap.get(anyString()));   //value2
    System.out.println(mockMap.get("test_key"));    //value2
    System.out.println(mockMap.get(0)); //null

    // 多個入參時,要么都使用參數匹配器,要么都不使用,否則會異常
    when(mockMap.put(anyString(), anyInt())).thenReturn("value3");
    System.out.println(mockMap.put("key3", 3));     //value3
    System.out.println(mockMap.put(anyString(), anyInt()));     //value3
    System.out.println(mockMap.put("key3", anyInt()));    //異常

    // 行為驗證時,也支持使用參數匹配器
    verify(mockMap, atLeastOnce()).get(anyString());
    verify(mockMap).put(anyString(), eq(3));

    // 自定義參數匹配器
    final ArgumentMatcher<ArgumentTestRequest> myArgumentMatcher = new ArgumentMatcher<ArgumentTestRequest>() {
        @Override
        public boolean matches(ArgumentTestRequest request) {
            return "name".equals(request.getName()) || "value".equals(request.getValue());
        }
    };
    // 自定義參數匹配器使用
    final ArgumentTestService mock = mock(ArgumentTestService.class);
    when(mock.argumentTestMethod(argThat(myArgumentMatcher))).thenReturn("success");
    doReturn("success").when(mock).argumentTestMethod(argThat(myArgumentMatcher));
    System.out.println(mock.argumentTestMethod(new ArgumentTestRequest("name", "value")));  // success
    System.out.println(mock.argumentTestMethod(new ArgumentTestRequest()));     //null
}

4、執行順序驗證

?驗證執行順序是非常靈活的-你不需要一個一個的驗證所有交互,只需要驗證你感興趣的對象即可;

?你可以僅通過那些需要驗證順序的mock對象來創建InOrder對象;

@Test
public void test4() {
    // 驗證同一個對象多個方法的執行順序
    final List mockList = mock(List.class);
    mockList.add("first");
    mockList.add("second");
    final InOrder inOrder = inOrder(mockList);
    inOrder.verify(mockList).add("first");
    inOrder.verify(mockList).add("second");

    // 驗證多個對象多個方法的執行順序
    final List mockList1 = mock(List.class);
    final List mockList2 = mock(List.class);
    mockList1.get(0);
    mockList1.get(1);
    mockList2.get(0);
    mockList1.get(2);
    mockList2.get(1);
    final InOrder inOrder1 = inOrder(mockList1, mockList2);
    inOrder1.verify(mockList1).get(0);
    inOrder1.verify(mockList1).get(2);
    inOrder1.verify(mockList2).get(1);
}

5、確保交互(interaction)操作不會執行在mock對象上

?一些用戶可能會在頻繁地使用verifyNoMoreInteractions(),甚至在每個測試函數中都用。但是verifyNoMoreInteractions()并不建議在每個測試函數中都使用;

?verifyNoMoreInteractions()在交互測試套件中只是一個便利的驗證,它的作用是當你需要驗證是否存在冗余調用時;

@Test
public void test5() {
    // 驗證某個交互是否從未被執行
    final List mock = mock(List.class);
    mock.add("first");
    verify(mock, never()).add("test5");   //通過
    verify(mock, never()).add("first");  //異常

    // 驗證mock對象沒有交互過
    final List mock1 = mock(List.class);
    final List mock2 = mock(List.class);
    verifyZeroInteractions(mock1);  //通過
    verifyNoMoreInteractions(mock1, mock2); //通過
    verifyZeroInteractions(mock, mock2);  //異常

    // 注意:可能只想驗證前面的邏輯,但是加上最后一行,會導致出現異常。建議使用方法層面的驗證,如:never();
    //      在驗證是否有冗余調用的時候,可使用此種方式。如下:
    final List mockList = mock(List.class);
    mockList.add("one");
    mockList.add("two");
    verify(mockList).add("one");    // 通過
    verify(mockList, never()).get(0);    //通過
    verifyZeroInteractions(mockList);   //異常
}

6、使用注解簡化mock對象創建

注意!下面這句代碼需要在運行測試函數之前被調用,一般放到測試類的基類或者test runner中:

MockitoAnnotations.initMocks(this);

也可以使用內置的runner: MockitoJUnitRunner 或者一個rule : MockitoRule;

// 代替 mock(ArgumentTestService.class) 創建mock對象;
@Mock
private ArgumentTestService argumentTestService;
// 若改注解修飾的對象有成員變量,@Mock定義的mock對象會被自動注入;
@InjectMocks
private MockitoAnnotationServiceImpl mockitoAnnotationService;

@Test
public void test6() {
    // 注意!下面這句代碼需要在運行測試函數之前被調用,一般放到測試類的基類或者test runner中;
    MockitoAnnotations.initMocks(this);
    when(argumentTestService.argumentTestMethod(new ArgumentTestRequest())).thenReturn("success");
    System.out.println(argumentTestService.argumentTestMethod(new ArgumentTestRequest()));  //success
    System.out.println(mockitoAnnotationService.mockitoAnnotationTestMethod()); //null
}

7、監控真實對象(部分mock)

?可以為真實對象創建一個監控(spy)對象。當你使用這個spy對象時真實的對象也會也調用,除非它的函數被stub了;

?盡量少使用spy對象,使用時也需要小心形式,例如spy對象可以用來處理遺留代碼;

?stub語法中同樣提供了部分mock的方法,可以調用真實的方法;

完全mock:

上文講的內容是完全mock,即創建的mock對象與真實對象無關,mock對象的方法默認都是基本的實現,返回基本類型。可基于接口、實現類創建mock對象。

部分mock:

所謂部分mock,即創建的mock對象時基于真實對象的,mock對象的方法都是默認使用真實對象的方法,除非stub之后,才會以stub為準。基于實現類創建mock對象,否則在沒有stub的情況下,調用真實方法時,會出現異常。

注意點:

Mockito并不會為真實對象代理函數調用,實際上它會拷貝真實對象。因此如果你保留了真實對象并且與之交互,不要期望從監控對象得到正確的結果。 當你在監控對象上調用一個沒有被stub的函數時并不會調用真實對象的對應函數,你不會在真實對象上看到任何效果

@Test
public void test7() {
    // stub部分mock(stub中使用真實調用)。注意:需要mock實現類,否則會有異常
    final StubTestService stubTestService = mock(StubTestServiceImpl.class);
    when(stubTestService.stubTestMethodA("paramA")).thenCallRealMethod();
    doCallRealMethod().when(stubTestService).stubTestMethodB();
    System.out.println(stubTestService.stubTestMethodA("paramA"));  //stubTestMethodA is called, param = paramA
    System.out.println(stubTestService.stubTestMethodB());  //stubTestMethodB is called
    System.out.println(stubTestService.stubTestMethodC());  //null

    // spy部分mock
    final LinkedList<String> linkedList = new LinkedList();
    final LinkedList spy = spy(linkedList);
    spy.add("one");
    spy.add("two");
    doReturn(100).when(spy).size();
    when(spy.get(0)).thenReturn("one_test");
    System.out.println(spy.size()); //100
    System.out.println(spy.get(0)); //one_test
    System.out.println(spy.get(1)); //two

    // spy可以類比AOP。在spy中,由于默認是調用真實方法,所以第二種寫法不等價于第一種寫法,不推薦這種寫法。
    doReturn("two_test").when(spy).get(2);
    when(spy.get(2)).thenReturn("two_test"); //異常 java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
    System.out.println(spy.get(2));   //two_test

    // spy對象只是真實對象的復制,真實對象的改變不會影響spy對象
    final List<String> arrayList = new ArrayList<>();
    final List<String> spy1 = spy(arrayList);
    spy1.add(0, "one");
    System.out.println(spy1.get(0));    //one
    arrayList.add(0, "list1");
    System.out.println(arrayList.get(0));   //list1
    System.out.println(spy1.get(0));    //one

    // 若對某個方法stub之后,又想調用真實的方法,可以使用reset(spy)
    final ArrayList<String> arrayList1 = new ArrayList<>();
    final ArrayList<String> spy2 = spy(arrayList1);
    doReturn(100).when(spy2).size();
    System.out.println(spy2.size());    //100
    reset(spy2);
    System.out.println(spy2.size());    //0
}

8、@Mock 和 @Spy的使用

?@Mock 等價于 Mockito.mock(Object.class);

?@Spy 等價于 Mockito.spy(obj);

區分是mock對象還是spy對象:
Mockito.mockingDetails(someObject).isMock();
Mockito.mockingDetails(someObject).isSpy();

@Mock
private StubTestService stubTestService;
@Spy
private StubTestServiceImpl stubTestServiceImpl;
@Spy
private StubTestService stubTestServiceImpl1 = new StubTestServiceImpl();
@Test
public void test8() {
    MockitoAnnotations.initMocks(this);
    // mock對象返回默認
    System.out.println(stubTestService.stubTestMethodB());  //null
    // spy對象調用真實方法
    System.out.println(stubTestServiceImpl.stubTestMethodC());  //stubTestMethodC is called
    System.out.println(stubTestServiceImpl1.stubTestMethodA("spy"));  //stubTestMethodA is called, param = spy

    // 區分是mock對象還是spy對象
    System.out.println(mockingDetails(stubTestService).isMock());   //true
    System.out.println(mockingDetails(stubTestService).isSpy());    //false
    System.out.println(mockingDetails(stubTestServiceImpl).isSpy());    //true
}

9、ArgumentCaptor(參數捕獲器)捕獲方法參數進行驗證。(可代替參數匹配器使用)

?在某些場景中,不光要對方法的返回值和調用進行驗證,同時需要驗證一系列交互后所傳入方法的參數。那么我們可以用參數捕獲器來捕獲傳入方法的參數進行驗證,看它是否符合我們的要求。

ArgumentCaptor介紹

通過ArgumentCaptor對象的forClass(Class

ArgumentCaptor的Api

argument.capture() 捕獲方法參數

argument.getValue() 獲取方法參數值,如果方法進行了多次調用,它將返回最后一個參數值

argument.getAllValues() 方法進行多次調用后,返回多個參數值

@Test
public void test9() {
    List mock = mock(List.class);
    List mock1 = mock(List.class);
    mock.add("John");
    mock1.add("Brian");
    mock1.add("Jim");
    // 獲取方法參數
    ArgumentCaptor argument = ArgumentCaptor.forClass(String.class);
    verify(mock).add(argument.capture());
    System.out.println(argument.getValue());    //John

    // 多次調用獲取最后一次
    ArgumentCaptor argument1 = ArgumentCaptor.forClass(String.class);
    verify(mock1, times(2)).add(argument1.capture());
    System.out.println(argument1.getValue());    //Jim

    // 獲取所有調用參數
    System.out.println(argument1.getAllValues());    //[Brian, Jim]
}

10、簡化 ArgumentCaptor 的創建

@Mock
private List<String> captorList;
@Captor
private ArgumentCaptor<String> argumentCaptor;
@Test
public void test10() {
    MockitoAnnotations.initMocks(this);
    captorList.add("cap1");
    captorList.add("cap2");
    System.out.println(captorList.size());
    verify(captorList, atLeastOnce()).add(argumentCaptor.capture());
    System.out.println(argumentCaptor.getAllValues());
}

11、高級特性:自定義驗證失敗信息

@Test
public void test11() {
    final ArrayList arrayList = mock(ArrayList.class);
    arrayList.add("one");
    arrayList.add("two");

    verify(arrayList, description("size()沒有調用")).size();
    // org.mockito.exceptions.base.MockitoAssertionError: size()沒有調用

    verify(arrayList, timeout(200).times(3).description("驗證失敗")).add(anyString());
    //org.mockito.exceptions.base.MockitoAssertionError: 驗證失敗
}

12、高級特性:修改沒有測試樁的調用的默認返回值

?可以指定策略來創建mock對象的返回值。這是一個高級特性,通常來說,你不需要寫這樣的測試;

?它對于遺留系統來說是很有用處的。當你不需要為函數調用打樁時你可以指定一個默認的answer;

@Test
public void test12(){
    // 創建mock對象、使用默認返回
    final ArrayList mockList = mock(ArrayList.class);
    System.out.println(mockList.get(0));    //null

    // 這個實現首先嘗試全局配置,如果沒有全局配置就會使用默認的回答,它返回0,空集合,null,等等。
    // 參考返回配置:ReturnsEmptyValues
    mock(ArrayList.class, Answers.RETURNS_DEFAULTS);

    // ReturnsSmartNulls首先嘗試返回普通值(0,空集合,空字符串,等等)然后它試圖返回SmartNull。
    // 如果最終返回對象,那么會簡單返回null。一般用在處理遺留代碼。
    // 參考返回配置:ReturnsMoreEmptyValues
    mock(ArrayList.class, Answers.RETURNS_SMART_NULLS);

    // 未stub的方法,會調用真實方法。
    //    注1:存根部分模擬使用時(mock.getSomething ()) .thenReturn (fakeValue)語法將調用的方法。對于部分模擬推薦使用doReturn語法。
    //    注2:如果模擬是序列化反序列化,那么這個Answer將無法理解泛型的元數據。
    mock(ArrayList.class, Answers.CALLS_REAL_METHODS);

    // 深度stub,用于嵌套對象的mock。參考:https://www.cnblogs.com/Ming8006/p/6297333.html
    mock(ArrayList.class, Answers.RETURNS_DEEP_STUBS);

    // ReturnsMocks首先嘗試返回普通值(0,空集合,空字符串,等等)然后它試圖返回mock。
    // 如果返回類型不能mocked(例如是final)然后返回null。
    mock(ArrayList.class, Answers.RETURNS_MOCKS);

    //  mock對象的方法調用后,可以返回自己(類似builder模式)
    mock(ArrayList.class, Answers.RETURNS_SELF);

    // 自定義返回
    final Answer<String> answer = new Answer<String>() {
        @Override
        public String answer(InvocationOnMock invocation) throws Throwable {
            return "test_answer";
        }
    };
    final ArrayList mockList1 = mock(ArrayList.class, answer);
    System.out.println(mockList1.get(0));   //test_answer
}

三、學習了這么多,牛刀小試一下!

測試實體類

@Data
public class User {

    /**
     * 姓名,登錄密碼
     */

持久層DAO

public interface UserDao {

    /**
     * 根據name查找user
     * @param name
     * @return
     */
    User getUserByName(String name);

    /**
     * 保存user
     * @param user
     * @return
     */
    Integer saveUser(User user);
}

業務層Service接口

public interface UserService {

    /**
     * 根據name查找user
     * @param name
     * @return
     */
    User getUserByName(String name);

    /**
     * 保存user
     * @param user
     * @return
     */
    Integer saveUser(User user);
}

業務層Serive實現類

@Service
public class UserServiceImpl implements UserService {

    //userDao
    @Autowired
    private UserDao userDao;

    /**
     * 根據name查找user
     * @param name
     * @return
     */
    @Override
    public User getUserByName(String name) {
        try {
            return userDao.getUserByName(name);
        } catch (Exception e) {
            throw new RuntimeException("查詢user異常");
        }
    }

    /**
     * 保存user
     * @param user
     * @return
     */
    @Override
    public Integer saveUser(User user) {
        if (userDao.getUserByName(user.getName()) != null) {
            throw new RuntimeException("用戶名已存在");
        }
        try {
            return userDao.saveUser(user);
        } catch (Exception e) {
            throw new RuntimeException("保存用戶異常");
        }
    }
}

現在我們的Service寫好了,想要單元測試一下,但是Dao是其他人開發的,目前還沒有寫好,那我們如何測試呢?

public class UserServiceTest {

    /**
     * Mock測試:根據name查詢user
     */
    @Test
    public void getUserByNameTest() {
        // mock對象
        final UserDao userDao = mock(UserDao.class);
        final UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao);

        // stub調用
        final User user = new User();
        user.setName("admin");
        user.setPassword("pass");
        when(userDao.getUserByName("admin")).thenReturn(user);

        // 執行待測試方法
        final User user1 = userService.getUserByName("admin");
        System.out.println("查詢結果:" + JacksonUtil.obj2json(user1));  //查詢結果:{"name":"admin","password":"pass"}

        // 驗證mock對象交互
        verify(userDao).getUserByName(anyString());

        // 驗證查詢結果
        Assert.assertNotNull("查詢結果為空!", user1);
        Assert.assertEquals("查詢結果錯誤!", "admin", user1.getName());
    }


    /**
     * Mock測試:保存user
     */
    @Mock
    private UserDao userDao;
    @InjectMocks
    private UserServiceImpl userService;
    @Test
    public void saveUserTest() throws Exception{
        // 執行注解初始化
        MockitoAnnotations.initMocks(this);

        // mock對象stub操作
        final User user = new User();
        user.setName("admin");
        user.setPassword("pass");
        when(userDao.getUserByName("admin")).thenReturn(user).thenReturn(null);
        when(userDao.saveUser(any(User.class))).thenReturn(1);

        // 驗證用戶名重復的情況
        try {
            userService.saveUser(user);
            throw new Exception();  //走到這里說明驗證失敗
        } catch (RuntimeException e) {
            System.out.println("重復用戶名保存失敗-測試通過");   //重復用戶名保存失敗-測試通過
        }
        verify(userDao).getUserByName("admin");

        // 驗證正常保存的情況
        user.setName("user");
        final Integer integer = userService.saveUser(user);
        System.out.println("保存結果:" + integer);  //保存結果:1
        Assert.assertEquals("保存失敗!", 1, integer.longValue());

        verify(userDao).saveUser(any(User.class));
        verify(userDao, times(2)).getUserByName(anyString());
    }

}

根據以上代碼我們可以知道,當我們的待測類開發完成而依賴的類的實現還沒有開發完成。此時,我們就可以用到我們的Mock測試,模擬我們依賴類的返回值,使我們的待測類與依賴類解耦。這樣,我們就可以對我們的待測類進行單元測了。

四、參考文檔及進一步學習~

  • Mockito英文版javadoc:https://javadoc.io/static/org.mockito/mockito-core/3.3.3/org/mockito/Mockito.html
  • Mockito中文文檔(部分):https://blog.csdn.net/bboyfeiyu/article/details/52127551#35
  • Mockito使用教程:https://www.cnblogs.com/Ming8006/p/6297333.html
  • 參數捕獲器使用:https://www.journaldev.com/21892/mockito-argumentcaptor-captor-annotation
  • 利用ArgumentCaptor(參數捕獲器)捕獲方法參數進行驗證:https://www.iteye.com/blog/hotdog-916364
  • 改變mock返回值:https://www.huangyunkun.com/2014/10/25/mockito-deep-stub-with-enum/
  • 五分鐘了解Mockito:https://www.iteye.com/blog/liuzhijun-1512780
  • 使用Mockito進行單元測試:https://www.iteye.com/blog/qiuguo0205-1443344
  • JUnit + Mockito 單元測試:https://blog.csdn.net/zhangxin09/article/details/42422643
  • Mockito中@Mock與@InjectMock:https://www.cnblogs.com/langren1992/p/9681600.html
  • mockito中兩種部分mock的實現,spy、callRealMethod:https://www.cnblogs.com/softidea/p/4204389.html
  • Mockito 中被 Mocked 的對象屬性及方法的默認值:https://www.cnblogs.com/fnlingnzb-learner/p/10635250.html
  • 單元測試工具之Mockito:https://blog.csdn.net/qq_32140971/article/details/90598454
  • 引入Mockito測試用@Spy和@Mock:https://blog.csdn.net/message_lx/article/details/83308114
  • Mockito初探(含實例):https://www.iteye.com/blog/sgq0085-2031319
  • 測試覆蓋率統計:https://blog.csdn.net/lvyuan1234/article/details/82836052?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
  • 測試覆蓋率無法統計解決:https://blog.csdn.net/zhanglei082319/article/details/81536398
責任編輯:武曉燕 來源: 今日頭條
相關推薦

2023-02-01 07:34:41

讀寫分離數據庫

2022-07-06 10:23:13

深度學習神經網絡

2021-07-23 11:35:49

架構運維技術

2021-08-13 05:50:01

ContainerdDockerKubernetes

2021-09-02 12:07:48

Swift 監聽系統Promise

2020-03-31 14:40:24

HashMap源碼Java

2024-04-12 12:19:08

語言模型AI

2020-08-27 07:34:50

Zookeeper數據結構

2023-12-27 07:40:43

HTTP服務器負載均衡

2025-10-20 09:20:06

2021-08-04 16:06:45

DataOps智領云

2020-10-26 09:18:50

RedisCluste

2022-03-24 08:51:48

Redis互聯網NoSQL

2023-12-22 19:59:15

2024-02-04 16:40:11

LLM人工智能AI

2020-08-31 06:54:37

注解脫敏ELK

2023-11-20 08:18:49

Netty服務器

2022-09-22 09:00:46

CSS單位

2021-03-22 10:05:59

netstat命令Linux

2018-09-28 14:06:25

前端緩存后端
點贊
收藏

51CTO技術棧公眾號

在线观看免费版| 欧美xxxxx少妇| 亚洲搞黄视频| 日本视频一区二区三区| 久久久99免费视频| 不许穿内裤随时挨c调教h苏绵| 岛国在线视频网站| 国产精品免费久久久久| 超碰97人人在线| 99成人精品视频| 国产精品mv在线观看| 亚洲欧洲av一区二区| 日韩av片免费观看| 日韩电影毛片| 亚洲激情一二三区| 日韩激情久久| 三级在线观看网站| 国内精品第一页| 日韩美女在线观看一区| 黄色一级免费视频| 日韩一区亚洲二区| 日韩电影中文字幕| 日本xxxx免费| 国产精品麻豆| 欧美日韩视频第一区| 六月丁香激情网| 污污片在线免费视频| 欧美激情在线一区二区| 久久人人爽爽人人爽人人片av| 国产视频手机在线观看| 秋霞午夜鲁丝一区二区老狼| 久久理论片午夜琪琪电影网| 国产午夜手机精彩视频| 欧美日韩黑人| 亚洲欧美成人在线| 影音先锋黄色资源| 中文字幕一区二区三区四区久久| 777午夜精品视频在线播放| 99视频在线免费| 性爽视频在线| 亚洲1区2区3区视频| 亚洲国产一二三精品无码| 日本中文在线观看| 国产精品久久久久久久浪潮网站| 人禽交欧美网站免费| 午夜小视频免费| 99麻豆久久久国产精品免费 | 91精品福利观看| 欧美午夜影院一区| 中文字幕网av| 日韩成人免费av| 欧美美女激情18p| 中文字幕中文在线| av在线国产精品| 欧美日本在线观看| 亚洲欧美aaa| 欧美日韩黄色| 日韩精品一区二区三区老鸭窝| 伊人成人免费视频| 999国产精品一区| 亚洲国产97在线精品一区| 亚洲天堂2024| 一区二区三区视频免费观看| 亚洲精品一区久久久久久| 91视频免费观看网站| 国产精品一线天粉嫩av| 在线看日韩欧美| 国产午夜精品理论片在线| 亚洲影视一区二区三区| 欧美激情中文网| 天海翼一区二区| 美女精品在线观看| 国产精品女主播| 99免费在线视频| 菠萝蜜视频在线观看一区| 久久精品99| 成人在线免费视频| 亚洲男同性恋视频| 加勒比成人在线| 在线观看欧美日韩电影| 精品视频色一区| 麻豆av免费看| 精品毛片免费观看| 欧美日韩福利视频| 五月天激情国产综合婷婷婷| 蜜桃视频一区二区三区在线观看| 成人国产精品久久久久久亚洲| 亚洲av无码国产综合专区| av在线播放不卡| 亚洲欧美99| 国产精品一区hongkong| 日本精品视频一区二区| 特黄特黄一级片| 性欧美lx╳lx╳| 另类天堂视频在线观看| 亚洲第一在线播放| 激情综合色丁香一区二区| 国产一区不卡在线观看| 日韩大片在线永久免费观看网站| 亚洲一二三四在线| 在线免费观看av的网站| 国产另类在线| 久久精品亚洲94久久精品| 青青草成人av| 精品系列免费在线观看| 精品国产乱码久久久久软件| 人人干在线视频| 香蕉av福利精品导航| 粉色视频免费看| 亚洲永久精品唐人导航网址| 欧美大片第1页| 免费看av在线| 2019国产精品| 18黄暴禁片在线观看| 亚洲福利影视| 亚洲天堂开心观看| 日操夜操天天操| 国产乱对白刺激视频不卡| 日韩和欧美的一区二区| 一区二区三区电影大全| 精品999在线播放| 欧美h片在线观看| 日本亚洲天堂网| 欧美日韩精品一区| av在线私库| 日韩欧美一级二级三级久久久| 18精品爽国产三级网站| 久久蜜桃精品| 麻豆成人小视频| f2c人成在线观看免费视频| 欧美日韩一级二级三级| 麻豆精品免费视频| 国产一区二区三区久久久久久久久| 99国产视频在线| 最新超碰在线| 91精品国产欧美日韩| 午夜激情福利电影| 热久久国产精品| 亚洲精品自在在线观看| 九九九伊在线综合永久| 亚洲人成绝费网站色www| 欧美一区二区激情视频| 91麻豆国产自产在线观看| av免费观看大全| 欧美电影免费网站| 97在线免费观看| 日韩一区av| 日本二三区不卡| www.99热| 久久精品国产亚洲一区二区三区 | 99国产精品免费视频观看| 国产精品久久久久久久电影| 在线视频婷婷| 91.com视频| 激情五月婷婷小说| 懂色av一区二区三区蜜臀| 波多野结衣av一区二区全免费观看| 日韩免费一级| 午夜精品福利电影| 清纯唯美亚洲色图| 在线视频一区二区三| 美国一级黄色录像| 国产一区二区免费看| 久久免费一级片| 女人抽搐喷水高潮国产精品| 欧美专区福利在线| jyzzz在线观看视频| 欧美日韩电影在线| 欧美日韩在线观看免费| 不卡视频一二三四| 久久综合久久色| 国产精品久久久久一区二区三区厕所 | 久久久影院一区二区三区| 成人香蕉视频| 日韩在线免费高清视频| 黄片毛片在线看| 色悠悠亚洲一区二区| 一本一本久久a久久| 国产老妇另类xxxxx| 青青青免费在线| 欧美日韩在线二区| av一区和二区| 人人鲁人人莫人人爱精品| 久久精品国产99国产精品澳门| 亚洲成人黄色片| 在线看日本不卡| 九九热精品在线观看| 91麻豆免费观看| 红桃视频 国产| 亚洲永久网站| 异国色恋浪漫潭| 欧美猛男做受videos| 4444kk亚洲人成电影在线| 五月天av在线| 欧美美最猛性xxxxxx| 久草在线青青草| 日韩免费在线观看| 亚洲婷婷久久综合| 亚洲国产日日夜夜| 久久一级免费视频| 97se亚洲国产综合自在线| 超碰人人草人人| 性娇小13――14欧美| 无码毛片aaa在线| 国产精品午夜一区二区三区| 国产精品自拍首页| 高清在线一区二区| 国产精品免费久久久久久| www555久久| 久久午夜a级毛片| 国产一级免费在线观看| 欧美精品一区二区久久久| 亚洲无码久久久久久久| 大桥未久av一区二区三区| 一区二区成人免费视频| 日本一区二区三区四区在线视频| 色哟哟视频在线| 国产麻豆精品theporn| 最近中文字幕一区二区| 亚洲欧美日韩视频二区| 国产夫妻自拍一区| 欧美成人日本| 制服丝袜综合日韩欧美| 精品国精品国产自在久国产应用 | 精品免费在线| 美媛馆国产精品一区二区| 视频精品二区| 亚洲自拍欧美另类| 日本午夜免费一区二区| 国产精品久久久久秋霞鲁丝| 国产精品迅雷| 97成人超碰免| 精精国产xxxx视频在线野外| 欧美激情精品久久久久久大尺度| 黄色动漫在线| 久久精品成人一区二区三区| 国产福利免费在线观看| 亚洲欧洲一区二区三区在线观看| 婷婷开心激情网| 日韩国产高清污视频在线观看| 日批视频在线播放| 亚洲国产精品久久久久秋霞不卡| 亚洲精品久久久久久久久久久久久久| 91精品国产黑色紧身裤美女| 国产精品久久久久精| 欧美丰满嫩嫩电影| 国产乱淫av免费| 欧美一区二区成人6969| 国产激情视频在线播放| 欧美成人a∨高清免费观看| 丰满人妻av一区二区三区| 亚洲国产成人精品女人久久久 | 精品一区二区三区视频在线播放| 成人黄色影片在线| 欧美成年网站| 国产乱码精品一区二区三区卡| 国产在线播放精品| 就去色蜜桃综合| av一区二区在线播放| 亚洲在线播放电影| 91精品国产自产拍在线观看蜜| 久久久无码中文字幕久...| 欧美成人综合| 国产成人无码精品久久久性色| 男人的天堂亚洲| 天堂网在线免费观看| 久久69国产一区二区蜜臀| 26uuu国产| 91麻豆国产香蕉久久精品| 日韩免费成人av| 综合婷婷亚洲小说| 男人天堂中文字幕| 欧美日韩精品在线播放| 最新中文字幕在线观看视频| 91精品一区二区三区在线观看| 成人av一区二区三区在线观看| 日韩成人在线视频观看| av网站在线播放| 欧美精品一区三区| 黄色成人免费网| 亚洲jizzjizz日本少妇| 亚洲另类av| 精品国产一区二区三区在线| 99精品免费视频| jizz欧美性11| 成人毛片视频在线观看| 久久久久久久毛片| 亚洲永久精品大片| 91黑人精品一区二区三区| 欧美一区二区三区啪啪| 久久av少妇| 欧美国产日韩一区二区三区| **在线精品| 国产精品二区二区三区| 欧美少妇性xxxx| 欧美视频在线免费播放| 另类小说一区二区三区| 五十路六十路七十路熟婆| 国产精品每日更新| 日本三级小视频| 日韩欧美一二三| av免费在线一区二区三区| 韩国国内大量揄拍精品视频| 国产成人精品一区二区三区免费| 国产嫩草一区二区三区在线观看 | 国产亚洲成aⅴ人片在线观看 | 欧美三级电影一区| 蜜臀久久99精品久久久| www.欧美精品| 国产日韩另类视频一区| 激情小说综合网| 欧美freesex交免费视频| 男女视频在线看| 91视频在线看| 久久久久久久国产精品毛片| 欧美无人高清视频在线观看| 头脑特工队2在线播放| 久久6精品影院| 亚洲精品成a人ⅴ香蕉片| 日韩欧美视频一区二区| 免费日韩一区二区| 美女久久久久久久久| 一区二区免费在线| 精品久久久中文字幕人妻| 日韩在线视频网| 国产精品亚洲d| 欧美日产一区二区三区在线观看| 亚洲黑丝一区二区| 国产ts在线观看| 一区二区三区高清不卡| 国产熟女一区二区三区五月婷| 最近中文字幕mv在线一区二区三区四区| 亚洲天堂手机| 久久综合久久久| 久久国产欧美| 亚洲av综合一区二区| 欧美色播在线播放| 亚洲人视频在线观看| 4388成人网| 亚洲区小说区图片区qvod按摩| 午夜精品久久久久久久无码| proumb性欧美在线观看| 五月婷婷激情网| 精品五月天久久| 欧美大胆成人| 日韩欧美在线一区二区| 男男成人高潮片免费网站| jizz中文字幕| 欧美老女人第四色| caopon在线免费视频| 99re在线视频观看| 激情综合中文娱乐网| 91丝袜在线观看| 岛国精品视频在线播放| 青青青免费视频在线2| 国产精品v日韩精品| 色乱码一区二区三区网站| 欧美午夜精品理论片| 亚洲影院免费观看| 亚洲人视频在线观看| 国产精品国产自产拍高清av水多 | 欧美三级一级片| 久久久精品国产免大香伊| 国产精品xxxxxx| 久久精品小视频| 麻豆一区二区麻豆免费观看| 成人在线看视频| 亚洲欧洲日韩综合一区二区| 性生交大片免费看女人按摩| 97精品国产91久久久久久| 国产欧美日韩视频在线| 亚洲图色中文字幕| 亚洲综合在线视频| 欧美精品a∨在线观看不卡| 国产精品青青在线观看爽香蕉 | 国产视频第一页| 51午夜精品视频| 天天精品视频| 亚洲欧美在线不卡| 欧美三级欧美一级| 欧美韩日亚洲| 日韩欧美国产二区| 国产精品888| 国产午夜麻豆影院在线观看| 精品国产一区二区三区久久狼黑人| 成人h动漫精品一区二区器材| 欧美极品欧美精品欧美图片| 亚洲欧美综合另类在线卡通| 天天干天天插天天操| 国产伦精品免费视频| 在线成人欧美| 日韩欧美在线视频播放| 精品国产91久久久久久久妲己| 国产成人精品一区二三区在线观看| 国产 欧美 日本| 日本一区二区三区四区| 黑人精品一区二区三区| 成人激情在线播放| 国产免费成人| 精品小视频在线观看|