国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

單元測試?yán)鳌职咽纸棠闶褂肕ockito

這篇具有很好參考價值的文章主要介紹了單元測試?yán)鳌职咽纸棠闶褂肕ockito。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

作者:京東零售 秦浩然

從你成為開發(fā)人員的那一天起,寫單元測試終究是你逃不開的宿命!那開發(fā)人員為什么不喜歡寫單元測試呢?究其原因,無外乎是依賴。依賴其他的服務(wù)、依賴運行的環(huán)境、等等,各種依賴都成為了我們寫單元測試的絆腳石。那現(xiàn)在有個單元測試?yán)骺梢詭臀覀兘鉀Q依賴的問題,你愿意使用一下嗎?你愿意!那就是我們要學(xué)習(xí)的Mockito

一、前期準(zhǔn)備~

1、準(zhǔn)備工作

<!--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對象:在調(diào)試期間用來作為真實對象的替代品;
3)mock測試:在測試過程中,對那些不容易構(gòu)建的對象用一個虛擬對象來代替測試的方法就叫mock測試;
4)stub:打樁,就是為mock對象的方法指定返回值(可拋出異常);
5)verify:行為驗證,驗證指定方法調(diào)用情況(是否被調(diào)用,調(diào)用次數(shù)等);

3、五分鐘入門Demo

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

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

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

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

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

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

二、讓我們開始學(xué)習(xí)吧!

1、行為驗證

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

@Test
public void test1() {
    final List mockList = Mockito.mock(List.class);
    mockList.add("mock1");
    mockList.get(0);
    mockList.size();
    mockList.clear();
    // 驗證方法被使用(默認(rèn)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();
    // 指定方法調(diào)用超時時間
    Mockito.verify(mockList, timeout(100)).get(0);
    // 指定時間內(nèi)需要完成的次數(shù)
    Mockito.verify(mockList, timeout(200).atLeastOnce()).size();
}

2、如何做一些測試樁stub

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

? 一旦測試樁函數(shù)被調(diào)用,該函數(shù)將會一致返回固定的值;

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

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

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

    // 設(shè)置方法調(diào)用拋出異常
    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();

    // 為回調(diào)做測試樁(對方法返回進行攔截處理)
    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

    // 對同一方法多次打樁,以最后一次為準(zhǔn)
    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

    // 設(shè)置多次調(diào)用同類型結(jié)果
    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

    // 為連續(xù)調(diào)用做測試樁(為同一個函數(shù)調(diào)用的不同的返回值或異常做測試樁)
    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

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

3、參數(shù)匹配器

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

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

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

? 支持自定義參數(shù)匹配器;

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

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

    // 為靈活起見,可使用參數(shù)匹配器
    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

    // 多個入?yún)r,要么都使用參數(shù)匹配器,要么都不使用,否則會異常
    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()));    //異常

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

    // 自定義參數(shù)匹配器
    final ArgumentMatcher<ArgumentTestRequest> myArgumentMatcher = new ArgumentMatcher<ArgumentTestRequest>() {
        @Override
        public boolean matches(ArgumentTestRequest request) {
            return "name".equals(request.getName()) || "value".equals(request.getValue());
        }
    };
    // 自定義參數(shù)匹配器使用
    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、執(zhí)行順序驗證

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

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

@Test
public void test4() {
    // 驗證同一個對象多個方法的執(zhí)行順序
    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");

    // 驗證多個對象多個方法的執(zhí)行順序
    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)操作不會執(zhí)行在mock對象上

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

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

@Test
public void test5() {
    // 驗證某個交互是否從未被執(zhí)行
    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);  //異常

    // 注意:可能只想驗證前面的邏輯,但是加上最后一行,會導(dǎo)致出現(xiàn)異常。建議使用方法層面的驗證,如:never();
    //      在驗證是否有冗余調(diào)用的時候,可使用此種方式。如下:
    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對象創(chuàng)建

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

