javascript
Spring Boot 应用的测试
Spring Boot 應(yīng)用的測試
《Spring Boot 實(shí)戰(zhàn)開發(fā)》(陳光劍)
—— 基于 Gradle + Kotlin的企業(yè)級應(yīng)用開發(fā)最佳實(shí)踐
本書寫到這里,Spring Boot 2.0.0.RC1版本已經(jīng)于2018.1.31 發(fā)布。這是本書最后一章,本章介紹 Spring Boot 應(yīng)用的測試(質(zhì)量保障)相關(guān)的內(nèi)容。我們在項(xiàng)目開發(fā)中使用分層架構(gòu),在測試中也進(jìn)行分層測試。
1.1 準(zhǔn)備工作
本節(jié)先來創(chuàng)建一個(gè)基于Spring MVC、 Spring Data JPA的 Spring Boot, 完成Dao 層、 Service 層、Controller 層代碼的編寫,為后面的測試代碼的編寫做準(zhǔn)備。
使用http://start.spring.io/ 創(chuàng)建項(xiàng)目、導(dǎo)入此 Gradle 項(xiàng)目到 IDEA 中。配置 Kotlin Compiler 版本與Target JVM 版本。最后等待項(xiàng)目構(gòu)建完畢。我們將得到一個(gè)初始Spring Boot 工程。詳細(xì)的代碼參考本章給出的示例工程源碼。
下面我們來詳細(xì)講解怎樣針對 Spring Boot 項(xiàng)目進(jìn)行分層測試。
1.2 分層測試
我們在開發(fā)階段過程中,單元測試通常是必要的。Spring Boot 提供的spring-boot-test 模塊基于 spring-test 模塊和junit 框架,封裝集成了功能強(qiáng)大的結(jié)果匹配校驗(yàn)器assertj 、hamcrest Matcher、 Web 請求 Mock 對象、 httpclient、JsonPath (測試 JSON 數(shù)據(jù))、mockito、selenium等。
測試代碼通常放在 src/test 目錄下,包目錄規(guī)范是跟 src/main 目錄保持一致。測試代碼目錄結(jié)構(gòu)設(shè)計(jì)如下
圖15-1 測試代碼目錄結(jié)構(gòu)
測試代碼的分層邏輯與項(xiàng)目源代碼中的 dao層、service 層、controller 層各自對應(yīng)。
下面我們來開發(fā)具體的測試類。
1.2.1 Dao 層測試
在包c(diǎn)om.easy.springboot.demo_testing_and_deploy.dao下面添加UserDaoTest.kt測試類,代碼如下
其中,需要測試類上需要添加@RunWith(SpringRunner.class) 和 @SpringBootTest 注解。這里的 @RunWith這里就不多做解釋了,在 JUnit中這個(gè)是最常用的注解。
@SpringBootTest這個(gè)注解是SpringBoot項(xiàng)目測試的核心注解,標(biāo)識該測試類以SpringBoot方式運(yùn)行,該注解的定義如下:
在上面的 @SpringBootTest 注解源碼中最重要的是 @BootstrapWith,該注解配置了測試類的啟動核心類SpringBootTestContextBootstrapper。
在UserDaoTest測試類中可以直接使用@Autowired來裝配UserDao這個(gè) Bean。而且,@SpringBootTest 注解會自動幫我們完成啟動一個(gè) Spring 容器 ApplicationContext,然后連接數(shù)據(jù)庫,執(zhí)行一套完整的業(yè)務(wù)邏輯。
1.2.2 Service 層測試
Service 層的代碼測試類跟 Dao 層類似,例如UserServiceTest.kt 測試代碼如下
1.2.3 使用 Mockito 測試 Service 層代碼
上面的測試代碼是連接真實(shí)的數(shù)據(jù)庫來執(zhí)行真實(shí)的 Dao 層數(shù)據(jù)庫查詢邏輯。
而在實(shí)際開發(fā)的場景中,我們有時(shí)候需要獨(dú)立于數(shù)據(jù)庫進(jìn)行 Service 層邏輯的開發(fā)。這個(gè)時(shí)候就可以直接把數(shù)據(jù)庫Dao層代碼Mock 掉。例如在UserService中有一個(gè) getOne()方法,具體的實(shí)現(xiàn)代碼是
下面,我們就使用 Mockito 來把 UserDao 層代碼 Mock 掉。Mockito 主要用于 service 層的 mock 測試。mock 的對象一般是對 DAO 層的依賴; 另外就是別人的Service實(shí)現(xiàn)類。
新建測試類MockUserServiceTest.kt 代碼如下:
需要注意的是,該測試的執(zhí)行 Runner 是 @RunWith(MockitoJUnitRunner::class) 。
? 使用 @Mock 注解標(biāo)記這個(gè)對象是被 Mock 的。
? 使用 @InjectMocks 注解標(biāo)注一個(gè)實(shí)現(xiàn)類UserServiceImpl,Mockito 會自動把 @Spy 或 @Mock標(biāo)注的 Mock 對象注入到實(shí)現(xiàn)類UserServiceImpl的方法執(zhí)行中,相當(dāng)于把實(shí)現(xiàn)類中的UserDao對象使用mockUserDao對象給“偷梁換柱”了。
運(yùn)行上面的測試類,可以發(fā)現(xiàn)測試成功
圖15-2 MockUserServiceTest測試成功
在測試代碼的打印日志中,輸出的 getOne(1)方法的返回對象是我們 Mock 的對象mockUser :
提示:更多關(guān)于 Mockito 的使用請參考官網(wǎng)文檔:http://site.mockito.org/
1.2.4 Controller 層測試
通過上面的實(shí)例,我們已經(jīng)了解了在實(shí)際項(xiàng)目開發(fā)測試中對dao層代碼和service層代碼的測試,還學(xué)習(xí)了 Mockito 技術(shù)的相關(guān)內(nèi)容。spring-boot-starter-test中提供了對項(xiàng)目測試功能的強(qiáng)大支持,更難得的是其中增加了對Controller層測試的支持。
下面我們來測試接口 http://127.0.0.1:8012/user/1 。該接口的輸出的JSON數(shù)據(jù)如下
UserControllerTest測試代碼如下
@RunWith(SpringJUnit4ClassRunner::class) @SpringBootTest class UserControllerTest {@Autowiredlateinit var context: WebApplicationContextlateinit var mvc: MockMvc@Beforefun setUp() {mvc = MockMvcBuilders.webAppContextSetup(context).build()}@Testfun testFetchUser1() {mvc.perform(MockMvcRequestBuilders.get("/user/1").contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk).andDo(MockMvcResultHandlers.print()).andExpect(MockMvcResultMatchers.content().string(Matchers.containsString(""""username":"user"""".trimIndent()))).andDo {println("it.request.method=${it.request.method}")println("it.response.contentAsString=${it.response.contentAsString}")}.andExpect(MockMvcResultMatchers.jsonPath("$.id", Matchers.equalTo(1))).andExpect(MockMvcResultMatchers.jsonPath("$.roles[0].role", Matchers.equalTo("ROLE_USER")))} }其中, MockMvc是一個(gè)被final修飾的類型,該類無法被繼承使用。這個(gè)類在包org.springframework.test.web.servlet下面,是Spring提供的模擬SpringMVC請求的實(shí)例類,該類由MockMvcBuilders通過WebApplicationContext實(shí)例進(jìn)行創(chuàng)建。MockMvcBuilder接口簽名如下
package org.springframework.test.web.servlet; public interface MockMvcBuilder {MockMvc build(); }上面的代碼簡單說明如下表15-1。
表15-1
方法名
功能說明
Perform()
方法其實(shí)只是為了構(gòu)建一個(gè)請求,并且返回ResultActions實(shí)例,使用該實(shí)例可以獲取到請求的返回內(nèi)容。
MockMvcRequestBuilders
支持構(gòu)建多種請求方法對象,如:Post、Get、Put、Delete等常用的請求方式,其中的參數(shù)"/user/1"則是我們需要請求的本項(xiàng)目的相對路徑,/ 則是項(xiàng)目請求的根路徑。另外,還可以調(diào)用param() 方法用于在發(fā)送請求時(shí)攜帶參數(shù)。
andExpect()
是ResultActions中成員,入?yún)⑹荝esultMatcher類型:
ResultActions andExpect(ResultMatcher matcher)
在發(fā)送請求后對響應(yīng)結(jié)果進(jìn)行匹配校驗(yàn)時(shí)調(diào)用。其中MockMvcResultMatchers 抽象類是一個(gè)靜態(tài)工廠,用于生產(chǎn)ResultMatcher對象。MockMvcResultMatchers中提供了豐富的匹配器。
1.2.5 JSON接口測試
使用 JsonPath 我們可以像 JavaScript 語法一樣方便地進(jìn)行 JSON 數(shù)據(jù)返回的訪問操作。例如下面的這兩行代碼
.andExpect(MockMvcResultMatchers.jsonPath("$.id", Matchers.equalTo(1)))
.andExpect(MockMvcResultMatchers.jsonPath("$.roles[0].role", Matchers.equalTo("ROLE_USER")))
這里的Matchers類是org.hamcrest包下面的類。org.hamcrest.Matchers 類中提供了豐富的斷言方法,這些方法的具體使用可以閱讀Matchers 類的源碼深入了解。
其中,"$.id" 和 "$.roles[0].role" 就是 JsonPath的表達(dá)式語法。
提示:更多關(guān)于 JsonPath 的內(nèi)容可以參考: https://github.com/json-path/JsonPath 。
運(yùn)行上面的測試代碼,測試成功:
圖15-3 UserControllerTest測試成功
使用命令 $ gradle test 可以一次性全部執(zhí)行 src/test 目錄下面的測試類。在 IDEA 中可以直接郵寄 src/test 目錄,選擇 Run > All Tests執(zhí)行所有測試類,如下圖所示
圖15-4 選擇 Run > All Tests執(zhí)行 所有測試類
另外,Gradle Test 生成的測試報(bào)告在 build/reports/tests/test/index.html 中,如下圖
圖15-5 Gradle Test 生成的測試報(bào)告在 build/reports/tests/test/index.html 中
測試報(bào)告的部分內(nèi)容截圖如下
圖15-6 測試報(bào)告Summary
圖15-7 UserControllerTest測試報(bào)告
圖15-8 MockUserServiceTest測試報(bào)告
1.3 本章小結(jié)
本章介紹了Spring Boot項(xiàng)目如何測試。Spring Boot 應(yīng)用對Web層測試提供強(qiáng)大的支持:采用MockMvc方式測試Web請求,根據(jù)傳遞的不用參數(shù)以及請求返回對象反饋信息進(jìn)行驗(yàn)證測試。另外,針對 JSON 數(shù)據(jù)接口,使用 JsonPath 可以方便地進(jìn)行 JSON 數(shù)據(jù)結(jié)果的校驗(yàn)。
提示:本章項(xiàng)目工程源代碼:
https://github.com/KotlinSpringBoot/demo_testing_and_deploy
總結(jié)
以上是生活随笔為你收集整理的Spring Boot 应用的测试的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 迅雷CEO陈磊出席深圳IT领袖峰会 解析
- 下一篇: 干货:Java并发编程必懂知识点解析