转自:http://www.importnew.com/21153.html

一、单元测试的目的

简单来说就是在我们增加或者改动一些代码以后对所有逻辑的一个检测,尤其是在我们后期修改后(不论是增加新功能,修改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=“测试”。

@Test
    public void testCreateSeewoAccountUser() throws Exception {
        mockMvc.perform(post("/users")
                        .contentType(MediaType.APPLICATION_FORM_URLENCODED) 
        ).andExpect(status().isOk())
        .andExpect(jsonPath("$.data.name", is("测试")))) 
        .andExpect(jsonPath("$.data.createTime", notNullValue()))
        ;
    }

三、遇到的问题

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>

  

Junit测试Controller(MockMVC使用),以及传输@RequestBody数据解决办法的更多相关文章

  1. Junit测试Controller(MockMVC使用),传输@RequestBody数据解决办法

    一.单元测试的目的 简单来说就是在我们增加或者改动一些代码以后对所有逻辑的一个检测,尤其是在我们后期修改后(不论是增加新功能,修改bug),都可以做到重新测试的工作.以减少我们在发布的时候出现更过甚至 ...

  2. spring boot(三)Junit 测试controller

    Junit测试Controller(MockMVC使用),传输@RequestBody数据解决办法 一.单元测试的目的 简单来说就是在我们增加或者改动一些代码以后对所有逻辑的一个检测,尤其是在我们后期 ...

  3. mybatis-generator没有自动生成代码和Junit测试controller

    本来mybatis的generator想要自动生成增删改的,但是到后来语句就两个select,原因是数据中没有给字段加primary,就不会有删改增. 以及Controller的Junit测试 先导入 ...

  4. mysql存储过程controller的not found造成混乱的解决办法

    打草稿 问题:对于select  var1 into var2 ,单select的结果为空的时候(空的意思是没有找到数据,不是该值为null) ,会触发controller的not found 当游标 ...

  5. SpringBoot Junit测试Controller

    原文链接:https://blog.csdn.net/xiaolyuh123/article/details/73281522 import java.util.List; import org.sp ...

  6. 打开word时出现the setup controller has encountered a problem during install解决办法

    问题电脑为win7,office是默认安装 删除下面文件夹即可解决该问题 C:\Program Files\Common Files\Microsoft Shared\OFFICE12\Office ...

  7. jmeter 非GUI执行测试,导入jtl文件没有响应数据出来办法

    jemter 官方也一直强调要在非GUI下执行 Run your JMeter test in command-line non-GUI mode as 在linux下执行jmeter压力测试,生成j ...

  8. linux安装 uwsgi 测试 test.py 不显示hello world 的解决办法

    一般部署项目到服务器,会安装uwsgi,但是很多教程在安装它的时候会让你测试一下安装好了没,于是就有很多像我一样懵逼的少年掉进一个坑里出不来,很久.很久... 那就是最后浏览器输入ip:8000端口后 ...

  9. 使用 TestNG 测试的时候事务总是roll back的解决办法

    为要测试方法加上 @Rollback(false) 注解

随机推荐

  1. feign传输String json串 自动转义 \ 解决方法

    @RequestMapping(value={"/sysOrgRest/getInfoByOrgIds"}, method={org.springframework.web.bin ...

  2. Spring Cloud微服务接口这么多怎么调试

    导读 我们知道在微服务架构下,软件系统会被拆分成很多个独立运行的服务,而这些服务间需要交互通信,就需要定义各种各样的服务接口.具体来说,在基于Spring Cloud的微服务模式中,各个微服务会基于S ...

  3. Hyper-v设置linux固定ip

    一.创建CentOS 7专用的虚拟交换机 打开Hyper-v控制面板,找到右边的“虚拟交换机管理器” 进去后,点击“新建虚拟网络交换机”,填写名称后,选择“内部” 打开网络中心,修改配置如下图,注意i ...

  4. Why do I write a blog

    I believe the most beautiful and elegant answer to this question is from Churchill. "On a peace ...

  5. node获取本机动态IP,并对应修改相关JavaScript文件的IP地址

    目录 由于本机是自动获取分配的动态IP,所以每次重启后需要重新更改与IP相关文件 参考 时间:2018-08-02,更新时间:2018-11-06 注意:在win10环境运行无问题 由于本机是自动获取 ...

  6. Spring Boot 中的同一个 Bug,竟然把我坑了两次!

    真是郁闷,不过这事又一次提醒我解决问题还是要根治,不能囫囵吞枣,否则相同的问题可能会以不同的形式出现,每次都得花时间去搞.刨根问底,一步到位,再遇到类似问题就可以分分钟解决了. 如果大家没看过松哥之前 ...

  7. 面系那个对象开发原则.高内聚.低耦合+Python安装详细教程+print输出带颜色的方法

    面系那个对象开发原则.高内聚.低耦合 软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准.划分摸块的一个准则就是高内聚低耦合. 这是软件工程中的概念,是判断设计好坏的标准,主要是面向OO的设计, ...

  8. IntelliJ IDEA提升效率开发插件必备

    工欲善其事,必先利其器,好的工具可以提升我们的开发效率,下面介绍几款个人觉得比较好的编辑器插件,不仅炫酷更重要可以提高你的工作效率. 本文是作者辛苦整理的16款插件,每个都是超级实用的,不好不介绍,相 ...

  9. EventEmitter的前端实现

    EventEmitter简介 EventEmitter是Node.js的内置模块events提供的一个类,它是Node事件流的核心,EventEmitter是服务端的东西, 前端已经有event-em ...

  10. 重学计算机组成原理(十)- "烫烫烫"乱码的由来

    程序 = 算法 + 数据结构 对应到计算机的组成原理(硬件层面) 算法 --- 各种计算机指令 数据结构 --- 二进制数据 计算机用0/1组成的二进制,来表示所有信息 程序指令用到的机器码,是使用二 ...