詳解Spring Boot實戰(zhàn)之單元測試
本文介紹使用Spring測試框架提供的MockMvc對象,對Restful API進(jìn)行單元測試
Spring測試框架提供MockMvc對象,可以在不需要客戶端-服務(wù)端請求的情況下進(jìn)行MVC測試,完全在服務(wù)端這邊就可以執(zhí)行Controller的請求,跟啟動了測試服務(wù)器一樣。
測試開始之前需要建立測試環(huán)境,setup方法被@Before修飾。通過MockMvcBuilders工具,使用WebApplicationContext對象作為參數(shù),創(chuàng)建一個MockMvc對象。
MockMvc對象提供一組工具函數(shù)用來執(zhí)行assert判斷,都是針對web請求的判斷。這組工具的使用方式是函數(shù)的鏈?zhǔn)秸{(diào)用,允許程序員將多個測試用例鏈接在一起,并進(jìn)行多個判斷。在這個例子中我們用到下面的一些工具函數(shù):
perform(get(...))建立web請求。在我們的第三個用例中,通過MockMvcRequestBuilder執(zhí)行GET請求。
andExpect(...)可以在perform(...)函數(shù)調(diào)用后多次調(diào)用,表示對多個條件的判斷,這個函數(shù)的參數(shù)類型是ResultMatcher接口,在MockMvcResultMatchers這這個類中提供了很多返回ResultMatcher接口的工具函數(shù)。這個函數(shù)使得可以檢測同一個web請求的多個方面,包括HTTP響應(yīng)狀態(tài)碼(response status),響應(yīng)的內(nèi)容類型(content type),會話中存放的值,檢驗重定向、model或者h(yuǎn)eader的內(nèi)容等等。這里需要通過第三方庫json-path檢測JSON格式的響應(yīng)數(shù)據(jù):檢查json數(shù)據(jù)包含正確的元素類型和對應(yīng)的值,例如jsonPath("$.name").value("中文測試")用于檢查在根目錄下有一個名為name的節(jié)點,并且該節(jié)點對應(yīng)的值是“testuser”。
本文對rest api的開發(fā)不做詳細(xì)描述,如需了解可以參考 Spring Boot實戰(zhàn)之Rest接口開發(fā)及數(shù)據(jù)庫基本操作
1、修改pom.xml,添加依賴庫json-path,用于檢測JSON格式的響應(yīng)數(shù)據(jù)
<dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> </dependency>
2、添加用戶數(shù)據(jù)模型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,用于實現(xiàn)對用戶的增刪改查
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;
/***
* 根據(jù)用戶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、修改測試類,添加對以上接口進(jìn)行單元測試的測試用例
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注解,為了進(jìn)行集成測試,需要通過這個注解加載和配置Spring應(yīng)用上下
@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
{
//構(gòu)造添加的用戶信息
UserInfo userInfo = new UserInfo();
userInfo.setName("testuser2");
userInfo.setAge(29);
userInfo.setAddress("北京");
ObjectMapper mapper = new ObjectMapper();
//調(diào)用接口,傳入添加的用戶參數(shù)
mockMvc.perform(post("/user/adduser")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(mapper.writeValueAsString(userInfo)))
//判斷返回值,是否達(dá)到預(yù)期,測試示例中的返回值的結(jié)構(gòu)如下{"errcode":0,"errmsg":"OK","p2pdata":null}
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
//使用jsonPath解析返回值,判斷具體的內(nèi)容
.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
{
//構(gòu)造添加的用戶信息,更新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)))
//判斷返回值,是否達(dá)到預(yù)期,測試示例中的返回值的結(jié)構(gòu)如下
//{"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("南京")));
}
/***
* 測試根據(jù)用戶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、運行測試,執(zhí)行JUnit Test

一共執(zhí)行4個測試用例,全都通過

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot實現(xiàn)yml配置文件為變量賦值
這篇文章主要介紹了SpringBoot實現(xiàn)yml配置文件為變量賦值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02
最新IntelliJ?IDEA?2022配置?Tomcat?8.5?的詳細(xì)步驟演示
這篇文章主要介紹了IntelliJ?IDEA?2022?詳細(xì)配置?Tomcat?8.5?步驟演示,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-08-08
springboot+springJdbc+postgresql 實現(xiàn)多數(shù)據(jù)源的配置
本文主要介紹了springboot+springJdbc+postgresql 實現(xiàn)多數(shù)據(jù)源的配置,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09
Springboot實現(xiàn)Activemq死信隊列詳解
這篇文章主要介紹了Springboot實現(xiàn)Activemq死信隊列詳解,Activemq服務(wù)端配置重新投遞次數(shù)超過?MaximumRedeliveries?,則會進(jìn)入死信隊列,默認(rèn)情況,有一個死信隊列:AcitveMQ.DLQ,所有的消息都投遞到此隊列,包括過期消息,重投遞失敗消息,需要的朋友可以參考下2023-12-12
Spring cloud oauth2如何搭建認(rèn)證資源中心
這篇文章主要介紹了Spring cloud oauth2如何搭建認(rèn)證資源中心,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-11-11

