前言
在之前进行用户认证单元测试的时候,应用的是 RestTemplate 来模仿发动申请,然而平时用的更多的是 MockMvc 来进行后盾的申请。他们两个有何不同呢?
RestTemplate
部署的一个实在的 web 服务器来监听 http 申请,响应后果
既然是实在的,那么它最大的弊病就是无奈进行事物回滚:
在测试完结后,发现并没有对数据进行回滚,然而我在认证单元测试的时候并没有波及到数据库回滚的问题,所以跟 mockmvc 没有区别
起因:@Transactional 注解对于 RestTemplate 是生效的,所以不会进行事物回滚
MockMvc
mockmvc 通常是通过设置一个残缺的高低完应用程序来模仿 HTTP 申请和响应
创立的是一个假的 DispatcherServlet 来模仿 MVC 堆栈的运行,并没有真正的网络链接
既然是模仿的,那么咱们能够通过注解 @Transactional 来进行事务的回滚,并不会因为测试对数据库造成副作用。
总结
综上:在更多时候进行单元测试的时候咱们还是应该偏向于 MockMvc 的,然而当有非凡需要的时候,咱们能够应用 RestTemplate。
单元测试遇到的问题:
问题一:
仿照之前老我的项目写 update 的单元测试代码:
@Test
void update() throws Exception {Long id = new Random().nextLong();
Town oldTown = getOneTown();
oldTown.setId(id);
Town newTown = getOneTown();
String jsonString = JSON.toJSONString(oldTown);
String url = baseUrl + "/" + id.toString();
Mockito.doReturn(newTown).when(this.townService).update(id, oldTown);
MockHttpServletRequestBuilder putRequest = MockMvcRequestBuilders
.put(url)
.contentType(MediaType.APPLICATION_JSON)
.content(jsonString);
this.mockMvc.perform(putRequest)
.andExpect(MockMvcResultMatchers.jsonPath("$.id").value(newTown.getId()))
.andExpect(MockMvcResultMatchers.jsonPath("$.name").exists())
.andExpect(MockMvcResultMatchers.jsonPath("$.pinyin").exists())
.andExpect(status().isOk());
ArgumentCaptor<Town> townArgumentCaptor = ArgumentCaptor.forClass(Town.class);
ArgumentCaptor<Long> longArgumentCaptor = ArgumentCaptor.forClass(Long.class);
Mockito.verify(this.townService).update(longArgumentCaptor.capture(),
townArgumentCaptor.capture());
org.assertj.core.api.Assertions.assertThat(longArgumentCaptor.getValue()).isEqualTo(id);
org.assertj.core.api.Assertions.assertThat(townArgumentCaptor.getValue().getName()).isEqualTo(oldTown.getName());
}
首先是谬误翻译:返回值的 id 属性不存在
排查:
1. 第一反馈认为是我 C 层 Long 属性写成 Integer 类型了
2. 查看响应状态:passed,申请胜利
3. 猜想返回值出了问题,因为申请是没有问题的:
认真想了之后:oldTown 在模仿发动申请的时候,传入的 oldTown 与 mock 中的 oldTown 就不是一个对象了,那他必然不会返回 newTown!
总结
还是对于单元测试短少锤炼,还须要通过一直的写来加深了解。
问题二:
依据 id 获取对象 c 层测试:
@Test
void getById() throws Exception{Town town = getOneTown();
Mockito.doReturn(town).when(this.townService).getById(Mockito.eq(town.getId()));
String url = baseUrl + "/" + town.getId().toString();
this.mockMvc.perform(MockMvcRequestBuilders.get(url))
.andExpect(MockMvcResultMatchers.status().isOk());
}
与历史我的项目比照,找区别:
将至改为 Long 便能够胜利拜访了!
认为是本人的申请的为 Long 类型,然而想到转换了 String 类型了啊,跟 Integer 一样啊
改为 Integer 测试还是不行!
总结
单元测试应用还是不够纯熟,应用办法也不对,总是在都写完之后进行集成测试,在明天老师讲了能够将未实现的办法间接 mock 掉的办法来进行单元测试,才明确原来单元测试应用始终不对!