SpringBoot基本操作(六)——SpringBoot使用Junit4單元測試(有demo)
SpringBoot2.0筆記
本篇介紹Springboot單元測試的一些基本操作,有人說一個合格的程式設計師必須熟練使用單元測試,接下來我們一起在Springboot專案中整合Junit4單元測試。
本文使用idea工具構建Springboot2.0+SpringMvc+Thymeleaf+SpringDataJPA+MySql專案
一、IDEA下載並安裝Junit外掛
點選file-settings,如圖按照順序操作即可,我這裡已經安裝過了所以最後一步不會顯示install按鈕。
二、引入關鍵依賴,完整pom文末給出
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <!--<scope>test</scope>--> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> <version>2.0.0.RELEASE</version> </dependency>
三、新建UserController.java作為被測試類
package com.springboot.demo.controller; import com.springboot.demo.base.controller.BaseController; import com.springboot.demo.base.utils.StateParameter; import com.springboot.demo.entity.User; import com.springboot.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; import java.util.Date; import java.util.List; /** * @ClassName: UserController * @Auther: zhangyingqi * @Date: 2018/8/27 17:30 * @Description: */ @Controller @RequestMapping(value="/user") public class UserController extends BaseController{ @Autowired UserService userService; /** * @auther: zhangyingqi * @date: 17:37 2018/8/27 * @param: [request, user] * @return: org.springframework.ui.ModelMap * @Description: 使用者儲存&更新 */ @RequestMapping(value="/add", method = RequestMethod.POST) @ResponseBody public ModelMap add(User user){ try { if(StringUtils.isEmpty(user.getId())){ user.setId(getUuid()); }else{ user.setUpdateDate(new Date()); } userService.save(user); logger.info("儲存成功"); return getModelMap(StateParameter.SUCCESS, user, "儲存成功"); } catch (Exception e) { e.printStackTrace(); return getModelMap(StateParameter.FAULT, null, "儲存失敗"); } } /** * @auther: zhangyingqi * @date: 17:47 2018/8/27 * @param: [id] * @return: org.springframework.ui.ModelMap * @Description: 刪除使用者 */ @RequestMapping(value="/delete", method = RequestMethod.GET) @ResponseBody public ModelMap delete(String id){ try { User user = userService.findById(id); if(user==null){ return getModelMap(StateParameter.FAULT, user, "找不到該使用者"); } userService.delete(user); logger.info("刪除成功"); return getModelMap(StateParameter.SUCCESS, null, "刪除成功"); } catch (Exception e) { e.printStackTrace(); return getModelMap(StateParameter.FAULT, null, "刪除失敗"); } } /** * @auther: zhangyingqi * @date: 17:47 2018/8/27 * @param: [request] * @return: java.lang.String * @Description: 查詢使用者列表 */ @RequestMapping(value="/list") public String view(HttpServletRequest request){ List<User> list = userService.findAll(); request.setAttribute("list", list); logger.info("返回列表頁面"); return "/demoPage/listPage"; } }
UserController類中用到的其他依賴都可以去我文章開始提供的GitHub地址下載,其實看過我之前文章的人應該都知道,最簡單的辦法就是直接下載demo了,當然你也可以自己編寫一個controller類,在本篇中並沒有特別要求。
當然不能少了實體類User.java,父類前幾篇文章我都有寫過,demo裡也有,節省文字這裡不再給出。
package com.springboot.demo.entity; import lombok.Data; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Table; /** * @ClassName: User * @Auther: zhangyingqi * @Date: 2018/8/27 17:17 * @Description: */ @Entity @Table(name = "user") @Data public class User extends BaseEntity{ @Column(name = "name", length = 100) private String name; @Column(name = "age") private int age; }
另外還需要list方法返回的實際頁面,在專案template下demoPage下新建listPage.html
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>使用者列表</title>
</head>
<body>
<div>
<table>
<thead>
<tr>
<th>使用者名稱稱</th>
<th>年齡</th>
<th>建立時間</th>
</tr>
</thead>
<tbody>
<tr th:if="${list !=null}" th:each="item : ${list}">
<td th:text="${item.name}"></td>
<td th:text="${item.age}"></td>
<td th:text="${#dates.format(item.create_date, 'yyyy-MM-dd')}"></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
四、生成單元測試類
在UserController中按住alt+insert鍵,如圖選擇將自動生成測試類。
這時Junit工具將自動生成一個test目錄,在同路徑下生成同類名+Test組合名稱UserControllerTest.java類,這就是自動生成的測試類。
我們改造這個測試類的內容
首先在類名上加入註解@RunWith和@SpringBootTest,後者需指定springboot啟動類
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class UserControllerTest {
}
然後引入MockMvc物件及WebApplicationContext上下文,如果涉及業務的測試內容還需引入其他依賴,@Before表示在測試方法執行之前執行會該方法,所以我們在這裡例項化mockmvc物件,這樣後面就可以操作他了。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class UserControllerTest {
/**
* 模擬mvc測試物件
*/
private MockMvc mockMvc;
/**
* web專案上下文
*/
@Autowired
private WebApplicationContext webApplicationContext;
/**
* 業務資料介面
*/
@Autowired
private UserService userService;
/**
* 所有測試方法執行之前執行該方法
*/
@Before
public void before() {
//獲取mockmvc物件例項
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
}
接下來我們編寫測試程式碼,首先對UserController中的查詢使用者列表方法進行測試,方法頭部需新增@Test註解,具體方法內容如下,使用MockMvcRequestBuilders模擬get請求,status接收返回狀態,responseString接收返回的內容。Assert.assertEquals
為通用的判斷測試執行結果方法,其中三個引數分別為:不一致時提示資訊,預期得到結果,實際得到結果。
@Test
public void testPage() throws Exception {
MvcResult mvcResult = mockMvc
.perform(// 1
MockMvcRequestBuilders.get("/user/list") // 2
//.param("name","getList") // 3
)
.andReturn();// 4
int status = mvcResult.getResponse().getStatus(); // 5
String responseString = mvcResult.getResponse().getContentAsString(); // 6
Assert.assertEquals("請求錯誤", 200, status); // 7
Assert.assertEquals("返回結果不一致", "/demoPage/listPage", responseString); // 8
}
接下來執行這個單元測試模組,IDEA自動檢測到這是一個測試方法,我們直接點選方法左邊的啟動按鈕即可,因為我已經執行過並且測試未通過,所以顯示紅色,本來是綠色。
如果執行成功會提示success,我這裡提供的這個測試方法執行後是報失敗的,具體原因是在列表頁面獲取不到實體中的create_date欄位
做如下修改,將create_date改為createDate即可,所以我們可以看到,測試頁面時會去渲染方法返回的整個html頁面,如果有語法錯誤將會報錯,測試執行失敗。
<tbody>
<tr th:if="${list !=null}" th:each="item : ${list}">
<td th:text="${item.name}"></td>
<td th:text="${item.age}"></td>
<td th:text="${#dates.format(item.create_date, 'yyyy-MM-dd')}"></td>
</tr>
</tbody>
再次啟動測試單元測試不再報錯,但是依舊執行失敗,提示“返回結果不一致”,我們點選結果對比發現返回結果有差異,所以未達到期望,直接返回了不一致時的提示資訊,因此我們在測試返回頁面時只需執行Assert.assertEquals("請求錯誤", 200, status); 即可,不必再判斷返回期望。
註釋掉返回結果預期判斷之後執行測試成功。
那麼返回結果預期判斷怎麼用呢,我們看下面的第二個測試刪除使用者方法,param可以新增傳遞的引數,預期結果為刪除成功,我這裡模擬了刪除成功後的返回json資料,實際應用中可根據情況設定。
可以看到後臺列印刪除成功,同時單元測試執行通過。
本篇我通過Junit4單元測試對springboot專案的controller類進行測試,掌握基本的單元測試在springboot中整合的使用方法。
下面給出完整的pom包,推薦大家直接下載文首給出的demo,可以直接執行,方便又快捷。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.springboot</groupId>
<artifactId>springbootJunit4</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>springbootJunit4</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<!--<scope>provided</scope>-->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</exclusion>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.10.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!--<scope>test</scope>-->
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
全文完,2018/8/30
寫博文不易,轉載請註明出處。