一文淺談Mockito使用
一、前期準備~
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:行為驗證,驗證指定方法調用情況(是否被調用,調用次數(shù)等);
3、五分鐘入門Demo
@Test
public void test0() {
//1、創(chuàng)建mock對象(模擬依賴的對象)
final List mock = Mockito.mock(List.class);
//2、使用mock對象(mock對象會對接口或類的方法給出默認實現(xiàn))
System.out.println("mock.add result => " + mock.add("first")); //false
System.out.println("mock.size result => " + mock.size()); //0
//3、打樁操作(狀態(tài)測試:設置該對象指定方法被調用時的返回值)
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對象被創(chuàng)建了,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);
// 指定時間內需要完成的次數(shù)
Mockito.verify(mockList, timeout(200).atLeastOnce()).size();
}
2、如何做一些測試樁stub
?默認情況下,所有的函數(shù)都有返回值。mock函數(shù)默認返回的是null,一個空的集合或者一個被對象類型包裝的內置類型,例如0、false對應的對象類型為Integer、Boolean;
?一旦測試樁函數(shù)被調用,該函數(shù)將會一致返回固定的值;
?對于 static 和 final 方法, Mockito 無法對其 when(…).thenReturn(…) 操作。
@Test
public void test2() {
//靜態(tài)導入,減少代碼量: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
// 為連續(xù)調用做測試樁(為同一個函數(shù)調用的不同的返回值或異常做測試樁)
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、參數(shù)匹配器
?參數(shù)匹配器使驗證和測試樁變得更靈活;
?為了合理的使用復雜的參數(shù)匹配,使用equals()與anyX() 的匹配器會使得測試代碼更簡潔、簡單。有時,會迫使你重構代碼以使用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()在交互測試套件中只是一個便利的驗證,它的作用是當你需要驗證是否存在冗余調用時;
@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); //異常
// 注意:可能只想驗證前面的邏輯,但是加上最后一行,會導致出現(xiàn)異常。建議使用方法層面的驗證,如: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對象創(chuàng)建
注意!下面這句代碼需要在運行測試函數(shù)之前被調用,一般放到測試類的基類或者test runner中:
MockitoAnnotations.initMocks(this);
也可以使用內置的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ù)之前被調用,一般放到測試類的基類或者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)對象。當你使用這個spy對象時真實的對象也會也調用,除非它的函數(shù)被stub了;
?盡量少使用spy對象,使用時也需要小心形式,例如spy對象可以用來處理遺留代碼;
?stub語法中同樣提供了部分mock的方法,可以調用真實的方法;
完全mock:
上文講的內容是完全mock,即創(chuàng)建的mock對象與真實對象無關,mock對象的方法默認都是基本的實現(xiàn),返回基本類型??苫诮涌?、實現(xiàn)類創(chuàng)建mock對象。
部分mock:
所謂部分mock,即創(chuàng)建的mock對象時基于真實對象的,mock對象的方法都是默認使用真實對象的方法,除非stub之后,才會以stub為準?;趯崿F(xiàn)類創(chuàng)建mock對象,否則在沒有stub的情況下,調用真實方法時,會出現(xiàn)異常。
注意點:
Mockito并不會為真實對象代理函數(shù)調用,實際上它會拷貝真實對象。因此如果你保留了真實對象并且與之交互,不要期望從監(jiān)控對象得到正確的結果。 當你在監(jiān)控對象上調用一個沒有被stub的函數(shù)時并不會調用真實對象的對應函數(shù),你不會在真實對象上看到任何效果
@Test
public void test7() {
// stub部分mock(stub中使用真實調用)。注意:需要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中,由于默認是調用真實方法,所以第二種寫法不等價于第一種寫法,不推薦這種寫法。
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);
區(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對象返回默認
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
// 區(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ù)匹配器使用)
?在某些場景中,不光要對方法的返回值和調用進行驗證,同時需要驗證一系列交互后所傳入方法的參數(shù)。那么我們可以用參數(shù)捕獲器來捕獲傳入方法的參數(shù)進行驗證,看它是否符合我們的要求。
ArgumentCaptor介紹
通過ArgumentCaptor對象的forClass(Class
ArgumentCaptor的Api
argument.capture() 捕獲方法參數(shù)
argument.getValue() 獲取方法參數(shù)值,如果方法進行了多次調用,它將返回最后一個參數(shù)值
argument.getAllValues() 方法進行多次調用后,返回多個參數(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
// 多次調用獲取最后一次
ArgumentCaptor argument1 = ArgumentCaptor.forClass(String.class);
verify(mock1, times(2)).add(argument1.capture());
System.out.println(argument1.getValue()); //Jim
// 獲取所有調用參數(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()沒有調用")).size();
// org.mockito.exceptions.base.MockitoAssertionError: size()沒有調用
verify(arrayList, timeout(200).times(3).description("驗證失敗")).add(anyString());
//org.mockito.exceptions.base.MockitoAssertionError: 驗證失敗
}
12、高級特性:修改沒有測試樁的調用的默認返回值
?可以指定策略來創(chuàng)建mock對象的返回值。這是一個高級特性,通常來說,你不需要寫這樣的測試;
?它對于遺留系統(tǒng)來說是很有用處的。當你不需要為函數(shù)調用打樁時你可以指定一個默認的answer;
@Test
public void test12(){
// 創(chuàng)建mock對象、使用默認返回
final ArrayList mockList = mock(ArrayList.class);
System.out.println(mockList.get(0)); //null
// 這個實現(xiàn)首先嘗試全局配置,如果沒有全局配置就會使用默認的回答,它返回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將無法理解泛型的元數(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對象的方法調用后,可以返回自己(類似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 {
/**
* 根據(jù)name查找user
* @param name
* @return
*/
User getUserByName(String name);
/**
* 保存user
* @param user
* @return
*/
Integer saveUser(User user);
}
業(yè)務層Service接口
public interface UserService {
/**
* 根據(jù)name查找user
* @param name
* @return
*/
User getUserByName(String name);
/**
* 保存user
* @param user
* @return
*/
Integer saveUser(User user);
}
業(yè)務層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ā)的,目前還沒有寫好,那我們如何測試呢?
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調用
final User user = new User();
user.setName("admin");
user.setPassword("pass");
when(userDao.getUserByName("admin")).thenReturn(user);
// 執(zhí)行待測試方法
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{
// 執(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);
// 驗證用戶名重復的情況
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());
}
}
根據(jù)以上代碼我們可以知道,當我們的待測類開發(fā)完成而依賴的類的實現(xiàn)還沒有開發(fā)完成。此時,我們就可以用到我們的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
- 參數(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 的對象屬性及方法的默認值: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