详解Spring Boot实战之单元测试

本文介绍使用Spring测试框架提供的MockMvc对象,对Restful API进行单元测试

Spring测试框架提供MockMvc对象,可以在不需要客户端-服务端请求的情况下进行MVC测试,完全在服务端这边就可以执行Controller的请求,跟启动了测试服务器一样。

测试开始之前需要建立测试环境,setup方法被@Before修饰。通过MockMvcBuilders工具,使用WebApplicationContext对象作为参数,创建一个MockMvc对象。

MockMvc对象提供一组工具函数用来执行assert判断,都是针对web请求的判断。这组工具的使用方式是函数的链式调用,允许程序员将多个测试用例链接在一起,并进行多个判断。在这个例子中我们用到下面的一些工具函数:

perform(get(...))建立web请求。在我们的第三个用例中,通过MockMvcRequestBuilder执行GET请求。

andExpect(...)可以在perform(...)函数调用后多次调用,表示对多个条件的判断,这个函数的参数类型是ResultMatcher接口,在MockMvcResultMatchers这这个类中提供了很多返回ResultMatcher接口的工具函数。这个函数使得可以检测同一个web请求的多个方面,包括HTTP响应状态码(response status),响应的内容类型(content type),会话中存放的值,检验重定向、model或者header的内容等等。这里需要通过第三方库json-path检测JSON格式的响应数据:检查json数据包含正确的元素类型和对应的值,例如jsonPath("$.name").value("中文测试")用于检查在根目录下有一个名为name的节点,并且该节点对应的值是“testuser”。

本文对rest api的开发不做详细描述,如需了解可以参考 Spring Boot实战之Rest接口开发及数据库基本操作

1、修改pom.xml,添加依赖库json-path,用于检测JSON格式的响应数据

<dependency>
  <groupId>com.jayway.jsonpath</groupId>
  <artifactId>json-path</artifactId>
</dependency> 

2、添加用户数据模型UserInfo.java

package com.xiaofangtech.sunt.bean; 

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.Size; 

@Entity
@Table(name="t_userinfo")
public class UserInfo {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  @Size(min=0, max=32)
  private String name; 

  private Integer age;
  @Size(min=0, max=255)
  private String address; 

  public Long getId() {
    return id;
  } 

  public void setId(Long id) {
    this.id = id;
  } 

  public String getName() {
    return name;
  } 

  public void setName(String name) {
    this.name = name;
  } 

  public Integer getAge() {
    return age;
  } 

  public void setAge(Integer age) {
    this.age = age;
  } 

  public String getAddress() {
    return address;
  } 

  public void setAddress(String address) {
    this.address = address;
  }
}

3、添加控制器UserController.java,用于实现对用户的增删改查

package com.xiaofangtech.sunt.controller; 

import java.util.List; 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; 

import com.xiaofangtech.sunt.bean.UserInfo;
import com.xiaofangtech.sunt.repository.UserInfoRepository;
import com.xiaofangtech.sunt.utils.*; 

@RestController
@RequestMapping("user")
public class UserController {
  @Autowired
  private UserInfoRepository userRepositoy; 

  /***
   * 根据用户id,获取用户信息
   * @param id
   * @return
   */
  @RequestMapping(value="getuser", method=RequestMethod.GET)
  public Object getUser(Long id)
  {
    UserInfo userEntity = userRepositoy.findOne(id);
    ResultMsg resultMsg = new ResultMsg(ResultStatusCode.OK.getErrcode(), ResultStatusCode.OK.getErrmsg(), userEntity);
    return resultMsg;
  } 

  /***
   * 获取所有用户列表
   * @return
   */
  @RequestMapping(value="getalluser", method=RequestMethod.GET)
  public Object getUserList()
  {
    List<UserInfo> userEntities = (List<UserInfo>) userRepositoy.findAll();
    ResultMsg resultMsg = new ResultMsg(ResultStatusCode.OK.getErrcode(), ResultStatusCode.OK.getErrmsg(), userEntities);
    return resultMsg;
  } 

