前言注意
Testng和Junit在使用过程中有所区别请参考:《Testng与Junit使用区别》
Mock的作用
构造假的关联依赖,专注测试单一服务。
假设:A有关联依赖B、C,而B、C又分别依赖D、E、F。测试A就需要将B、C、D、E、F同时构建,比较费劲。

此时我们构造一个假的B、C给到A进行使用,就会很方便我们单独测试A的功能。

Mockito
简单原理介绍
使用代理模式将原有对象再包一层。
能力
-
针对Spring bean对象进行Mock处理。
- @Mock 定义一个新的Mock对象,此时不会替换Spring容器中的Bean。需要针对性打桩,未打桩方法不可调用。
- @MockBean 替换Spring容器中的Bean。
- @Spy 在原有的对象上进行方法层面的Mock。未打桩重新定义的方法会使用原有对象的方法。
- @SpyBean 再原有的Bean对象上覆盖原有的方法。
-
打桩,针对特定的调用方式返回特定的值(或报错等其他操作)。
- 语法:
when(testDao.getRank()).thenReturn("1"),如果 testDao 调用 getRank() 就返回 1。
- 语法:
代码示例
@Slf4j
// testng需要添加次注解才能使用 Mockito
@TestExecutionListeners(MockitoTestExecutionListener.class)
// testng使用Spring进行Bean注入需要添加注解 @SpringBootTest,并继承 AbstractTestNGSpringContextTests
@SpringBootTest
public class TestngTest extends AbstractTestNGSpringContextTests {
// 通过MockBean会将Spring容器内的Bean替换掉
@MockBean
private RankDao rankDao;
// douyinGameRankServiceMock 构建时会依赖 rankDao
@Autowired
private DouyinGameRankService douyinGameRankServiceMock;
@Test(groups = "demo")
public void testMockito() {
Rank rank = new Rank();
rank.setId(1L);
rank.setLiveUserName("测试user");
rank.setRoomId("测试roomId");
Mockito.when(rankDao.getRank(1L)).thenReturn(rank);
// douyinGameRankServiceMock.getRank() 会调用rankDao.getRank(),此时会返回上面自定义的rank。
log.debug(String.valueOf(douyinGameRankServiceMock.getRank(1L)));
}
}
MockMvc与Mockito结合使用
MockMvc能力
基于RESTful风格的SpringMVC单元测试,可以测试完整的SpringMVC流程
代码示例
@Slf4j
// 通过注解确认需要使用 MockMvc
@AutoConfigureMockMvc
@TestExecutionListeners(MockitoTestExecutionListener.class)
@SpringBootTest(classes = GameApplication.class)
public class DouyinGameControllerTest extends AbstractTestNGSpringContextTests {
// 通过注解注入 mockMvc
@Autowired
private MockMvc mockMvc;
// 通过MockBean会将Spring容器内的Bean替换掉
@MockBean
private RankDao rankDao;
@Test(groups = {"controller"})
public void testGetRank() throws Exception {
Rank rank = new Rank();
rank.setId(1L);
rank.setLiveUserName("测试user");
rank.setRoomId("测试roomId");
Mockito.when(rankDao.getRank(1L)).thenReturn(rank);
List<Rank> list = new ArrayList<>();
list.add(rank);
Mockito.when(rankDao.getRankList()).thenReturn(list);
// 路由 /douyin/rank 会调用rankDao.getRankList() 查询Rank列表信息,由于之前已经Mock返回值,此时的接口返回结果就是变量list中数据。
MvcResult authResult = mockMvc.perform(MockMvcRequestBuilders.get("/douyin/rank") // 调用get接口
.contentType(MediaType.APPLICATION_FORM_URLENCODED)) // 请求数据类型
.andExpect(MockMvcResultMatchers.status().isOk()) // 验证成功响应
.andReturn();
authResult.getResponse().setCharacterEncoding("UTF-8"); // 设置响应解码格式
log.debug(authResult.getResponse().getContentAsString());
}
}