spring boot(三)Junit 测试controller
Junit测试Controller(MockMVC使用),传输@RequestBody数据解决办法
一、单元测试的目的
简单来说就是在我们增加或者改动一些代码以后对所有逻辑的一个检测,尤其是在我们后期修改后(不论是增加新功能,修改bug),都可以做到重新测试的工作。以减少我们在发布的时候出现更过甚至是出现之前解决了的问题再次重现。
这里主要是使用MockMvc对我们的系统的Controller进行单元测试。
对数据库的操作使用事务实现回滚,及对数据库的增删改方法结束后将会还远数据库。
二、MockMvc的使用
1、首先我们上一个例子,

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /**
* Created by zhengcanrui on 16/8/11.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:spring/applicationContext-*xml"}) //配置事务的回滚,对数据库的增删改都会回滚,便于测试用例的循环利用
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional @WebAppConfiguration
public class Test {
//记得配置log4j.properties ,的命令行输出水平是debug
protected Log logger= LogFactory.getLog(TestBase.class); protected MockMvc mockMvc; @Autowired
protected WebApplicationContext wac; @Before() //这个方法在每个方法执行之前都会执行一遍
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); //初始化MockMvc对象
} @org.junit.Test
public void getAllCategoryTest() throws Exception {
String responseString = mockMvc.perform(
get("/categories/getAllCategory") //请求的url,请求的方法是get
.contentType(MediaType.APPLICATION_FORM_URLENCODED) //数据的格式
.param("pcode","root") //添加参数
).andExpect(status().isOk()) //返回的状态是200
.andDo(print()) //打印出请求和相应的内容
.andReturn().getResponse().getContentAsString(); //将相应的数据转换为字符串
System.out.println("--------返回的json = " + responseString);
} }

Spring MVC的测试往往看似比较复杂。其实他的不同在于,他需要一个ServletContext来模拟我们的请求和响应。但是Spring也针对Spring MVC 提供了请求和响应的模拟测试接口,以方便我们的单元测试覆盖面不只是service,dao层。
2、代码解释:
@webappconfiguration是一级注释,用于声明一个ApplicationContext集成测试加载WebApplicationContext。作用是模拟ServletContext
@ContextConfiguration:因为controller,component等都是使用注解,需要注解指定spring的配置文件,扫描相应的配置,将类初始化等。
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
上面两句的作用是,让我们对数据库的操作会事务回滚,如对数据库的添加操作,在方法结束之后,会撤销我们对数据库的操作。
为什么要事务回滚?
- 测试过程对数据库的操作,会产生脏数据,影响我们数据的正确性
- 不方便循环测试,即假如这次我们将一个记录删除了,下次就无法再进行这个Junit测试了,因为该记录已经删除,将会报错。
- 如果不使用事务回滚,我们需要在代码中显式的对我们的增删改数据库操作进行恢复,将多很多和测试无关的代码
方法解析:
- perform:执行一个RequestBuilder请求,会自动执行SpringMVC的流程并映射到相应的控制器执行处理;
- get:声明发送一个get请求的方法。MockHttpServletRequestBuilder get(String urlTemplate, Object... urlVariables):根据uri模板和uri变量值得到一个GET请求方式的。另外提供了其他的请求的方法,如:post、put、delete等。
- param:添加request的参数,如上面发送请求的时候带上了了pcode = root的参数。假如使用需要发送json数据格式的时将不能使用这种方式,可见后面被@ResponseBody注解参数的解决方法
- andExpect:添加ResultMatcher验证规则,验证控制器执行完成后结果是否正确(对返回的数据进行的判断);
- andDo:添加ResultHandler结果处理器,比如调试时打印结果到控制台(对返回的数据进行的判断);
- andReturn:最后返回相应的MvcResult;然后进行自定义验证/进行下一步的异步处理(对返回的数据进行的判断);
注意事项:
- 在mac上使用log4j是,假如使用了${catalina.home}需要注意,mac不会去找到tomcat所在的路径,直接回到根路径 “/”,而正常情况下,根路径是没有写权限的,需要使用管理员赋权限。
- log4j在配置完成之后,需要设置起打印日志的级别,假如没有设置,在Junit中,将无法打印日志。
3、后台的返回数据中,最好带上我们对数据库的修改的结果返回的前端。
为什么要在data中返回一个修改或者添加的对象
- 将数据返回给前端,前端容易判断数据是否添加或者修改成功
- 更新或者添加完数据经常需要刷新页面,将数据直接给了前端,前端不用再发一个请求来获取
- 单元测试的时候,能对数据库的DDL(增删改)操作的时候,我们能对数据进行审核,从何判断我们的操作是否是成功的。如下面的例子:
我们发送一个添加操作,添加一个SoftInfo对象,SoftInfo类定义如下:
public class SoftInfo {
private String id;
private String name;
}
添加完之后,由于我们进行了单元测试的事务回滚,我们将不能再数据库中看我们我们的的添加操作,无法判断操作是否成功。
为了解决上面的问题,我们可以在返回的json的数据中添加一个“data”字段,解析该json中的data字段数据,判断我们的添加操作是否成功的。json格式如下:
{
"status":200,
"data":{"id":"2","name":"测试"}
}
我们可以使用andExpect方法对返回的数据进行判断,用“$.属性”获取里面的数据,如我要获取返回数据中的"data.name",可以写成"$.data.name"。下面的例子是判断返回的data.name=“测试”。
三、遇到的问题
1、发送一个被@ResponseBody标识的参数,一直到400错误。 即无法发送一个json格式的数据到Controller层。
解决方法1:

SoftInfo softInfo = new SoftInfo();
//设置值
ObjectMapper mapper = new ObjectMapper();
ObjectWriter ow = mapper.writer().withDefaultPrettyPrinter();
java.lang.String requestJson = ow.writeValueAsString(softInfo);
String responseString = mockMvc.perform( post("/softs").contentType(MediaType.APPLICATION_JSON).content(requestJson)).andDo(print())
.andExpect(status().isOk()).andReturn().getResponse().getContentAsString();

解决方法2:使用com.alibaba.fastjson.JSONObject将对象转换为Json数据

SoftInfo softInfo = new SoftInfo();
//。。。设置值
String requestJson = JSONObject.toJSONString(folderInfo);
String responseString = mockMvc.perform( post("/softs").contentType(MediaType.APPLICATION_JSON).content(requestJson)).andDo(print())
.andExpect(status().isOk()).andReturn().getResponse().getContentAsString();

注意上面contentType需要设置成MediaType.APPLICATION_JSON,即声明是发送“application/json”格式的数据。使用content方法,将转换的json数据放到request的body中。
2、java.lang.NoClassDefFoundError: com/jayway/jsonpath/InvalidPathException
缺少了jar包:
可以添加一下的maven依赖

<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>0.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path-assert</artifactId>
<version>0.8.1</version>
<scope>test</scope>
</dependency>

学习连接:https://www.cnblogs.com/0201zcr/p/5756642.html
spring boot(三)Junit 测试controller的更多相关文章
- Spring Boot 解决方案 - JUnit 测试
简单的 JUnit 项目 回顾一下创建并运行简单的 JUnit 测试项目,先添加 JUnit 依赖然后编写类似如下模板的测试类,使用 IDE 的话直接用插件运行就行, 使用 Maven 的话运行命令 ...
- Spring Boot集成Junit测试
添加依赖: 在测试类上添加注解:
- Spring Boot应用的测试——Mockito
Spring Boot应用的测试——Mockito Spring Boot可以和大部分流行的测试框架协同工作:通过Spring JUnit创建单元测试:生成测试数据初始化数据库用于测试:Spring ...
- Spring Boot中的测试
文章目录 简介 添加maven依赖 Repository测试 Service测试 测试Controller @SpringBootTest的集成测试 Spring Boot中的测试 简介 本篇文章我们 ...
- spring boot项目如何测试,如何部署
有很多网友会时不时的问我,spring boot项目如何测试,如何部署,在生产中有什么好的部署方案吗?这篇文章就来介绍一下spring boot 如何开发.调试.打包到最后的投产上线. 开发阶段 单元 ...
- Spring Boot 整合Junit和redis
14. Spring Boot整合-Junit 目标:在Spring Boot项目中使用Junit进行单元测试UserService的方法 分析: 添加启动器依赖spring-boot-starter ...
- Spring框架下Junit测试
Spring框架下Junit测试 一.设置 1.1 目录 设置源码目录和测试目录,这样在设置产生测试方法时,会统一放到一个目录,如果没有设置测试目录,则不会产生测试代码. 1.2 增加配置文件 Res ...
- Spring Boot 1.4测试的改进
对Pivotal团队来说,工作上的好事情是他们拥有一个被叫做Pivotal Labs的灵活发展部门,拥有Labs团队的Lean 和 XP程序设计方法学的强大支持,例如结对编程和测试驱动开发.他们对于测 ...
- Spring Boot 1.4测试的简单理解
首先maven要引入spring-boot-starter-test这个包. 先看一段代码 @RunWith(SpringRunner.class) @SpringBootTest(webEnviro ...
随机推荐
- 从零学React Native之06flexbox布局
前面我们接触了好多React Native代码, 并没有介绍RN中的组件具体是如何布局的,这一篇文章,重点介绍下flexbox布局. 什么是flexbox布局 React中引入了flexbox概念,f ...
- Spring IoC 使用详解
在Spring中,依赖注入(DI)模式实现了控制反转(IoC)原理.让我们通过一个例子来帮助理解依赖注入.我们先看到java版的例子,然后在此基础上加上spring的功能.就例子而言,是相当地简单.Q ...
- top-100-of-the-best-useful-opensource-applications/
top-100-of-the-best-useful-opensource-applications/ http://www.ubuntulinuxhelp.com/top-100-of-the-be ...
- 独家 | TensorFlow 2.0将把Eager Execution变为默认执行模式,你该转向动态计算图了
机器之心报道 作者:邱陆陆 8 月中旬,谷歌大脑成员 Martin Wicke 在一封公开邮件中宣布,新版本开源框架——TensorFlow 2.0 预览版将在年底之前正式发布.今日,在上海谷歌开发者 ...
- SQL server无法绑定由多个部分绑定的标示符
原因https://blog.csdn.net/wolfalcon/article/details/54578215给了我启发,原来有犯错在insert和update的使用上了对于已存在的表(表中有字 ...
- rowStyle设置Bootstrap Table行样式
日常开发中我们通常会用到隔行变色来美化表格,也会根据每行的数据显示特定的背景颜色,如果库存低于100的行显示红色背景 CSS样式 <style> .bg-blue { background ...
- Vue 路由的嵌套使用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- HDU 1372
题意:模拟国际象棋马的走棋方式,和中国象棋一样马走日,8X8的棋盘,问从起点到终点的最短步数,国际象棋中数字代表行row,字母代表列column, 思路:记忆化深搜. #include<cstd ...
- 脑残的设计--- 视图(view)里面包含order by
2015/05/26 更新 今天又遇到了类似问题...尼玛无语了 编码规范啊 !!! 今天有个兄弟跟我说sql跑得太慢了,让我看看.sql如下: SELECT rownum row_num, pv.v ...
- 分布式全局唯一ID
方案一.UUID UUID的方式能生成一串唯一随机32位长度数据,它是无序的一串数据,按照开放软件基金会(OSF)制定的标准计算,UUID的生成用到了以太网卡地址.纳秒级时间.芯片ID码和许多可能的数 ...