## 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);
}
}
```