MockitoAnnotations.initMocks(this);

也可以使用內(nèi)置的runner: MockitoJUnitRunner 或者一個rule : MockitoRule;

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

@Test
public void test6() {
    // 注意!下面這句代碼需要在運行測試函數(shù)之前被調(diào)用,一般放到測試類的基類或者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、監(jiān)控真實對象(部分mock)

? 可以為真實對象創(chuàng)建一個監(jiān)控(spy)對象。當(dāng)你使用這個spy對象時真實的對象也會也調(diào)用,除非它的函數(shù)被stub了;

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

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

完全mock:

上文講的內(nèi)容是完全mock,即創(chuàng)建的mock對象與真實對象無關(guān),mock對象的方法默認(rèn)都是基本的實現(xiàn),返回基本類型。可基于接口、實現(xiàn)類創(chuàng)建mock對象。

部分mock:

所謂部分mock,即創(chuàng)建的mock對象時基于真實對象的,mock對象的方法都是默認(rèn)使用真實對象的方法,除非stub之后,才會以stub為準(zhǔn)?;趯崿F(xiàn)類創(chuàng)建mock對象,否則在沒有stub的情況下,調(diào)用真實方法時,會出現(xiàn)異常。

注意點:

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

@Test
public void test7() {
    // stub部分mock(stub中使用真實調(diào)用)。注意:需要mock實現(xiàn)類,否則會有異常
    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中,由于默認(rèn)是調(diào)用真實方法,所以第二種寫法不等價于第一種寫法,不推薦這種寫法。
    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對象只是真實對象的復(fù)制,真實對象的改變不會影響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之后,又想調(diào)用真實的方法,可以使用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);

區(qū)分是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對象返回默認(rèn)
    System.out.println(stubTestService.stubTestMethodB());  //null
    // spy對象調(diào)用真實方法
    System.out.println(stubTestServiceImpl.stubTestMethodC());  //stubTestMethodC is called
    System.out.println(stubTestServiceImpl1.stubTestMethodA("spy"));  //stubTestMethodA is called, param = spy

    // 區(qū)分是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(參數(shù)捕獲器)捕獲方法參數(shù)進行驗證。(可代替參數(shù)匹配器使用)

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

ArgumentCaptor介紹

通過ArgumentCaptor對象的forClass(Class

ArgumentCaptor的Api

argument.capture() 捕獲方法參數(shù)

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

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

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

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

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

10、簡化 ArgumentCaptor 的創(chuàng)建

@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()沒有調(diào)用")).size();
    // org.mockito.exceptions.base.MockitoAssertionError: size()沒有調(diào)用

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

12、高級特性:修改沒有測試樁的調(diào)用的默認(rèn)返回值

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

? 它對于遺留系統(tǒng)來說是很有用處的。當(dāng)你不需要為函數(shù)調(diào)用打樁時你可以指定一個默認(rèn)的answer;

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

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

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

    // 未stub的方法,會調(diào)用真實方法。
    //    注1:存根部分模擬使用時(mock.getSomething ()) .thenReturn (fakeValue)語法將調(diào)用的方法。對于部分模擬推薦使用doReturn語法。
    //    注2:如果模擬是序列化反序列化,那么這個Answer將無法理解泛型的元數(shù)據(jù)。
    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對象的方法調(diào)用后,可以返回自己(類似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
}

三、學(xué)習(xí)了這么多,牛刀小試一下!

測試實體類

@Data
public class User {

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

持久層DAO

public interface UserDao {

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

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

業(yè)務(wù)層Service接口

public interface UserService {

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

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

業(yè)務(wù)層Serive實現(xiàn)類

@Service
public class UserServiceImpl implements UserService {

    //userDao
    @Autowired
    private UserDao userDao;

    /**
     * 根據(jù)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("保存用戶異常");
        }
    }
}

現(xiàn)在我們的Service寫好了,想要單元測試一下,但是Dao是其他人開發(fā)的,目前還沒有寫好,那我們?nèi)绾螠y試呢?

public class UserServiceTest {

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

        // stub調(diào)用
        final User user = new User();
        user.setName("admin");
        user.setPa ssword("pass");
        when(userDao.getUserByName("admin")).thenReturn(user);

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

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

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


    /**
     * Mock測試:保存user
     */
    @Mock
    private UserDao userDao;
    @InjectMocks
    private UserServiceImpl userService;
    @Test
    public void saveUserTest() throws Exception{
        // 執(zhí)行注解初始化
        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);

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

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

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

}

根據(jù)以上代碼我們可以知道,當(dāng)我們的待測類開發(fā)完成而依賴的類的實現(xiàn)還沒有開發(fā)完成。此時,我們就可以用到我們的Mock測試,模擬我們依賴類的返回值,使我們的待測類與依賴類解耦。這樣,我們就可以對我們的待測類進行單元測了。文章來源地址http://www.zghlxwxcb.cn/news/detail-481261.html

四、參考文檔及進一步學(xué)習(xí)~

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
參數(shù)捕獲器使用:https://www.journaldev.com/21892/mockito-argumentcaptor-captor-annotation
利用ArgumentCaptor(參數(shù)捕獲器)捕獲方法參數(shù)進行驗證: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的實現(xiàn),spy、callRealMethod:https://www.cnblogs.com/softidea/p/4204389.html
Mockito 中被 Mocked 的對象屬性及方法的默認(rèn)值: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
測試覆蓋率統(tǒng)計:https://blog.csdn.net/lvyuan1234/article/details/82836052?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
測試覆蓋率無法統(tǒng)計解決:https://blog.csdn.net/zhanglei082319/article/details/81536398

到了這里,關(guān)于單元測試?yán)鳌职咽纸棠闶褂肕ockito的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 優(yōu)化| 手把手教你學(xué)會杉樹求解器(COPT)的安裝、配置與測試

    優(yōu)化| 手把手教你學(xué)會杉樹求解器(COPT)的安裝、配置與測試

    作者: 劉興祿,清華大學(xué),清華伯克利深圳學(xué)院博士在讀 歡迎關(guān)注我們的微信公眾號 運小籌 最近杉數(shù)求解器發(fā)布了4.0.2版本。著名的優(yōu)化求解器benchmark測評的官網(wǎng)也更新了最近的榜單。 網(wǎng)址如下: Benchmarks for Optimization Software - Hans Mittelmann http://plato.asu.edu/bench.html 線性規(guī)劃

    2023年04月13日
    瀏覽(70)
  • 手把手教你如何快速定位bug,如何編寫測試用例,快來觀摩......

    手把手教你如何快速定位bug,如何編寫測試用例,快來觀摩......

    手把手教你如何快速定位bug,如何編寫測試用例,快來觀摩......手把手教你如何快速定位bug,如何編寫測試用例,快來觀摩......作為一名測試人員如果連常見的系統(tǒng)問題都不知道如何分析,頻繁將前端人員問題指派給后端人員,后端人員問題指派給前端人員,那么在團隊里你在開發(fā)

    2024年01月20日
    瀏覽(23)
  • 手把手教你如何使用SimiliarWeb

    手把手教你如何使用SimiliarWeb

    在之前的“手把手教你如何使用Google Trends”文章中我們講到從事跨境電商的賣家第一步遇到的問題是“客戶在哪里?”該如何推廣我的產(chǎn)品?因此若想自己的店鋪做大做好,則需要工具來幫助分析市場行情,根據(jù)市場行情調(diào)整自己的業(yè)務(wù)狀況。小編在上篇中已經(jīng)講解了三個特

    2024年02月09日
    瀏覽(103)
  • 手把手教你如何使用Docker

    手把手教你如何使用Docker

    我們在公司開發(fā)中,會有開發(fā)環(huán)境,測試環(huán)境,上線環(huán)境, 比如我們開發(fā)人員開發(fā)好了一個項目,在開發(fā)環(huán)境中運行正常,但測試人員拉到測試環(huán)境就跑不起來【jdk版本等】,或者上線的時候運行不起來,這時候就要為每個機器配置一個環(huán)境,那運維人員不得累死?【哈哈,

    2024年02月10日
    瀏覽(104)
  • 手把手教你使用gdb調(diào)試器

    手把手教你使用gdb調(diào)試器

    所謂調(diào)試,指的是對編好的程序用各種手段進進行查錯和排非錯的過程。進行這種查錯處理時,下面將講解如何使用gdb進行程序的調(diào)試。? gdb?簡介 gdb是一個功能強大的調(diào)試工具,可以用來調(diào)試C程序或C++程序。在使用這個工具進行程序調(diào)試時,主要涉及下面四個方面的操作。

    2024年02月16日
    瀏覽(31)
  • 怎么用AI繪畫?手把手教你使用

    怎么用AI繪畫?手把手教你使用

    與傳統(tǒng)的繪畫方式不同,AI繪畫軟件采用了人工智能算法和計算機視覺技術(shù),使藝術(shù)作品的創(chuàng)作變得更加智能化和自動化。這樣,即使一個看不懂顏料,也毫無繪畫經(jīng)驗的業(yè)余者也能創(chuàng)作出可圈可點的藝術(shù)品了。AI繪畫軟件因此被越來越多的創(chuàng)作者和愛好者所使用。那你們知道

    2024年02月15日
    瀏覽(97)
  • 手把手教你 iconfont 導(dǎo)入使用及相關(guān)配置

    手把手教你 iconfont 導(dǎo)入使用及相關(guān)配置

    iconfont是阿里旗下的一套圖標(biāo)庫,UI設(shè)計師設(shè)計號圖標(biāo)后,會將圖標(biāo)上傳到iconfont的項目庫中。前端開發(fā)人員需要下載項目圖標(biāo),并在項目中使用。 iconfont相對于傳統(tǒng)的直接導(dǎo)入圖標(biāo)進入頁面,有以下幾點優(yōu)勢: 體積更小,頁面加載速度更快 解決圖片像素點會隨頁面變化而模

    2024年02月07日
    瀏覽(28)
  • 手把手教你使用Markdown:從入門到精通

    手把手教你使用Markdown:從入門到精通

    本篇文章由卷不動的小白撰寫,為讀者提供了一份詳盡的Markdown語法指南。

    2024年02月03日
    瀏覽(110)
  • 手把手教你如何使用Fiddler抓包工具

    手把手教你如何使用Fiddler抓包工具

    什么是 Fiddler? Fiddler 是一個 HTTP 協(xié)議調(diào)試代理工具,它能夠記錄并檢查所有你的電腦和互聯(lián)網(wǎng)之間的 HTTP 通訊。Fiddler 提供了電腦端、移動端的抓包、包括 http 協(xié)議和 https 協(xié)議都可以捕獲到報文并進行分析;可以設(shè)置斷點調(diào)試、截取報文進行請求替換和數(shù)據(jù)篡改,也可以進行

    2024年02月07日
    瀏覽(92)
  • 手把手教你使用Segformer訓(xùn)練自己的數(shù)據(jù)

    手把手教你使用Segformer訓(xùn)練自己的數(shù)據(jù)

    使用Transformer進行語義分割的簡單高效設(shè)計。 將 Transformer 與輕量級多層感知 (MLP) 解碼器相結(jié)合,表現(xiàn)SOTA!性能優(yōu)于SETR、Auto-Deeplab和OCRNet等網(wǎng)絡(luò) 相比于ViT,Swin Transfomer計算復(fù)雜度大幅度降低,具有輸入圖像大小線性計算復(fù)雜度。Swin Transformer隨著深度加深,逐漸合并圖像塊來

    2024年01月20日
    瀏覽(119)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包