  /***
   * 新增用户信息
   * @param userEntity
   * @return
   */
  @Modifying
  @RequestMapping(value="adduser", method=RequestMethod.POST)
  public Object addUser(@RequestBody UserInfo userEntity)
  {
    userRepositoy.save(userEntity);
    ResultMsg resultMsg = new ResultMsg(ResultStatusCode.OK.getErrcode(), ResultStatusCode.OK.getErrmsg(), userEntity);
    return resultMsg;
  } 

  /***
   * 更新用户信息
   * @param userEntity
   * @return
   */
  @Modifying
  @RequestMapping(value="updateuser", method=RequestMethod.PUT)
  public Object updateUser(@RequestBody UserInfo userEntity)
  {
    UserInfo user = userRepositoy.findOne(userEntity.getId());
    if (user != null)
    {
      user.setName(userEntity.getName());
      user.setAge(userEntity.getAge());
      user.setAddress(userEntity.getAddress());
      userRepositoy.save(user);
    }
    ResultMsg resultMsg = new ResultMsg(ResultStatusCode.OK.getErrcode(), ResultStatusCode.OK.getErrmsg(), user);
    return resultMsg;
  } 

  /***
   * 删除用户
   * @param id
   * @return
   */
  @Modifying
  @RequestMapping(value="deleteuser", method=RequestMethod.DELETE)
  public Object deleteUser(Long id)
  {
    try
    {
      userRepositoy.delete(id);
    }
    catch(Exception exception)
    { 

    }
    ResultMsg resultMsg = new ResultMsg(ResultStatusCode.OK.getErrcode(), ResultStatusCode.OK.getErrmsg(), null);
    return resultMsg;
  }
}

4、修改测试类,添加对以上接口进行单元测试的测试用例

package com.xiaofangtech.sunt; 

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext; 

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiaofangtech.sunt.bean.UserInfo; 

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.hamcrest.Matchers.*;
//这是JUnit的注解,通过这个注解让SpringJUnit4ClassRunner这个类提供Spring测试上下文。
@RunWith(SpringJUnit4ClassRunner.class)
//这是Spring Boot注解,为了进行集成测试,需要通过这个注解加载和配置Spring应用上下
@SpringApplicationConfiguration(classes = SpringJUnitTestApplication.class)
@WebAppConfiguration
public class SpringJUnitTestApplicationTests { 

  @Autowired
  private WebApplicationContext context; 

  private MockMvc mockMvc;  

  @Before
  public void setupMockMvc() throws Exception {
    mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
  } 

  /***
   * 测试添加用户接口
   * @throws Exception
   */
  @Test
  public void testAddUser() throws Exception
  {
    //构造添加的用户信息
    UserInfo userInfo = new UserInfo();
    userInfo.setName("testuser2");
    userInfo.setAge(29);
    userInfo.setAddress("北京");
    ObjectMapper mapper = new ObjectMapper(); 

    //调用接口,传入添加的用户参数
    mockMvc.perform(post("/user/adduser")
        .contentType(MediaType.APPLICATION_JSON_UTF8)
        .content(mapper.writeValueAsString(userInfo)))
    //判断返回值,是否达到预期,测试示例中的返回值的结构如下{"errcode":0,"errmsg":"OK","p2pdata":null}
    .andExpect(status().isOk())
    .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
    //使用jsonPath解析返回值,判断具体的内容
    .andExpect(jsonPath("$.errcode", is(0)))
    .andExpect(jsonPath("$.p2pdata", notNullValue()))
    .andExpect(jsonPath("$.p2pdata.id", not(0)))
    .andExpect(jsonPath("$.p2pdata.name", is("testuser2")));
  } 

