1、官方解释: Mockito is a mocking framework that tastes really good. It lets you write beautiful tests with a clean & simple API. Mockito doesn’t give you hangover because the tests are very readable and they produce clean verification errors.
2、Mockito是简单轻量级的Mocking(模拟测试)框架。使用简单,测试代码可读性高,能够使单元测试尽可能独立。
1、JUnit可以轻松完成关联依赖关系少或者比较简单的单元测试,但是对于关联依赖关系较多的类或者对运行环境有要求的类的单元测试,模拟环境或者配置环境时会非常耗时,实施单元测试较为困难。例如需要需要测试一个controller方法,需要从controller->service->dao层,这种方法无疑是正确的,但是有一个很明显的问题,速度问题。测试controller层时会访问下面两层,如果我们之前已经测试过service,dao层是正确的,现在相当于做了两次重复的动作。
2、Mockito可以模拟对象的行为,隔离开我们不关心的其他对象,使测试变得简单。图解及代码示例:
1. public class UserService(){
2. //...
3. public void saveUser(User user){
4. {
5. //...
6. }
7. // 访问数据库方法
8. userDao.insertUser(new User());
9. {
10. //...
11. }
12. }
13. }
14. public class UserDao(){
15.
16. public void insertUser(){
17. // 数据库此时不能访问
18. throw new RuntimeException("databaser cant connect");
19. }
20.
21. }
模拟并替换测试代码中外部依赖。
执行测试代码。
执行测试代码是否被正确执行。
1)状态检测(state verification),方法运行过之后,检测方法的运行状态(或者说返回值状态),判断方法运行是否成功。
1. assertNotNull(user); // 验证返回值时候为空
2. assertEquals(user.getUserName(), "tom"); // 验证返回值时候等于预期值
3. assertTrue(biilean); // 验证返回值是否为true
2)行为检测(behavior verification),方法运行之后,检测方法的执行行为(或者说执行顺序),判断方法是否执行成功。
1. verify(mockUserService).findUserByUserName("tom"); // 验证交互行为
2. verify(mockUserService, atLeastOnce()).findUserByUserName("tom");// 方法至少调用一次
3. verify(mockUserService, atLeast(1)).findUserByUserName("tom");
4. verify(mockUserService, atMost(1)).findUserByUserName("tom"); // 方法至多调用一次
官网:
http://mockito.org
项目源码:
https://github.com/mockito/mockito
API文档:
https://static.javadoc.io/org.mockito/mockito-core/3.0.0/org/mockito/Mockito.html
教程:
https://www.cnblogs.com/Ming8006/p/6297333.html
https://www.jianshu.com/p/f6e3ab9719b9
Mockito依赖,需配合Junit使用
1) <dependency>
2) <groupId>org.mockito</groupId>
3) <artifactId>mockito-core</artifactId>
4) <version>1.10.19</version>
5) <scope>test</scope>
6) </dependency>
7)
8) <dependency>
9) <groupId>org.mockito</groupId>
10) <artifactId>mockito-all</artifactId>
11) <version>1.10.19</version>
12) <scope>test</scope>
13) </dependency>
如果在代码中静态引用了org.mockito.Mockito.*;,那你你就可以直接调用静态方法和静态变量而不用创建对象,
1. import static org.mockito.Mockito.verify;
2. import static org.mockito.Matchers.*;
3. import static org.mockito.Mockito.times;
4. import static org.mockito.Mockito.verify;
5. import static org.mockito.Mockito.when;
(一) 除了上面所说的使用 mock() 静态方法外,Mockito 还支持通过 @Mock 注解的方式来创建 mock 对象。
(二) @Mock 是对于测试类的依赖类的注解,被 @Mock 标记后相当于创建了一个Mock对象,不会进入方法体。
(三) @InjectMocks 是对待测试类的注解,创建一个实例,其余使用@Mock或@Spy注解的Mock将会被注解到该实例中,所有方法都会进入方法体。
(四) Mockito在遇到使用注解的字段的时候,会调用MockitoAnnotations.initMocks(this) 来初始化该 mock 对象。另外也可以通过使用@RunWith(MockitoJUnitRunner.class)来达到相同的效果。
1. @RunWith(MockitoJUnitRunner.class)
2. public class ServiceMockitoTest {
3.
4. // Dao对象
5. @Mock
6. UserDao userDao;
7.
8. // 被测试Service对象
9. @InjectMocks
10. UserService userService;
11.
12. @Test
13. public void serviceMockito(){
14.
15. User user = new User();
16. // 当UserDao的insertUser方法被UserService的regist方法调用时返回1
17. when(userDao.insertUser(any(User.class))).thenReturn(1);
18. // 验证方法调用
19. assertTrue(userService.regist(user));
20. }
21. }
注:
测试时URL参数应当与Mock时参数保持一致,否则mock不成功。
1. @ContextConfiguration(classes = MockServletContext.class)
2. public class ControllerMockitoTest {
3.
4. private MockMvc mockMvc;
5.
6. @Mock
7. UserService userService;
8.
9. @InjectMocks
10. UserController userController;
11.
12. @Before
13. public void setUp() throws Exception {
14. MockitoAnnotations.initMocks(this);
15. this.mockMvc = MockMvcBuilders.standaloneSetup(userController).build();
16. }
17.
18.
19. @Test
20. public void mockitoTest() throws Exception {
21. //mock void方法
22. Mockito.doNothing().when(userService).deleteUser(Mockito.anyInt());
23. //构建请求,与接口路径一致
24. RequestBuilder request = MockMvcRequestBuilders.post("/user/1");
25. //断言请求是否成功
26. mockMvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
27. }
28. }
1. @RunWith(MockitoJUnitRunner.class)
2. public class ExceptionMockitoTest {
3.
4. @Mock
5. UserDao userDao;
6.
7. @InjectMocks
8. UserService userService;
9.
10. @Test
11. public void MockitoTest(){
12. User user = new User();
13. // 调用userDao的updateUser方法时抛出RuntimeException
14. doThrow(new RuntimeException("operation notimplemented")).when(userDao).updateUser(any(User.class));
15. // 异常后断言
16. assertTrue(userService.update(user));
17. }
18. }
注:
Mockito可以对普通方法进行Mock,如public等,如要对private/static/final进行Mock,需要配合PowerMock。
Mockito与PowerMock存在版本兼容问题,对应版本。https://blog.csdn.net/fengliushaonian1993/article/details/78241932
依赖
1. <dependency>
2. <groupId>org.powermock</groupId>
3. <artifactId>powermock-api-mockito</artifactId>
4. <version>1.6.3</version>
5. <scope>test</scope>
6. </dependency>
7. <dependency>
8. <groupId>org.powermock</groupId>
9. <artifactId>powermock-module-junit4</artifactId>
10. <version>1.6.3</version>
11. <scope>test</scope>
12. </dependency>
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserDao.class)
public class UserServiceStaticTest {
@Test
public void queryUserCount() {
// powerMock的静态方法支持
mockStatic(UserDao.class);
// 当调用UserDao的静态方法getCount时,返回10
when(UserDao.getCount()).thenReturn(10);
// 调用方法userService.queryUserCount()的方法
UserService userService = new UserService();
int count = userService.queryUserCount();
// 断言结果是否为预期值
assertEquals(10 , count);
}
@Test
public void saveUser() {
User user = new User();
// powerMock的静态方法支持
mockStatic(UserDao.class);
// void返回类型doNothing
PowerMockito.doNothing().when(UserDao.class);
// 调用方法userService.saveUser(user)的方法
UserService userService = new UserService();
userService.saveUser(user);
// 验证是否执行成功
PowerMockito.verifyStatic();
}
}
注:
public方法中常会调用私有方法,如果只想测试public方法,不关注private的逻辑,就需要对private方法进行Mock。
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserServicePrivateTest {
@Test
public void log() {
/*// mock对象不进入方法体
UserService userService1 = PowerMockito.mock(UserService.class);
userService1.log("e");
// spy对象进入方法体
// 满足断言条件使用mock, 不满足使用spy
UserService userService2 = PowerMockito.spy(new UserService());
userService2.log("e");*/
UserService userService3 = PowerMockito.spy(new UserService());
String arg = "log";
doNothing().when(userService3).log(arg);
// 不符合断言, 使用soy会进入方法体
// userService3.log("test");
// 符合断言,使用mock不会进入方法体
userService3.log("arg");
}
@Test
public void exists() throws Exception {
// spy userService对象
UserService userService = PowerMockito.spy(new UserService());
// 当实行userService的checkExists并且参数为qyh时,返回true
PowerMockito.doReturn(true).when(userService, "checkExists", "qyh");
// 断言
assertTrue(userService.exists("qyh"));
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserDao.class)
public class UserServiceFinalTest {
@Mock
private UserDao userDao;
@Test
@Ignore
public void queryUserCountWithMockito() {
// 初始化UserDao的mock对象
MockitoAnnotations.initMocks(this);
UserService userService = new UserService(userDao);
// 调用UserDao的final方法getCount时,返回10
when(userService.queryUserCount()).thenReturn(10);
int count = userService.queryUserCount();
// 断言结果是否为预期
assertEquals(10, count);
}
@Test
public void queryUserCountWithPowerMock() {
// 调用UserDao的final方法getCount时,返回10
PowerMockito.when(userDao.getCount()).thenReturn(10);
UserService userService = new UserService(userDao);
int count = userService.queryUserCount();
// 断言结果是否为预期值
assertEquals(10 , count);
}
}
t);
}
@Test
public void queryUserCountWithPowerMock() {
// 调用UserDao的final方法getCount时,返回10
PowerMockito.when(userDao.getCount()).thenReturn(10);
UserService userService = new UserService(userDao);
int count = userService.queryUserCount();
// 断言结果是否为预期值
assertEquals(10 , count);
}
}
### 9) Final方法测试
测试方式与Final类测试方法一致,将Final类改为Final方法,其他代码不变。
代码下载地址 : https://download.csdn.net/download/qq_37813031/12198273