## Mockito簡介
單元測試中如何減少對外部的依賴這正是 mockito 的使命,mockito 是一個流行的 mock 框架,可以與 junit 結合使用,mockito 允許我們創建和配置 mock 對象,使用 mockito 將大大簡化了具有外部依賴項的類的測試開發。spring-boot-starter-test 中默認集成了 mockito,不需要額外引入。
## Mockito使用
* 打樁:實際上就是對接口、類、方法、參數、返回值進行偽造或者模擬。
* ReflectionTestUtils
* 注解的使用
* @Mock:真實對象的替代品
* @Spy:被測試對象需要一部分被執行、一部分被mock,需要用spy對目標對象進行包裝
* thenReturn與doReturn差異
* 語法:
* when-thenReturn
* when(obj.method()).thenReturn(returnValue)
* doReturn-when
* doReturn(returnValue).when(obj).method()
* 差異
| API | Mock Obj | Spy Obj |
| --- | --- | --- |
| when-thenReturn | × | ○ |
| doReturn-when | × | × |
## maven依賴
```
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>xxx.yyy</version>
<scope>test</scope>
</dependency>
```
## 注解介紹
* 在單元測試中使用@Mock, @Spy, @InjectMocks等注解時,需要進行初始化后才能使用
* 可以使用 @RunWith(MockitoJUnitRunner.class) 代替@RunWith(SpringRunner.class)進行初始化,也可以在測試類的構造方法中使用MockitoAnnotations.initMocks(this) 來初始化
* @Mock:創建mock對象,也可使用靜態方法mock()創建
~~~
List mockedList = mock(List.class);
~~~
* @Spy:和@Mock一樣創建對象,區別在于@Spy會調用真實數據
* @InjectMocks:創建一個實例,其余用@Mock(或@Spy)注解創建的mock將被注入到用該實例中
## Mockito的常用方法
| 方法名 | 描述 |
| --- | --- |
| Mockito.mock(classToMock) | 模擬對象 |
| Mockito.verify(mock) | 驗證行為是否發生 |
| Mockito.when(methodCall).thenReturn(value1).thenReturn(value2) | 觸發時第一次返回value1,第n次都返回value2 |
| Mockito.doThrow(toBeThrown).when(mock).\[method\] | 模擬拋出異常。 |
| Mockito.mock(classToMock,defaultAnswer) | 使用默認Answer模擬對象 |
| Mockito.when(methodCall).thenReturn(value) | 參數匹配 |
| Mockito.doReturn(toBeReturned).when(mock).\[method\] | 參數匹配(直接執行不判斷) |
| Mockito.when(methodCall).thenAnswer(answer)) | 預期回調接口生成期望值 |
| Mockito.doAnswer(answer).when(methodCall).\[method\] | 預期回調接口生成期望值(直接執行不判斷) |
| Mockito.spy(Object) | 用spy監控真實對象,設置真實對象行為 |
| Mockito.doNothing().when(mock).\[method\] | 不做任何返回 |
| Mockito.doCallRealMethod().when(mock).\[method\] //等價于Mockito.when(mock.\[method\]).thenCallRealMethod(); | 調用真實的方法 |
| reset(mock) | 重置mock |
## 例子
```
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.boot.test.context.SpringBootTest;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
//@RunWith(SpringRunner.class)
@SpringBootTest
public class MockLoginTest {
//對被測類中@Autowired的對象,用@Mock標注;對被測類自己,用@InjectMocks標注
@InjectMocks
private UserServiceImpl userService;
@Mock
private UserRepository userDao;
@Mock
private BargainBlackListService bargainBlackListService;
@Mock
private DistributionUserService distributionUserService;
@Mock
private AuthorityService authorityService;
@Before
public void init(){
MockitoAnnotations.initMocks(this);
}
@Test
public void loginTest() {
//模擬方法動作
//spyUserService在調用getUserEntity方法的時候,指定返回事先定義好的userEntity
UserService spyUserService = spy(userService);
UserEntity userEntity = new UserEntity();
userEntity.setUserName("ppp");
doReturn(userEntity).when(spyUserService).getUserEntity(anyString());
when(bargainBlackListService.checkBlackList(anyString())).thenReturn(true);
UserInfoDTO userInfoDTO = new UserInfoDTO();
userInfoDTO.setUserName("ppp");
userInfoDTO.setId("2c95808a644ade6801644ae37f730000");
spyUserService.updateUserInfo("0520b1d9-9806-4ec1-a095-dfcd8bea8fd6", userInfoDTO);
}
}
```