  /***
   * 测试更新用户信息接口
   * @throws Exception
   */
  @Test
  public void testUpdateUser() throws Exception
  {
    //构造添加的用户信息,更新id为2的用户的用户信息
    UserInfo userInfo = new UserInfo();
    userInfo.setId((long)2);
    userInfo.setName("testuser");
    userInfo.setAge(26);
    userInfo.setAddress("南京");
    ObjectMapper mapper = new ObjectMapper(); 

    mockMvc.perform(put("/user/updateuser")
        .contentType(MediaType.APPLICATION_JSON_UTF8)
        .content(mapper.writeValueAsString(userInfo)))
    //判断返回值,是否达到预期,测试示例中的返回值的结构如下
    //{"errcode":0,"errmsg":"OK","p2pdata":null}
    .andExpect(status().isOk())
    .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
    .andExpect(jsonPath("$.errcode", is(0)))
    .andExpect(jsonPath("$.p2pdata", notNullValue()))
    .andExpect(jsonPath("$.p2pdata.id", is(2)))
    .andExpect(jsonPath("$.p2pdata.name", is("testuser")))
    .andExpect(jsonPath("$.p2pdata.age", is(26)))
    .andExpect(jsonPath("$.p2pdata.address", is("南京")));
  } 

  /***
   * 测试根据用户id获取用户信息接口
   * @throws Exception
   */
  @Test
  public void testGetUser() throws Exception
  {
    mockMvc.perform(get("/user/getuser?id=2"))
    .andExpect(status().isOk())
    .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
    .andExpect(jsonPath("$.errcode", is(0)))
    .andExpect(jsonPath("$.p2pdata", notNullValue()))
    .andExpect(jsonPath("$.p2pdata.id", is(2)))
    .andExpect(jsonPath("$.p2pdata.name", is("testuser")))
    .andExpect(jsonPath("$.p2pdata.age", is(26)))
    .andExpect(jsonPath("$.p2pdata.address", is("南京")));
  } 

  /***
   * 测试获取用户列表接口
   * @throws Exception
   */
  @Test
  public void testGetUsers() throws Exception
  {
    mockMvc.perform(get("/user/getalluser"))
    .andExpect(status().isOk())
    .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
    .andExpect(jsonPath("$.errcode", is(0)))
    .andExpect(jsonPath("$.p2pdata", notNullValue()));
  }
}

5、运行测试,执行JUnit Test

