欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解Spring Boot实战之单元测试

程序员文章站 2023-12-03 18:27:52
本文介绍使用spring测试框架提供的mockmvc对象,对restful api进行单元测试 spring测试框架提供mockmvc对象,可以在不需要客户端-服务端请求...

本文介绍使用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

详解Spring Boot实战之单元测试

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

详解Spring Boot实战之单元测试

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