看到一篇很是好的關於Springboot單元測試的文章,特此轉過來,原文地址: Spring Boot乾貨系列:(十二)Spring Boot使用單元測試
此次來介紹下Spring Boot中對單元測試的整合使用,本篇會經過如下4點來介紹,基本知足平常需求java
Spring Boot中引入單元測試很簡單,依賴以下:程序員
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
在生成的測試類中就能夠寫單元測試了。用spring自帶spring-boot-test的測試工具類便可,spring-boot-starter-test 啓動器能引入這些 Spring Boot 測試模塊:web
Spring Boot中單元測試類寫在在src/test/java目錄下,你能夠手動建立具體測試類,若是是IDEA,則能夠經過IDEA自動建立測試類,以下圖,也能夠經過快捷鍵⇧⌘T
(MAC)或者Ctrl+Shift+T
(Window)來建立,以下:spring
自動生成測試類以下:
json
而後再編寫建立好的測試類,具體代碼以下:springboot
package com.dudu.service; import com.dudu.domain.LearnResource; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import static org.hamcrest.CoreMatchers.*; @RunWith(SpringRunner.class) @SpringBootTest public class LearnServiceTest { @Autowired private LearnService learnService; @Test public void getLearn(){ LearnResource learnResource=learnService.selectByKey(1001L); Assert.assertThat(learnResource.getAuthor(),is("嘟嘟MD獨立博客")); } }
上面就是最簡單的單元測試寫法,頂部只要@RunWith(SpringRunner.class)
和SpringBootTest
便可,想要執行的時候,鼠標放在對應的方法,右鍵選擇run該方法便可。網絡
RunWith解釋session
@RunWith就是一個運行器,如 @RunWith(SpringJUnit4ClassRunner.class),讓測試運行於Spring測試環境,@RunWith(SpringJUnit4ClassRunner.class)使用了Spring的SpringJUnit4ClassRunner,以便在測試開始的時候自動建立Spring的應用上下文。其餘的想建立spring容器的話,就得子啊web.xml配置classloder。 註解了@RunWith就能夠直接使用spring容器,直接使用@Test註解,不用啓動spring容器
測試用例中我使用了assertThat斷言,下文中會介紹,也推薦你們使用該斷言。mvc
上面只是針對Service層作測試,可是有時候須要對Controller層(API)作測試,這時候就得用到MockMvc了,你能夠沒必要啓動工程就能測試這些接口。app
MockMvc實現了對Http請求的模擬,可以直接使用網絡的形式,轉換到Controller的調用,這樣可使得測試速度快、不依賴網絡環境,並且提供了一套驗證的工具,這樣可使得請求的驗證統一併且很方便。
Controller類:
package com.dudu.controller; /** 教程頁面 * Created by tengj on 2017/3/13. */ @Controller @RequestMapping("/learn") public class LearnController extends AbstractController{ @Autowired private LearnService learnService; private Logger logger = LoggerFactory.getLogger(this.getClass()); @RequestMapping("") public String learn(Model model){ model.addAttribute("ctx", getContextPath()+"/"); return "learn-resource"; } /** * 查詢教程列表 * @param page * @return */ @RequestMapping(value = "/queryLeanList",method = RequestMethod.POST) @ResponseBody public AjaxObject queryLearnList(Page<LeanQueryLeanListReq> page){ List<LearnResource> learnList=learnService.queryLearnResouceList(page); PageInfo<LearnResource> pageInfo =new PageInfo<LearnResource>(learnList); return AjaxObject.ok().put("page", pageInfo); } /** * 新添教程 * @param learn */ @RequestMapping(value = "/add",method = RequestMethod.POST) @ResponseBody public AjaxObject addLearn(@RequestBody LearnResource learn){ learnService.save(learn); return AjaxObject.ok(); } /** * 修改教程 * @param learn */ @RequestMapping(value = "/update",method = RequestMethod.POST) @ResponseBody public AjaxObject updateLearn(@RequestBody LearnResource learn){ learnService.updateNotNull(learn); return AjaxObject.ok(); } /** * 刪除教程 * @param ids */ @RequestMapping(value="/delete",method = RequestMethod.POST) @ResponseBody public AjaxObject deleteLearn(@RequestBody Long[] ids){ learnService.deleteBatch(ids); return AjaxObject.ok(); } /** * 獲取教程 * @param id */ @RequestMapping(value="/resource/{id}",method = RequestMethod.GET) @ResponseBody public LearnResource qryLearn(@PathVariable(value = "id") Long id){ LearnResource lean= learnService.selectByKey(id); return lean; } }
這裏咱們也自動建立一個Controller的測試類,具體代碼以下:
package com.dudu.controller; import com.dudu.domain.User; 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.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpSession; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; @RunWith(SpringRunner.class) @SpringBootTest public class LearnControllerTest { @Autowired private WebApplicationContext wac; private MockMvc mvc; private MockHttpSession session; @Before public void setupMockMvc(){ mvc = MockMvcBuilders.webAppContextSetup(wac).build(); //初始化MockMvc對象 session = new MockHttpSession(); User user =new User("root","root"); session.setAttribute("user",user); //攔截器那邊會判斷用戶是否登陸,因此這裏注入一個用戶 } /** * 新增教程測試用例 * @throws Exception */ @Test public void addLearn() throws Exception{ String json="{\"author\":\"HAHAHAA\",\"title\":\"Spring\",\"url\":\"http://tengj.top/\"}"; mvc.perform(MockMvcRequestBuilders.post("/learn/add") .accept(MediaType.APPLICATION_JSON_UTF8) .content(json.getBytes()) //傳json參數 .session(session) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcResultHandlers.print()); } /** * 獲取教程測試用例 * @throws Exception */ @Test public void qryLearn() throws Exception { mvc.perform(MockMvcRequestBuilders.get("/learn/resource/1001") .contentType(MediaType.APPLICATION_JSON_UTF8) .accept(MediaType.APPLICATION_JSON_UTF8) .session(session) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.author").value("嘟嘟MD獨立博客")) .andExpect(MockMvcResultMatchers.jsonPath("$.title").value("Spring Boot乾貨系列")) .andDo(MockMvcResultHandlers.print()); } /** * 修改教程測試用例 * @throws Exception */ @Test public void updateLearn() throws Exception{ String json="{\"author\":\"測試修改\",\"id\":1031,\"title\":\"Spring Boot乾貨系列\",\"url\":\"http://tengj.top/\"}"; mvc.perform(MockMvcRequestBuilders.post("/learn/update") .accept(MediaType.APPLICATION_JSON_UTF8) .content(json.getBytes())//傳json參數 .session(session) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcResultHandlers.print()); } /** * 刪除教程測試用例 * @throws Exception */ @Test public void deleteLearn() throws Exception{ String json="[1031]"; mvc.perform(MockMvcRequestBuilders.post("/learn/delete") .accept(MediaType.APPLICATION_JSON_UTF8) .content(json.getBytes())//傳json參數 .session(session) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcResultHandlers.print()); } }
上面實現了基本的增刪改查的測試用例,使用MockMvc的時候須要先用MockMvcBuilders使用構建MockMvc對象,以下
@Before public void setupMockMvc(){ mvc = MockMvcBuilders.webAppContextSetup(wac).build(); //初始化MockMvc對象 session = new MockHttpSession(); User user =new User("root","root"); session.setAttribute("user",user); //攔截器那邊會判斷用戶是否登陸,因此這裏注入一個用戶 }
由於攔截器那邊會判斷是否登陸,因此這裏我注入了一個用戶,你也能夠直接修改攔截器取消驗證用戶登陸,先測試完再開啓。
這裏拿一個例子來介紹一下MockMvc簡單的方法
/** * 獲取教程測試用例 * @throws Exception */ @Test public void qryLearn() throws Exception { mvc.perform(MockMvcRequestBuilders.get("/learn/resource/1001") .contentType(MediaType.APPLICATION_JSON_UTF8) .accept(MediaType.APPLICATION_JSON_UTF8) .session(session) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.author").value("嘟嘟MD獨立博客")) .andExpect(MockMvcResultMatchers.jsonPath("$.title").value("Spring Boot乾貨系列")) .andDo(MockMvcResultHandlers.print()); }
application/json;charset=UTF-8
application/json;charset=UTF-8
嘟嘟MD獨立博客
,不是就測試不經過本例子測試以下:
JUnit 4.4 結合 Hamcrest 提供了一個全新的斷言語法——assertThat。程序員能夠只使用 assertThat 一個斷言語句,結合 Hamcrest 提供的匹配符,就能夠表達所有的測試思想,咱們引入的版本是Junit4.12因此支持assertThat。
清單 1 assertThat 基本語法
assertThat( \[value\], \[matcher statement\] );
清單 2 使用匹配符 Matcher 和不使用之間的比較
// 想判斷某個字符串 s 是否含有子字符串 "developer" 或 "Works" 中間的一個 // JUnit 4.4 之前的版本:assertTrue(s.indexOf("developer")>-1||s.indexOf("Works")>-1 ); // JUnit 4.4: assertThat(s, anyOf(containsString("developer"), containsString("Works"))); // 匹配符 anyOf 表示任何一個條件知足則成立,相似於邏輯或 "||", 匹配符 containsString 表示是否含有參數子 // 字符串,文章接下來會對匹配符進行具體介紹
優勢 3:assertThat 再也不像 assertEquals 那樣,使用比較難懂的「謂賓主」語法模式(如:assertEquals(3, x);),相反,assertThat 使用了相似於「主謂賓」的易讀語法模式(如:assertThat(x,is(3));),使得代碼更加直觀、易讀。
注:本篇博文爲轉載,原問地址:Spring Boot乾貨系列:(十二)Spring Boot使用單元測試