Spring Boot 整合 JUnit 單元測試
技術標籤:spring bootjavaspring bootjunit
為自己的應用編寫單元測試是一個很好的習慣。在Java開發中最流行的測試工具非JUnit莫屬,它已經成為Java單元測試的事實標準。Spring Boot測試模組不僅整合JUnit框架,還提供了許多實用程式和註釋,方便我們測試應用。
1. 新增依賴
在 pom.xml 檔案中引入 spring-boot-starter-test
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId> spring-boot-starter-test</artifactId>
<version>${version}</version>
<scope>test</scope>
</dependency>
Spring Boot 2.2.x 開始整合的是JUnit 5。如果之前是使用的JUnit 4,可以使用JUnit 5中提供的老式引擎執行,需要新增 junit-vintage-engine 依賴。
Spring Boot 2.2.x釋出很久了,現在最新穩定版是2.4.x。舊的總要被替代,所以本篇只用JUnit 5,關於JUnit 4的文章相信網上很多,官方也有給出使用說明,請自行查詢。
2. 編寫單元測試
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class JUnitTest {
@Test
public void test() {
// 測試程式碼
}
}
@SpringBootTest 重要引數
-
args
應用程式引數,如:args = “–app.test=one” -
classes
Spring Boot應用啟動入口類名,該引數不指定時由Spring Boot預設查詢。 -
webEnvironment
預設情況下@SpringBootTest不會啟動伺服器。當測試Web應用時,需指定該引數以便載入上下文環境。
WebEnvironment列舉值說明:
MOCK
預設值,載入WebApplicationContext並提供模擬Web環境。使用此註釋時,不會啟動嵌入式伺服器。RANDOM_PORT
啟動應用並隨機監聽一個埠。DEFINED_PORT
啟動應用並監聽自定義的埠(來自application.properties)或使用預設埠8080。NONE
ApplicationContext通過使用載入,SpringApplication但不提供任何網路環境(模擬或其他方式)。
@Test
注意 JUnit 5 的 @Test 註解在 org.junit.jupiter.api 包下。
如果應用使用Spring MVC和 Spring WebFlux,則優先MVC。測試WebFlux應用必須設定:
@SpringBootTest(properties = "spring.main.web-application-type=reactive")
public class MyWebFluxTests {
}
3. 自動裝配測試
有時候我們只需要測試框架模組整合是否正常,不需要載入整個專案。可以使用 spring-boot-test-autoconfigure 模組中一些註解。整個框架被“切片”成獨立的測試模組。
JSON 測試
測試JSON序列化與反序列化。如果是GSON或JSONB,使用 @GsonTester 或 @JsonbTester 註解。
/**
* @author Engr-Z
* @since 2021/1/18
*/
@JsonTest
public class MyJsonTest {
@Autowired
private JacksonTester<Map> json;
@Test
void testSerialize() throws Exception {
Map<String, Object> map = new HashMap<>();
map.put("name", "攻城獅·正");
map.put("websit", "engr-z.com");
Assertions.assertThat(this.json.write(map)).isEqualToJson("expected.json");
Assertions.assertThat(this.json.write(map)).hasJsonPathStringValue("@.make");
Assertions.assertThat(this.json.write(map)).extractingJsonPathStringValue("@.make")
.isEqualTo("Honda");
}
@Test
void testDeserialize() throws Exception {
String content = "{\"name\":\"攻城獅·正\",\"website\":\"engr-z.com\"}";
Assertions.assertThat(this.json.parse(content));
Assertions.assertThat(this.json.parseObject(content).get("website")).isEqualTo("engr-z.com");
}
}
Spring MVC 測試
測試 /demo/hello 介面是否正常
/**
* @author Engr-Z
* @since 2021/1/18
*/
@WebMvcTest(DemoController.class)
public class SpringMVCTest {
@Autowired
private MockMvc mvc;
@Test
void test() throws Exception {
RequestBuilder builder = MockMvcRequestBuilders.get("/demo/hello");
ResultActions resultActions = mvc.perform(builder);
int status = resultActions.andReturn().getResponse().getStatus();
Assertions.assertEquals(200, status);
}
}
Spring WebFlux 測試
/**
* @author Engr-Z
* @since 2021/1/18
*/
@WebFluxTest(DemoController.class)
public class SpringWebFluxTest {
@Autowired
private WebTestClient webClient;
@Test
void test() throws Exception {
webClient.get().uri("/demo/webflux")
.accept(MediaType.TEXT_PLAIN)
.exchange()
.expectStatus().isOk();
}
}
JDBC 測試
@JdbcTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class JdbcTransactionalTests {
}
自動裝配還支援 JPA,Redis,Rest Client 等模組測試。更多請參考:Auto-configured Tests
@MockBean 和 @SpyBean
如果一個服務依賴於遠端呼叫的結果。為了不影響我們做單元測試,可以使用@MockBean
。以下是官方程式碼示例:
@SpringBootTest
class MyTests {
@MockBean
private RemoteService remoteService;
@Autowired
private Reverser reverser;
@Test
void exampleTest() {
// RemoteService has been injected into the reverser bean
BDDMockito.given(this.remoteService.someCall()).willReturn("mock");
String reverse = reverser.reverseSomeCall();
Assertions.assertThat(reverse).isEqualTo("kcom");
}
}
@SpyBean
和 @MockBean
不同之處是:對於未指定mock的方法,spy預設會呼叫真實的方法,有返回值的返回真實的返回值,而mock預設不執行,有返回值的,預設返回null
本篇只介紹 Spring Boot 整合 JUnit 單元測試,關於 JUnit 用法會在以後篇章詳細講解。
除非註明,否則均為攻城獅·正原創文章,轉載請註明出處。
本文連結:https://engr-z.com/88.html