一共执行4个测试用例,全都通过

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解SpringBoot之添加单元测试

    本文介绍了详解SpringBoot之添加单元测试,分享给大家,希望此文章对各位有所帮助 在SpringBoot里添加单元测试是非常简单的一件事,我们只需要添加SpringBoot单元测试的依赖jar,然后再添加两个注解就可搞定了. 首先我们来添加单元测试所需要的jar <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test<

  • 详解Spring Boot Junit单元测试

    Junit这种老技术,现在又拿出来说,不为别的,某种程度上来说,更是为了要说明它在项目中的重要性. 凭本人的感觉和经验来说,在项目中完全按标准都写Junit用例覆盖大部分业务代码的,应该不会超过一半. 刚好前段时间写了一些关于SpringBoot的帖子,正好现在把Junit再拿出来从几个方面再说一下,也算是给一些新手参考了. 那么先简单说一下为什么要写测试用例 1. 可以避免测试点的遗漏,为了更好的进行测试,可以提高测试效率 2. 可以自动测试,可以在项目打包前进行测试校验 3. 可以及时发现因

  • 详解Spring Boot实战之单元测试

    本文介绍使用Spring测试框架提供的MockMvc对象,对Restful API进行单元测试 Spring测试框架提供MockMvc对象,可以在不需要客户端-服务端请求的情况下进行MVC测试,完全在服务端这边就可以执行Controller的请求,跟启动了测试服务器一样. 测试开始之前需要建立测试环境,setup方法被@Before修饰.通过MockMvcBuilders工具,使用WebApplicationContext对象作为参数,创建一个MockMvc对象. MockMvc对象提供一组工具

  • 实例详解Spring Boot实战之Redis缓存登录验证码

    本章简单介绍redis的配置及使用方法,本文示例代码在前面代码的基础上进行修改添加,实现了使用redis进行缓存验证码,以及校验验证码的过程. 1.添加依赖库(添加redis库,以及第三方的验证码库) <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> </dependency&

  • 详解Spring Boot实战之Restful API的构建

    上一篇文章讲解了通过Spring boot与JdbcTemplate.JPA和MyBatis的集成,实现对数据库的访问.今天主要给大家分享一下如何通过Spring boot向前端返回数据. 在现在的开发流程中,为了最大程度实现前后端的分离,通常后端接口只提供数据接口,由前端通过Ajax请求从后端获取数据并进行渲染再展示给用户.我们用的最多的方式就是后端会返回给前端一个JSON字符串,前端解析JSON字符串生成JavaScript的对象,然后再做处理.本文就来演示一下Spring boot如何实现

  • 详解Spring Boot实战之Filter实现使用JWT进行接口认证

    本文介绍了spring Boot实战之Filter实现使用JWT进行接口认证,分享给大家 jwt(json web token) 用户发送按照约定,向服务端发送 Header.Payload 和 Signature,并包含认证信息(密码),验证通过后服务端返回一个token,之后用户使用该token作为登录凭证,适合于移动端和api jwt使用流程 本文示例接上面几篇文章中的代码进行编写,请阅读本文的同时可以参考前面几篇文章 1.添加依赖库jjwt,本文中构造jwt及解析jwt都使用了jjwt库

  • 详解Spring Boot实战之Rest接口开发及数据库基本操作

    本文介绍了Spring Boot实战之Rest接口开发及数据库基本操作,分享给大家 1.修改pom.xml,添加依赖库,本文使用的是mysql <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <

  • 详解spring boot rest例子

    简介:本文将帮助您使用 Spring Boot 创建简单的 REST 服务. 你将学习 什么是 REST 服务? 如何使用 Spring Initializr 引导创建 Rest 服务应用程序? 如何创建获取 REST 服务以检索学生注册的课程? 如何为学生注册课程创建 Post REST 服务? 如何利用 postman 执行 rest 服务? 本教程使用的 rest 服务 在本教程中,我们将使用适当的 URI 和 HTTP 方法创建三个服务: @GetMapping("/ students

  • 详解Spring Boot中使用Flyway来管理数据库版本

    如果没有读过上面内容的读者,有兴趣的可以一阅.在上面的使用JdbcTemplate一文中,主要通过spring提供的JdbcTemplate实现对用户表的增删改查操作.在实现这个例子的时候,我们事先在MySQL中创建了用户表.创建表的过程我们在实际开发系统的时候会经常使用,但是一直有一个问题存在,由于一个系统的程序版本通过git得到了很好的版本控制,而数据库结构并没有,即使我们通过Git进行了语句的版本化,那么在各个环境的数据库中如何做好版本管理呢?下面我们就通过本文来学习一下在Spring B

  • 详解spring boot starter redis配置文件

    spring-boot-starter-Redis主要是通过配置RedisConnectionFactory中的相关参数去实现连接redis service. RedisConnectionFactory是一个接口,有如下4个具体的实现类,我们通常使用的是JedisConnectionFactory. 在spring boot的配置文件中redis的基本配置如下: # Redis服务器地址 spring.redis.host=192.168.0.58 # Redis服务器连接端口 spring.

  • 详解Spring boot Admin 使用eureka监控服务

    前言 最近刚好有空,来学习一下如何搭建spring boot admin环境.其中遇到很多的坑. 网上大多都是使用admin-url的方式直接来监控的,感觉一点也不灵活,这不是我想要的结果,所以本篇介绍借助eureka服务注册和发现功能来灵活监控程序. 本文主要记录spring boot admin的搭建过程,希望能有所帮助.其实非常的简单,不要被使用常规方式的误导! 环境介绍 IDE:intellij idea jdk: java8 maven:3.3.9 spring boot:1.5.6

  • 详解spring boot jpa整合QueryDSL来简化复杂操作

    前言 使用过spring data jpa的同学,都很清楚,对于复杂的sql查询,处理起来还是比较复杂的,而本文中的QueryDSL就是用来简化JPA操作的. Querydsl定义了一种常用的静态类型语法,用于在持久域模型数据之上进行查询.JDO和JPA是Querydsl的主要集成技术.本文旨在介绍如何使用Querydsl与JPA组合使用.JPA的Querydsl是JPQL和Criteria查询的替代方法.QueryDSL仅仅是一个通用的查询框架,专注于通过Java API构建类型安全的SQL查

随机推荐