單元測試用於測試單個代碼組件,並確保代碼按預期方式工作。單元測試由開發人員編寫和執行。大多數情況下,會使用JUnit或TestNG這樣的測試框架。測試用例通常在方法級別編寫,並通過自動化執行。
Spring Boot提供了一些注解和工具去幫助開發者測試他們的應用。
在講springboot單元測試之前,先簡單介紹下軟件測試的類型(從開發角度來說),跟如何寫好一個單元測試。
軟件測試類型
- 單元測試:用於測試單個代碼組件,並確保代碼按預期方式工作。單元測試由開發人員編寫和執行。
- 集成測試: 檢查整個系統是否工作正常。集成測試也是由開發人員完成的,但它不是測試單個組件,而是旨在跨組件進行測試。系統由許多單獨的組件組成,如代碼、數據庫、Web服務器等。集成測試能夠發現組件的連接、網絡訪問、數據庫問題等問題。
- 功能測試: 通過將給定輸入的結果與規范進行比較來檢查每個特性是否正確實現。這個階段通常由公司專門的測試團隊來負責。
- 驗收測試:驗收測試是保證軟件的准備就緒,按照項目合同、任務書、雙方約定的驗收依據文檔,向軟件的購買者展示該軟件的原始的需求。
單元測試要點
- 測試的粒度是方法級的。
- 測試的用例的結果應該是穩定的。
- 測試的用例應該盡量少寫邏輯或者不寫測試邏輯。
- 測試用例應該有很高的覆蓋率,把基本的輸入輸出覆蓋,一些邊界也要覆蓋到。
- 使用斷言而不是輸出打印的語句。
- 單元測試用例應該有個好名字,例如test_MethodName()
SpringBoot集成單元測試
引入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
依賴關系
- JUnit — The de-facto standard for unit testing Java applications.
- Spring Test & Spring Boot Test — Utilities and integration test support for Spring Boot applications.
- AssertJ — A fluent assertion library.
- Hamcrest — A library of matcher objects (also known as constraints or predicates).
- Mockito — A Java mocking framework.
- JsonPath — XPath for JSON
常用注解說明
- @RunWith(SpringRunner.class)
JUnit運行使用Spring的測試支持。SpringRunner是SpringJUnit4ClassRunner的新名字,這樣做的目的僅僅是為了讓名字看起來更簡單一點。 - @SpringBootTest
用於Spring Boot應用測試,它默認會根據包名逐級往上找,一直找到Spring Boot主程序,通過類注解是否包含@SpringBootApplication來判斷是否主程序,並在測試的時候啟動該類來創建Spring上下文環境。 - @BeforeClass
針對所有測試,只執行一次,且必須為static void - @BeforeEach
初始化方法,執行當前測試類的每個測試方法前執行 - @Test
測試方法,在這里可以測試期望異常和超時時間 - @AfterEach
釋放資源,執行當前測試類的每個測試方法后執行 - @AfterClass
針對所有測試,只執行一次,且必須為static void - @Ignore
忽略的測試方法
斷言常見使用方法
- assertNotNull("message",A) //判斷A不為空
- assertFalse("message",A) //判斷條件A不為真
- assertTure("message",A) //判斷條件A為真
- assertEquals("message",A,B) // 判斷A.equals(B)
- assertSame("message",A,B) //判斷A==B
測試方法
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserRepositoryTest {
@Autowired
UserRepository userRepository;
@Test
@Ignore
public void testFindAll(){
Page<UserDO> userDOS= userRepository.findAll(PageRequest.of(1,10));
Assert.assertNotNull(userDOS.getContent());
}
@Test(expected = RuntimeException.class)
public void testNullPointerException(){
throw new RuntimeException();
}
}
測試API接口
- MockMvcRequestBuilders
構造請求的路徑,請求的參數等信息 - andExpect
添加斷言判斷結果是否達到預期 - andDo
添加結果處理器,比如示例中的打印 - andReturn
返回驗證成功后的MvcResult,用於自定義驗證/下一步的異步處理。
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
class UserControllerTest {
@Autowired
MockMvc mockMvc;
UserDO userDO;
MultiValueMap<String,String> params;
@BeforeEach
public void setUp()throws Exception{
userDO=new UserDO();
userDO.setPasswd("123456");
params=new LinkedMultiValueMap<>();
params.add("name","codehome");
}
//測試get接口
@Test
public void queryUser() throws Exception {
String result= mockMvc.perform(MockMvcRequestBuilders.get("/user/query")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.params(params)
).andExpect(MockMvcResultMatchers.status().is2xxSuccessful())
.andDo(MockMvcResultHandlers.print())
.andReturn().getResponse()
.getContentAsString();
Assert.assertEquals("調用成功","codehome",result);
}
//測試post接口
@Test
void addUser() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/user/add")
.contentType(MediaType.APPLICATION_JSON)
.content(JsonUtil.toJson(userDO))
.accept(MediaType.APPLICATION_JSON)
).andExpect(MockMvcResultMatchers.status().is2xxSuccessful())
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.jsonPath("$.data.passwd").value("123456"));
}
//測試cookie
@Test
void testCookie()throws Exception{
String token= mockMvc.perform(MockMvcRequestBuilders.get("/user/cookie")
.cookie(new Cookie("token","123456")))
.andDo(MockMvcResultHandlers.print())
.andReturn().getResponse()
.getContentAsString();
Assert.assertEquals("token從cookie中獲取成功","123456",token);
}
}
//測試的接口類
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/query")
public String queryUser(String name){
return name;
}
@PostMapping("/add")
public R addUser(@RequestBody UserDO userDO){
return R.ok(userDO);
}
@GetMapping("/cookie")
public String testCookie(@CookieValue("token") String token){
return token;
}
}
千里之行,始於足下。這里是SpringBoot教程系列第七篇,所有項目源碼均可以在我的GitHub上面下載源碼。**