測試 Spring Boot 應用
Spring Boot 應用是一個 Spring ApplicationContext
,因此除了通常對普通 Spring 上下文進行的操作之外,無需進行任何特殊處理即可對其進行測試。
外部屬性、日誌記錄和 Spring Boot 的其他特性預設只有在使用 SpringApplication 建立上下文時才會被安裝。 |
Spring Boot 提供了 @SpringBootTest
註解,當你需要 Spring Boot 特性時,它可以作為標準的 spring-test
@ContextConfiguration
註解的替代品。該註解透過 SpringApplication
建立測試中使用的 ApplicationContext
來工作。除了 @SpringBootTest
之外,還提供了許多其他註解用於測試應用中更具體的“切片”。
如果你使用的是 JUnit 4,不要忘記也在你的測試中新增 @RunWith(SpringRunner.class) 註解,否則這些註解將被忽略。如果你使用的是 JUnit 5,則無需新增等效的 @ExtendWith(SpringExtension.class) ,因為 @SpringBootTest 和其他 @…Test 註解已經使用它進行了註解。 |
預設情況下,@SpringBootTest
不會啟動伺服器。你可以使用 @SpringBootTest
的 webEnvironment
屬性來進一步細化測試的執行方式
-
MOCK
(預設值):載入一個 webApplicationContext
並提供一個模擬的 web 環境。使用此註解時不會啟動嵌入式伺服器。如果你的 classpath 中沒有可用的 web 環境,此模式會透明地回退到建立一個常規的非 webApplicationContext
。它可以與@AutoConfigureMockMvc
或@AutoConfigureWebTestClient
結合使用,用於對你的 web 應用進行基於模擬的測試。 -
RANDOM_PORT
:載入一個WebServerApplicationContext
並提供一個真實的 web 環境。嵌入式伺服器會啟動並監聽隨機埠。 -
DEFINED_PORT
:載入一個WebServerApplicationContext
並提供一個真實的 web 環境。嵌入式伺服器會啟動並監聽指定的埠(來自你的application.properties
)或預設埠8080
。 -
NONE
:使用SpringApplication
載入一個ApplicationContext
,但不提供*任何* web 環境(模擬的或其他)。
如果你的測試帶有 @Transactional 註解,預設情況下它會在每個測試方法結束時回滾事務。然而,由於在 RANDOM_PORT 或 DEFINED_PORT 模式下使用此配置會隱式提供一個真實的 Servlet 環境,HTTP 客戶端和伺服器會在不同的執行緒中執行,因此在不同的事務中執行。在這種情況下,在伺服器上啟動的任何事務都不會回滾。 |
如果你的應用為管理伺服器使用了不同的埠,則使用 webEnvironment = WebEnvironment.RANDOM_PORT 的 @SpringBootTest 也會在另一個隨機埠上啟動管理伺服器。 |
檢測 Web 應用型別
如果存在 Spring MVC,則會配置一個常規的基於 MVC 的應用上下文。如果你只有 Spring WebFlux,我們將檢測到這一點並配置一個基於 WebFlux 的應用上下文。
如果兩者都存在,Spring MVC 優先。在這種情況下,如果你想測試響應式 web 應用,你必須設定 spring.main.web-application-type
屬性
-
Java
-
Kotlin
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(properties = "spring.main.web-application-type=reactive")
class MyWebFluxTests {
// ...
}
import org.springframework.boot.test.context.SpringBootTest
@SpringBootTest(properties = ["spring.main.web-application-type=reactive"])
class MyWebFluxTests {
// ...
}
檢測測試配置
如果你熟悉 Spring Test Framework,你可能習慣於使用 @ContextConfiguration(classes=…)
來指定要載入哪個 Spring @Configuration
。或者,你可能經常在測試中使用巢狀的 @Configuration
類。
測試 Spring Boot 應用時,通常不需要這樣做。每當你沒有顯式定義主要配置時,Spring Boot 的 @*Test
註解會自動搜尋它。
搜尋演算法從包含測試的包向上查詢,直到找到帶有 @SpringBootApplication
或 @SpringBootConfiguration
註解的類。只要你以合理的方式構建了程式碼,通常就能找到你的主配置。
如果你使用測試註解來測試應用中更具體的“切片”,則應避免在主方法的應用類上新增特定於某個區域的配置設定。
|
如果你想自定義主配置,可以使用巢狀的 @TestConfiguration
類。與用於替代你的應用主配置的巢狀 @Configuration
類不同,巢狀的 @TestConfiguration
類是在你的應用主配置之外使用的。
Spring 的測試框架會在測試之間快取應用上下文。因此,只要你的測試共享相同的配置(無論如何發現),載入上下文這個潛在耗時的過程只發生一次。 |
使用測試配置的主方法
通常,@SpringBootTest
發現的測試配置將是你的主 @SpringBootApplication
。在大多數結構良好的應用中,這個配置類也將包含用於啟動應用的 main
方法。
例如,下面是一個典型 Spring Boot 應用中非常常見的程式碼模式
-
Java
-
Kotlin
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.docs.using.structuringyourcode.locatingthemainclass.MyApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
在上面的例子中,main
方法除了委託給 SpringApplication.run(Class, String…)
外不做任何事情。但是,也可以有一個更復雜的 main
方法,在呼叫 SpringApplication.run(Class, String…)
之前應用自定義配置。
例如,這是一個改變 banner 模式並設定額外 profiles 的應用
-
Java
-
Kotlin
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.setAdditionalProfiles("myprofile");
application.run(args);
}
}
import org.springframework.boot.Banner
import org.springframework.boot.runApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args) {
setBannerMode(Banner.Mode.OFF)
setAdditionalProfiles("myprofile")
}
}
由於 main
方法中的自定義配置會影響最終的 ApplicationContext
,你可能也想使用 main
方法來建立測試中使用的 ApplicationContext
。預設情況下,@SpringBootTest
不會呼叫你的 main
方法,而是直接使用類本身來建立 ApplicationContext
如果你想改變這種行為,可以將 @SpringBootTest
的 useMainMethod
屬性更改為 SpringBootTest.UseMainMethod.ALWAYS
或 SpringBootTest.UseMainMethod.WHEN_AVAILABLE
。當設定為 ALWAYS
時,如果找不到 main
方法,測試將失敗。當設定為 WHEN_AVAILABLE
時,如果 main
方法可用,則會使用它,否則將使用標準的載入機制。
例如,以下測試將呼叫 MyApplication
的 main
方法來建立 ApplicationContext
。如果 main
方法設定了額外的 profiles,那麼當 ApplicationContext
啟動時,這些 profiles 將會啟用。
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.UseMainMethod;
@SpringBootTest(useMainMethod = UseMainMethod.ALWAYS)
class MyApplicationTests {
@Test
void exampleTest() {
// ...
}
}
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.UseMainMethod
@SpringBootTest(useMainMethod = UseMainMethod.ALWAYS)
class MyApplicationTests {
@Test
fun exampleTest() {
// ...
}
}
排除測試配置
如果你的應用使用元件掃描(例如,如果你使用了 @SpringBootApplication
或 @ComponentScan
),你可能會發現你僅為特定測試建立的頂級配置類意外地在所有地方都被掃描到。
如我們前面所見,可以在測試的內部類上使用 @TestConfiguration
來自定義主配置。@TestConfiguration
也可以用於頂級類。這樣做表明該類不應被掃描到。然後你可以在需要的地方顯式匯入該類,如下例所示
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
@SpringBootTest
@Import(MyTestsConfiguration.class)
class MyTests {
@Test
void exampleTest() {
// ...
}
}
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.context.annotation.Import
@SpringBootTest
@Import(MyTestsConfiguration::class)
class MyTests {
@Test
fun exampleTest() {
// ...
}
}
如果你直接使用 @ComponentScan (即不透過 @SpringBootApplication ),你需要將 TypeExcludeFilter 註冊到其中。詳情請參見 TypeExcludeFilter API 文件。 |
匯入的 @TestConfiguration 比內部類 @TestConfiguration 處理得更早,並且匯入的 @TestConfiguration 會在透過元件掃描找到的任何配置之前處理。一般來說,這種順序差異沒有明顯的影響,但如果你依賴於 bean 覆蓋,則需要注意這一點。 |
使用應用引數
如果你的應用需要引數,你可以讓 @SpringBootTest
使用 args
屬性注入它們。
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(args = "--app.test=one")
class MyApplicationArgumentTests {
@Test
void applicationArgumentsPopulated(@Autowired ApplicationArguments args) {
assertThat(args.getOptionNames()).containsOnly("app.test");
assertThat(args.getOptionValues("app.test")).containsOnly("one");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.ApplicationArguments
import org.springframework.boot.test.context.SpringBootTest
@SpringBootTest(args = ["--app.test=one"])
class MyApplicationArgumentTests {
@Test
fun applicationArgumentsPopulated(@Autowired args: ApplicationArguments) {
assertThat(args.optionNames).containsOnly("app.test")
assertThat(args.getOptionValues("app.test")).containsOnly("one")
}
}
在模擬環境中測試
預設情況下,@SpringBootTest
不會啟動伺服器,而是設定一個模擬環境來測試 web 端點。
使用 Spring MVC,我們可以使用 MockMvc
查詢我們的 web 端點。有三種整合方式可用
-
使用 Hamcrest 的常規
MockMvc
。 -
包裝了
MockMvc
並使用 AssertJ 的MockMvcTester
。 -
其中
MockMvc
作為伺服器插入以處理請求的WebTestClient
。
以下示例展示了可用的整合方式
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
class MyMockMvcTests {
@Test
void testWithMockMvc(@Autowired MockMvc mvc) throws Exception {
mvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("Hello World"));
}
// If AssertJ is on the classpath, you can use MockMvcTester
@Test
void testWithMockMvcTester(@Autowired MockMvcTester mvc) {
assertThat(mvc.get().uri("/")).hasStatusOk().hasBodyTextEqualTo("Hello World");
}
// If Spring WebFlux is on the classpath, you can drive MVC tests with a WebTestClient
@Test
void testWithWebTestClient(@Autowired WebTestClient webClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello World");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBody
import org.springframework.test.web.servlet.assertj.MockMvcTester
@SpringBootTest
@AutoConfigureMockMvc
class MyMockMvcTests {
@Test
fun testWithMockMvc(@Autowired mvc: MockMvcTester) {
assertThat(mvc.get().uri("/")).hasStatusOk()
.hasBodyTextEqualTo("Hello World")
}
// If Spring WebFlux is on the classpath, you can drive MVC tests with a WebTestClient
@Test
fun testWithWebTestClient(@Autowired webClient: WebTestClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk
.expectBody<String>().isEqualTo("Hello World")
}
}
如果你想只關注 web 層而不啟動完整的 ApplicationContext ,可以考慮使用 @WebMvcTest 。 |
使用 Spring WebFlux 端點,你可以使用 WebTestClient
,如下例所示
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.reactive.server.WebTestClient;
@SpringBootTest
@AutoConfigureWebTestClient
class MyMockWebTestClientTests {
@Test
void exampleTest(@Autowired WebTestClient webClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello World");
}
}
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBody
@SpringBootTest
@AutoConfigureWebTestClient
class MyMockWebTestClientTests {
@Test
fun exampleTest(@Autowired webClient: WebTestClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk
.expectBody<String>().isEqualTo("Hello World")
}
}
在執行的伺服器中測試
如果你需要啟動一個完全執行的伺服器,我們建議你使用隨機埠。如果你使用 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
,每次測試執行時都會隨機選擇一個可用埠。
可以使用 @LocalServerPort
註解將實際使用的埠注入到你的測試中。為了方便起見,需要向已啟動伺服器進行 REST 呼叫的測試還可以自動注入一個 WebTestClient
,它可以將相對連結解析到正在執行的伺服器,並提供一個專門用於驗證響應的 API,如下例所示
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.web.reactive.server.WebTestClient;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyRandomPortWebTestClientTests {
@Test
void exampleTest(@Autowired WebTestClient webClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello World");
}
}
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBody
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyRandomPortWebTestClientTests {
@Test
fun exampleTest(@Autowired webClient: WebTestClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk
.expectBody<String>().isEqualTo("Hello World")
}
}
WebTestClient 也可以與模擬環境一起使用,透過使用 @AutoConfigureWebTestClient 註解測試類來消除對執行伺服器的需求。 |
此設定需要在 classpath 中包含 spring-webflux
。如果你不能或不想新增 webflux,Spring Boot 還提供了 TestRestTemplate
工具
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyRandomPortTestRestTemplateTests {
@Test
void exampleTest(@Autowired TestRestTemplate restTemplate) {
String body = restTemplate.getForObject("/", String.class);
assertThat(body).isEqualTo("Hello World");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
import org.springframework.boot.test.web.client.TestRestTemplate
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyRandomPortTestRestTemplateTests {
@Test
fun exampleTest(@Autowired restTemplate: TestRestTemplate) {
val body = restTemplate.getForObject("/", String::class.java)
assertThat(body).isEqualTo("Hello World")
}
}
自定義 WebTestClient
要自定義 WebTestClient
bean,請配置一個 WebTestClientBuilderCustomizer
bean。任何此類 bean 都會在建立 WebTestClient
時,使用用於構建 WebTestClient
的 WebTestClient.Builder
被呼叫。
使用 JMX
由於測試上下文框架會快取上下文,JMX 預設是停用的,以防止相同的元件註冊到同一個域。如果此類測試需要訪問 MBeanServer
,請考慮將其標記為 dirty。
-
Java
-
Kotlin
import javax.management.MBeanServer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(properties = "spring.jmx.enabled=true")
@DirtiesContext
class MyJmxTests {
@Autowired
private MBeanServer mBeanServer;
@Test
void exampleTest() {
assertThat(this.mBeanServer.getDomains()).contains("java.lang");
// ...
}
}
import javax.management.MBeanServer
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.annotation.DirtiesContext
@SpringBootTest(properties = ["spring.jmx.enabled=true"])
@DirtiesContext
class MyJmxTests(@Autowired val mBeanServer: MBeanServer) {
@Test
fun exampleTest() {
assertThat(mBeanServer.domains).contains("java.lang")
// ...
}
}
使用 Observations
如果你使用 @AutoConfigureObservability
註解 切片測試,它會自動配置一個 ObservationRegistry
。
使用 Metrics
無論你的 classpath 如何,除了記憶體支援的 meter registries 外,在使用 @SpringBootTest
時都不會自動配置。
如果你需要將 metrics 匯出到其他後端作為整合測試的一部分,請使用 @AutoConfigureObservability
註解進行標註。
如果你使用 @AutoConfigureObservability
註解 切片測試,它會自動配置一個記憶體型的 MeterRegistry
。使用 @AutoConfigureObservability
註解時,不支援在切片測試中匯出資料。
使用 Tracing
無論你的 classpath 如何,在使用 @SpringBootTest
時,用於報告資料的 tracing 元件都不會自動配置。
如果你需要將這些元件作為整合測試的一部分,請使用 @AutoConfigureObservability
註解測試。
如果你建立了自己的報告元件(例如自定義的 SpanExporter
或 brave.handler.SpanHandler
),並且不希望它們在測試中啟用,你可以使用 @ConditionalOnEnabledTracing
註解來停用它們。
如果你使用 @AutoConfigureObservability
註解 切片測試,它會自動配置一個 no-op Tracer
。使用 @AutoConfigureObservability
註解時,不支援在切片測試中匯出資料。
Mocking 和 Spying Beans
執行測試時,有時需要模擬應用程式上下文中的某些元件。例如,你可能有一個遠端服務的門面 (facade),該服務在開發期間不可用。模擬 (Mocking) 也可以在你想要模擬在真實環境中難以觸發的故障時非常有用。
Spring Framework 包含 @MockitoBean
註解,可用於在你的 ApplicationContext
中為 bean 定義一個 Mockito mock。此外,@MockitoSpyBean
可用於定義一個 Mockito spy。在Spring Framework 文件中瞭解有關這些功能的更多資訊。
自動配置測試
Spring Boot 的自動配置系統對於應用程式來說很好,但有時對於測試來說可能有點過多。通常只加載測試應用程式“切片”所需的配置部分會很有幫助。例如,你可能想要測試 Spring MVC 控制器是否正確對映 URL,並且不希望在這些測試中涉及資料庫呼叫;或者你可能想要測試 JPA 實體,並且在這些測試執行時對 Web 層不感興趣。
spring-boot-test-autoconfigure
模組包含許多可用於自動配置此類“切片”的註解。它們都以類似的方式工作,提供一個載入 ApplicationContext
的 @…Test
註解,以及一個或多個可用於自定義自動配置設定的 @AutoConfigure…
註解。
每個切片都會限制元件掃描到適當的元件,並載入一組非常有限的自動配置類。如果你需要排除其中一個,大多數 @…Test 註解都提供一個 excludeAutoConfiguration 屬性。或者,你可以使用 @ImportAutoConfiguration#exclude 。 |
不支援在同一個測試中使用多個 @…Test 註解來包含多個“切片”。如果你需要多個“切片”,請選擇一個 @…Test 註解,然後手動包含其他“切片”的 @AutoConfigure… 註解。 |
也可以將 @AutoConfigure… 註解與標準的 @SpringBootTest 註解一起使用。如果你對應用程式的“切片”不感興趣,但需要一些自動配置的測試 bean,可以使用這種組合。 |
自動配置的 JSON 測試
-
Jackson
ObjectMapper
、任何@JsonComponent
bean 以及任何 JacksonModule
-
Gson
-
Jsonb
如果你需要配置自動配置的元素,可以使用 @AutoConfigureJsonTesters
註解。
Spring Boot 包含基於 AssertJ 的 helper 類,它們與 JSONAssert 和 JsonPath 庫配合使用,以檢查 JSON 是否按預期出現。JacksonTester
、GsonTester
、JsonbTester
和 BasicJsonTester
類可分別用於 Jackson、Gson、Jsonb 和字串。在使用 @JsonTest
時,測試類中的任何 helper 欄位都可以被 @Autowired
注入。下面的示例顯示了用於 Jackson 的測試類
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.json.JsonTest;
import org.springframework.boot.test.json.JacksonTester;
import static org.assertj.core.api.Assertions.assertThat;
@JsonTest
class MyJsonTests {
@Autowired
private JacksonTester<VehicleDetails> json;
@Test
void serialize() throws Exception {
VehicleDetails details = new VehicleDetails("Honda", "Civic");
// Assert against a `.json` file in the same package as the test
assertThat(this.json.write(details)).isEqualToJson("expected.json");
// Or use JSON path based assertions
assertThat(this.json.write(details)).hasJsonPathStringValue("@.make");
assertThat(this.json.write(details)).extractingJsonPathStringValue("@.make").isEqualTo("Honda");
}
@Test
void deserialize() throws Exception {
String content = "{\"make\":\"Ford\",\"model\":\"Focus\"}";
assertThat(this.json.parse(content)).isEqualTo(new VehicleDetails("Ford", "Focus"));
assertThat(this.json.parseObject(content).getMake()).isEqualTo("Ford");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.json.JsonTest
import org.springframework.boot.test.json.JacksonTester
@JsonTest
class MyJsonTests(@Autowired val json: JacksonTester<VehicleDetails>) {
@Test
fun serialize() {
val details = VehicleDetails("Honda", "Civic")
// Assert against a `.json` file in the same package as the test
assertThat(json.write(details)).isEqualToJson("expected.json")
// Or use JSON path based assertions
assertThat(json.write(details)).hasJsonPathStringValue("@.make")
assertThat(json.write(details)).extractingJsonPathStringValue("@.make").isEqualTo("Honda")
}
@Test
fun deserialize() {
val content = "{\"make\":\"Ford\",\"model\":\"Focus\"}"
assertThat(json.parse(content)).isEqualTo(VehicleDetails("Ford", "Focus"))
assertThat(json.parseObject(content).make).isEqualTo("Ford")
}
}
JSON helper 類也可以直接用於標準單元測試。為此,如果你不使用 @JsonTest ,請在你的 @BeforeEach 方法中呼叫 helper 的 initFields 方法。 |
如果你使用 Spring Boot 基於 AssertJ 的 helper 類來對給定 JSON 路徑下的數值進行斷言,根據型別不同,你可能無法使用 isEqualTo
。相反,你可以使用 AssertJ 的 satisfies
來斷言該值符合給定條件。例如,下面的示例斷言實際數值是一個接近 0.15
且偏移量在 0.01
之內的浮點值。
-
Java
-
Kotlin
@Test
void someTest() throws Exception {
SomeObject value = new SomeObject(0.152f);
assertThat(this.json.write(value)).extractingJsonPathNumberValue("@.test.numberValue")
.satisfies((number) -> assertThat(number.floatValue()).isCloseTo(0.15f, within(0.01f)));
}
@Test
fun someTest() {
val value = SomeObject(0.152f)
assertThat(json.write(value)).extractingJsonPathNumberValue("@.test.numberValue")
.satisfies(ThrowingConsumer { number ->
assertThat(number.toFloat()).isCloseTo(0.15f, within(0.01f))
})
}
自動配置的 Spring MVC 測試
要測試 Spring MVC 控制器是否按預期工作,使用 @WebMvcTest
註解。@WebMvcTest
會自動配置 Spring MVC 基礎設施,並將掃描的 bean 限制為 @Controller
、@ControllerAdvice
、@JsonComponent
、Converter
、GenericConverter
、Filter
、HandlerInterceptor
、WebMvcConfigurer
、WebMvcRegistrations
和 HandlerMethodArgumentResolver
。使用 @WebMvcTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。
@WebMvcTest 啟用的自動配置設定列表可以在附錄中找到。 |
通常,@WebMvcTest
僅限於單個控制器,並與 @MockitoBean
結合使用,為所需的協作物件提供 mock 實現。
@WebMvcTest
也會自動配置 MockMvc
。Mock MVC 提供了一種強大的方法,無需啟動完整的 HTTP 伺服器即可快速測試 MVC 控制器。如果 AssertJ 可用,MockMvcTester
提供的 AssertJ 支援也會自動配置。
你也可以透過使用 @AutoConfigureMockMvc 註解,在非 @WebMvcTest 測試(例如 @SpringBootTest )中自動配置 MockMvc 和 MockMvcTester 。下面的示例使用了 MockMvcTester |
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
@WebMvcTest(UserVehicleController.class)
class MyControllerTests {
@Autowired
private MockMvcTester mvc;
@MockitoBean
private UserVehicleService userVehicleService;
@Test
void testExample() {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda", "Civic"));
assertThat(this.mvc.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
.hasStatusOk()
.hasBodyTextEqualTo("Honda Civic");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.mockito.BDDMockito.given
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.http.MediaType
import org.springframework.test.context.bean.override.mockito.MockitoBean
import org.springframework.test.web.servlet.assertj.MockMvcTester
@WebMvcTest(UserVehicleController::class)
class MyControllerTests(@Autowired val mvc: MockMvcTester) {
@MockitoBean
lateinit var userVehicleService: UserVehicleService
@Test
fun testExample() {
given(userVehicleService.getVehicleDetails("sboot"))
.willReturn(VehicleDetails("Honda", "Civic"))
assertThat(mvc.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
.hasStatusOk().hasBodyTextEqualTo("Honda Civic")
}
}
如果你需要配置自動配置的元素(例如,何時應用 servlet filter),可以使用 @AutoConfigureMockMvc 註解中的屬性。 |
如果你使用 HtmlUnit 和 Selenium,自動配置也會提供一個 HtmlUnit WebClient
bean 和/或一個 Selenium WebDriver
bean。下面的示例使用了 HtmlUnit
-
Java
-
Kotlin
import org.htmlunit.WebClient;
import org.htmlunit.html.HtmlPage;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
@WebMvcTest(UserVehicleController.class)
class MyHtmlUnitTests {
@Autowired
private WebClient webClient;
@MockitoBean
private UserVehicleService userVehicleService;
@Test
void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot")).willReturn(new VehicleDetails("Honda", "Civic"));
HtmlPage page = this.webClient.getPage("/sboot/vehicle.html");
assertThat(page.getBody().getTextContent()).isEqualTo("Honda Civic");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.htmlunit.WebClient
import org.htmlunit.html.HtmlPage
import org.junit.jupiter.api.Test
import org.mockito.BDDMockito.given
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.test.context.bean.override.mockito.MockitoBean
@WebMvcTest(UserVehicleController::class)
class MyHtmlUnitTests(@Autowired val webClient: WebClient) {
@MockitoBean
lateinit var userVehicleService: UserVehicleService
@Test
fun testExample() {
given(userVehicleService.getVehicleDetails("sboot")).willReturn(VehicleDetails("Honda", "Civic"))
val page = webClient.getPage<HtmlPage>("/sboot/vehicle.html")
assertThat(page.body.textContent).isEqualTo("Honda Civic")
}
}
預設情況下,Spring Boot 將 WebDriver bean 放入一個特殊的“scope”中,以確保 driver 在每個測試後退出並注入新的例項。如果你不想要此行為,可以將 @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) 新增到你的 WebDriver @Bean 定義中。 |
Spring Boot 建立的 webDriver scope 將替換任何使用者定義的同名 scope。如果你定義了自己的 webDriver scope,你可能會發現當使用 @WebMvcTest 時它會停止工作。 |
如果你的 classpath 中有 Spring Security,@WebMvcTest
也會掃描 WebSecurityConfigurer
bean。你可以使用 Spring Security 的測試支援,而不是為此類測試完全停用安全性。有關如何使用 Spring Security 的 MockMvc
支援的更多詳細資訊,可以在此使用 Spring Security 進行測試 “How-to Guides” 部分中找到。
有時編寫 Spring MVC 測試還不夠;Spring Boot 可以幫助你執行使用實際伺服器進行完整的端到端測試。 |
自動配置的 Spring WebFlux 測試
要測試 Spring WebFlux 控制器是否按預期工作,你可以使用 @WebFluxTest
註解。@WebFluxTest
會自動配置 Spring WebFlux 基礎設施,並將掃描的 bean 限制為 @Controller
、@ControllerAdvice
、@JsonComponent
、Converter
、GenericConverter
和 WebFluxConfigurer
。使用 @WebFluxTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。
@WebFluxTest 啟用的自動配置列表可以在附錄中找到。 |
通常,@WebFluxTest
僅限於單個控制器,並與 @MockitoBean
註解結合使用,為所需的協作物件提供 mock 實現。
@WebFluxTest
也會自動配置 WebTestClient
,它提供了一種強大的方法,無需啟動完整的 HTTP 伺服器即可快速測試 WebFlux 控制器。
你也可以透過使用 @AutoConfigureWebTestClient 註解,在非 @WebFluxTest 測試(例如 @SpringBootTest )中自動配置 WebTestClient 。下面的示例顯示了一個同時使用了 @WebFluxTest 和 WebTestClient 的類 |
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.mockito.BDDMockito.given;
@WebFluxTest(UserVehicleController.class)
class MyControllerTests {
@Autowired
private WebTestClient webClient;
@MockitoBean
private UserVehicleService userVehicleService;
@Test
void testExample() {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda", "Civic"));
this.webClient.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN).exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Honda Civic");
}
}
import org.junit.jupiter.api.Test
import org.mockito.BDDMockito.given
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest
import org.springframework.http.MediaType
import org.springframework.test.context.bean.override.mockito.MockitoBean
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBody
@WebFluxTest(UserVehicleController::class)
class MyControllerTests(@Autowired val webClient: WebTestClient) {
@MockitoBean
lateinit var userVehicleService: UserVehicleService
@Test
fun testExample() {
given(userVehicleService.getVehicleDetails("sboot"))
.willReturn(VehicleDetails("Honda", "Civic"))
webClient.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN).exchange()
.expectStatus().isOk
.expectBody<String>().isEqualTo("Honda Civic")
}
}
此設定僅受 WebFlux 應用程式支援,因為目前在模擬的 Web 應用程式中使用 WebTestClient 只適用於 WebFlux。 |
@WebFluxTest 無法檢測透過函式式 Web 框架註冊的路由。要測試上下文中的 RouterFunction bean,請考慮透過使用 @Import 或使用 @SpringBootTest 來匯入你自己的 RouterFunction 。 |
@WebFluxTest 無法檢測註冊為型別為 SecurityWebFilterChain 的 @Bean 的自定義安全配置。要將其包含在測試中,你需要透過使用 @Import 或使用 @SpringBootTest 匯入註冊該 bean 的配置。 |
有時編寫 Spring WebFlux 測試還不夠;Spring Boot 可以幫助你執行使用實際伺服器進行完整的端到端測試。 |
自動配置的 Spring GraphQL 測試
Spring GraphQL 提供了一個專用的測試支援模組;你需要將其新增到你的專案中
<dependencies>
<dependency>
<groupId>org.springframework.graphql</groupId>
<artifactId>spring-graphql-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Unless already present in the compile scope -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
dependencies {
testImplementation("org.springframework.graphql:spring-graphql-test")
// Unless already present in the implementation configuration
testImplementation("org.springframework.boot:spring-boot-starter-webflux")
}
這個測試模組提供了 GraphQlTester。這個 tester 在測試中被大量使用,所以請務必熟悉它的用法。有不同變種的 GraphQlTester
,Spring Boot 會根據測試型別自動配置它們
-
ExecutionGraphQlServiceTester
在服務端執行測試,不涉及客戶端或傳輸層 -
HttpGraphQlTester
使用連線到伺服器的客戶端執行測試,無論伺服器是否正在執行。
Spring Boot 透過 @GraphQlTest
註解幫助你測試你的 Spring GraphQL Controller。@GraphQlTest
會自動配置 Spring GraphQL 基礎設施,不涉及任何傳輸或伺服器。這將掃描的 bean 限制為 @Controller
、RuntimeWiringConfigurer
、JsonComponent
、Converter
、GenericConverter
、DataFetcherExceptionResolver
、Instrumentation
和 GraphQlSourceBuilderCustomizer
。使用 @GraphQlTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。
@GraphQlTest 啟用的自動配置列表可以在附錄中找到。 |
通常,@GraphQlTest
僅限於一組控制器,並與 @MockitoBean
註解結合使用,為所需的協作物件提供 mock 實現。
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.docs.web.graphql.runtimewiring.GreetingController;
import org.springframework.boot.test.autoconfigure.graphql.GraphQlTest;
import org.springframework.graphql.test.tester.GraphQlTester;
@GraphQlTest(GreetingController.class)
class GreetingControllerTests {
@Autowired
private GraphQlTester graphQlTester;
@Test
void shouldGreetWithSpecificName() {
this.graphQlTester.document("{ greeting(name: \"Alice\") } ")
.execute()
.path("greeting")
.entity(String.class)
.isEqualTo("Hello, Alice!");
}
@Test
void shouldGreetWithDefaultName() {
this.graphQlTester.document("{ greeting } ")
.execute()
.path("greeting")
.entity(String.class)
.isEqualTo("Hello, Spring!");
}
}
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.docs.web.graphql.runtimewiring.GreetingController
import org.springframework.boot.test.autoconfigure.graphql.GraphQlTest
import org.springframework.graphql.test.tester.GraphQlTester
@GraphQlTest(GreetingController::class)
internal class GreetingControllerTests {
@Autowired
lateinit var graphQlTester: GraphQlTester
@Test
fun shouldGreetWithSpecificName() {
graphQlTester.document("{ greeting(name: \"Alice\") } ").execute().path("greeting").entity(String::class.java)
.isEqualTo("Hello, Alice!")
}
@Test
fun shouldGreetWithDefaultName() {
graphQlTester.document("{ greeting } ").execute().path("greeting").entity(String::class.java)
.isEqualTo("Hello, Spring!")
}
}
@SpringBootTest
測試是完整的整合測試,涉及整個應用程式。使用隨機埠或指定埠時,會配置 live server,並自動貢獻一個 HttpGraphQlTester
bean,這樣你就可以用它來測試你的伺服器。配置 MOCK 環境時,你也可以透過使用 @AutoConfigureHttpGraphQlTester
註解測試類來請求一個 HttpGraphQlTester
bean
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.graphql.tester.AutoConfigureHttpGraphQlTester;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.graphql.test.tester.HttpGraphQlTester;
@AutoConfigureHttpGraphQlTester
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
class GraphQlIntegrationTests {
@Test
void shouldGreetWithSpecificName(@Autowired HttpGraphQlTester graphQlTester) {
HttpGraphQlTester authenticatedTester = graphQlTester.mutate()
.webTestClient((client) -> client.defaultHeaders((headers) -> headers.setBasicAuth("admin", "ilovespring")))
.build();
authenticatedTester.document("{ greeting(name: \"Alice\") } ")
.execute()
.path("greeting")
.entity(String.class)
.isEqualTo("Hello, Alice!");
}
}
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.graphql.tester.AutoConfigureHttpGraphQlTester
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.graphql.test.tester.HttpGraphQlTester
import org.springframework.http.HttpHeaders
import org.springframework.test.web.reactive.server.WebTestClient
@AutoConfigureHttpGraphQlTester
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
class GraphQlIntegrationTests {
@Test
fun shouldGreetWithSpecificName(@Autowired graphQlTester: HttpGraphQlTester) {
val authenticatedTester = graphQlTester.mutate()
.webTestClient { client: WebTestClient.Builder ->
client.defaultHeaders { headers: HttpHeaders ->
headers.setBasicAuth("admin", "ilovespring")
}
}.build()
authenticatedTester.document("{ greeting(name: \"Alice\") } ").execute()
.path("greeting").entity(String::class.java).isEqualTo("Hello, Alice!")
}
}
自動配置的 Data Cassandra 測試
你可以使用 @DataCassandraTest
來測試 Cassandra 應用程式。預設情況下,它配置一個 CassandraTemplate
,掃描 @Table
類,並配置 Spring Data Cassandra repositories。使用 @DataCassandraTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。(有關在 Spring Boot 中使用 Cassandra 的更多資訊,請參閱Cassandra。)
@DataCassandraTest 啟用的自動配置設定列表可以在附錄中找到。 |
下面的示例顯示了在 Spring Boot 中使用 Cassandra 測試的典型設定
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest;
@DataCassandraTest
class MyDataCassandraTests {
@Autowired
private SomeRepository repository;
}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest
@DataCassandraTest
class MyDataCassandraTests(@Autowired val repository: SomeRepository)
自動配置的 Data Couchbase 測試
你可以使用 @DataCouchbaseTest
來測試 Couchbase 應用程式。預設情況下,它配置一個 CouchbaseTemplate
或一個 ReactiveCouchbaseTemplate
,掃描 @Document
類,並配置 Spring Data Couchbase repositories。使用 @DataCouchbaseTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。(有關在 Spring Boot 中使用 Couchbase 的更多資訊,請參閱Couchbase。)
@DataCouchbaseTest 啟用的自動配置設定列表可以在附錄中找到。 |
下面的示例顯示了在 Spring Boot 中使用 Couchbase 測試的典型設定
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.couchbase.DataCouchbaseTest;
@DataCouchbaseTest
class MyDataCouchbaseTests {
@Autowired
private SomeRepository repository;
// ...
}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.couchbase.DataCouchbaseTest
@DataCouchbaseTest
class MyDataCouchbaseTests(@Autowired val repository: SomeRepository) {
// ...
}
自動配置的 Data Elasticsearch 測試
你可以使用 @DataElasticsearchTest
來測試 Elasticsearch 應用程式。預設情況下,它配置一個 ElasticsearchTemplate
,掃描 @Document
類,並配置 Spring Data Elasticsearch repositories。使用 @DataElasticsearchTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。(有關在 Spring Boot 中使用 Elasticsearch 的更多資訊,請參閱Elasticsearch。)
@DataElasticsearchTest 啟用的自動配置設定列表可以在附錄中找到。 |
下面的示例顯示了在 Spring Boot 中使用 Elasticsearch 測試的典型設定
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.elasticsearch.DataElasticsearchTest;
@DataElasticsearchTest
class MyDataElasticsearchTests {
@Autowired
private SomeRepository repository;
// ...
}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.elasticsearch.DataElasticsearchTest
@DataElasticsearchTest
class MyDataElasticsearchTests(@Autowired val repository: SomeRepository) {
// ...
}
自動配置的 Data JPA 測試
你可以使用 @DataJpaTest
註解來測試 JPA 應用程式。預設情況下,它掃描 @Entity
類並配置 Spring Data JPA repositories。如果 classpath 中有嵌入式資料庫,它也會配置一個。透過將 spring.jpa.show-sql
屬性設定為 true
,SQL 查詢預設會被記錄。可以使用註解的 showSql
屬性停用此功能。
使用 @DataJpaTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。
@DataJpaTest 啟用的自動配置設定列表可以在附錄中找到。 |
預設情況下,Data JPA 測試是事務性的,並在每個測試結束時回滾。更多詳細資訊,請參閱 Spring Framework 參考文件中的相關章節。如果這不是你想要的,可以按如下方式為單個測試或整個類停用事務管理
-
Java
-
Kotlin
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyNonTransactionalTests {
// ...
}
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyNonTransactionalTests {
// ...
}
Data JPA 測試也可能注入一個 TestEntityManager
bean,它提供了標準 JPA EntityManager
的替代方案,專為測試設計。
TestEntityManager 也可以透過新增 @AutoConfigureTestEntityManager ,自動配置到你的任何基於 Spring 的測試類中。進行此操作時,請確保你的測試執行在事務中,例如透過在測試類或方法上新增 @Transactional 。 |
如果你需要 JdbcTemplate
,它也是可用的。下面的示例展示了正在使用的 @DataJpaTest
註解
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest
class MyRepositoryTests {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository repository;
@Test
void testExample() {
this.entityManager.persist(new User("sboot", "1234"));
User user = this.repository.findByUsername("sboot");
assertThat(user.getUsername()).isEqualTo("sboot");
assertThat(user.getEmployeeNumber()).isEqualTo("1234");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
@DataJpaTest
class MyRepositoryTests(@Autowired val entityManager: TestEntityManager, @Autowired val repository: UserRepository) {
@Test
fun testExample() {
entityManager.persist(User("sboot", "1234"))
val user = repository.findByUsername("sboot")
assertThat(user?.username).isEqualTo("sboot")
assertThat(user?.employeeNumber).isEqualTo("1234")
}
}
記憶體中的嵌入式資料庫通常很適合用於測試,因為它們速度快且不需要任何安裝。然而,如果您希望針對真實的資料庫執行測試,可以使用 @AutoConfigureTestDatabase
註解,如下例所示
-
Java
-
Kotlin
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
class MyRepositoryTests {
// ...
}
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class MyRepositoryTests {
// ...
}
自動配置的 JDBC 測試
@JdbcTest
類似於 @DataJpaTest
,但適用於僅需要 DataSource
而不使用 Spring Data JDBC 的測試。預設情況下,它配置一個記憶體嵌入式資料庫和一個 JdbcTemplate
。當使用 @JdbcTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。
預設情況下,JDBC 測試是事務性的,並在每個測試結束時回滾。更多詳情請參見 Spring Framework 參考文件中的相關部分。如果這不是您想要的行為,可以為某個測試或整個類停用事務管理,如下所示
-
Java
-
Kotlin
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@JdbcTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyTransactionalTests {
}
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
@JdbcTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyTransactionalTests
如果您希望測試針對真實的資料庫執行,可以使用 @AutoConfigureTestDatabase
註解,用法與 @DataJpaTest
相同。(參見自動配置的 Data JPA 測試。)
自動配置的 Data JDBC 測試
@DataJdbcTest
類似於 @JdbcTest
,但適用於使用 Spring Data JDBC 倉庫的測試。預設情況下,它配置一個記憶體嵌入式資料庫、一個 JdbcTemplate
和 Spring Data JDBC 倉庫。當使用 @DataJdbcTest
註解時,只會掃描 AbstractJdbcConfiguration
的子類,常規的 @Component
和 @ConfigurationProperties
bean 不會被掃描。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。
由 @DataJdbcTest 啟用的自動配置列表在附錄中可以找到。 |
預設情況下,Data JDBC 測試是事務性的,並在每個測試結束時回滾。更多詳情請參見 Spring Framework 參考文件中的相關部分。如果這不是您想要的行為,可以為某個測試或整個測試類停用事務管理,如JDBC 示例中所示。
如果您希望測試針對真實的資料庫執行,可以使用 @AutoConfigureTestDatabase
註解,用法與 @DataJpaTest
相同。(參見自動配置的 Data JPA 測試。)
自動配置的 Data R2DBC 測試
@DataR2dbcTest
類似於 @DataJdbcTest
,但適用於使用 Spring Data R2DBC 倉庫的測試。預設情況下,它配置一個記憶體嵌入式資料庫、一個 R2dbcEntityTemplate
和 Spring Data R2DBC 倉庫。當使用 @DataR2dbcTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。
由 @DataR2dbcTest 啟用的自動配置設定列表在附錄中可以找到。 |
預設情況下,Data R2DBC 測試不是事務性的。
如果您希望測試針對真實的資料庫執行,可以使用 @AutoConfigureTestDatabase
註解,用法與 @DataJpaTest
相同。(參見自動配置的 Data JPA 測試。)
自動配置的 jOOQ 測試
您可以像使用 @JdbcTest
一樣使用 @JooqTest
,但它用於 jOOQ 相關的測試。由於 jOOQ 嚴重依賴於與資料庫模式相對應的基於 Java 的模式,因此會使用現有的 DataSource
。如果您想用記憶體資料庫替換它,可以使用 @AutoConfigureTestDatabase
來覆蓋這些設定。(更多關於在 Spring Boot 中使用 jOOQ 的資訊,請參見使用 jOOQ。)當使用 @JooqTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。
@JooqTest
配置了一個 DSLContext
。以下示例展示了 @JooqTest
註解的使用方法
-
Java
-
Kotlin
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jooq.JooqTest;
@JooqTest
class MyJooqTests {
@Autowired
private DSLContext dslContext;
// ...
}
import org.jooq.DSLContext
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.jooq.JooqTest
@JooqTest
class MyJooqTests(@Autowired val dslContext: DSLContext) {
// ...
}
預設情況下,jOOQ 測試是事務性的,並在每個測試結束時回滾。如果這不是您想要的行為,可以為某個測試或整個測試類停用事務管理,如JDBC 示例中所示。
自動配置的 Data MongoDB 測試
您可以使用 @DataMongoTest
來測試 MongoDB 應用。預設情況下,它配置一個 MongoTemplate
,掃描 @Document
類,並配置 Spring Data MongoDB 倉庫。當使用 @DataMongoTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。(更多關於在 Spring Boot 中使用 MongoDB 的資訊,請參見MongoDB。)
由 @DataMongoTest 啟用的自動配置設定列表在附錄中可以找到。 |
以下類展示了 @DataMongoTest
註解的使用方法
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.data.mongodb.core.MongoTemplate;
@DataMongoTest
class MyDataMongoDbTests {
@Autowired
private MongoTemplate mongoTemplate;
// ...
}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest
import org.springframework.data.mongodb.core.MongoTemplate
@DataMongoTest
class MyDataMongoDbTests(@Autowired val mongoTemplate: MongoTemplate) {
// ...
}
自動配置的 Data Neo4j 測試
您可以使用 @DataNeo4jTest
來測試 Neo4j 應用。預設情況下,它掃描 @Node
類,並配置 Spring Data Neo4j 倉庫。當使用 @DataNeo4jTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。(更多關於在 Spring Boot 中使用 Neo4j 的資訊,請參見Neo4j。)
由 @DataNeo4jTest 啟用的自動配置設定列表在附錄中可以找到。 |
以下示例展示了在 Spring Boot 中使用 Neo4j 測試的典型設定
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
@DataNeo4jTest
class MyDataNeo4jTests {
@Autowired
private SomeRepository repository;
// ...
}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest
@DataNeo4jTest
class MyDataNeo4jTests(@Autowired val repository: SomeRepository) {
// ...
}
預設情況下,Data Neo4j 測試是事務性的,並在每個測試結束時回滾。更多詳情請參見 Spring Framework 參考文件中的相關部分。如果這不是您想要的行為,可以為某個測試或整個類停用事務管理,如下所示
-
Java
-
Kotlin
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@DataNeo4jTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyDataNeo4jTests {
}
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
@DataNeo4jTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyDataNeo4jTests
響應式訪問不支援事務性測試。如果您使用這種風格,則必須按照上述說明配置 @DataNeo4jTest 測試。 |
自動配置的 Data Redis 測試
您可以使用 @DataRedisTest
來測試 Redis 應用。預設情況下,它掃描 @RedisHash
類並配置 Spring Data Redis 倉庫。當使用 @DataRedisTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。(更多關於在 Spring Boot 中使用 Redis 的資訊,請參見Redis。)
由 @DataRedisTest 啟用的自動配置設定列表在附錄中可以找到。 |
以下示例展示了 @DataRedisTest
註解的使用方法
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest;
@DataRedisTest
class MyDataRedisTests {
@Autowired
private SomeRepository repository;
// ...
}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest
@DataRedisTest
class MyDataRedisTests(@Autowired val repository: SomeRepository) {
// ...
}
自動配置的 Data LDAP 測試
您可以使用 @DataLdapTest
來測試 LDAP 應用。預設情況下,它配置一個記憶體嵌入式 LDAP(如果可用)、配置一個 LdapTemplate
,掃描 @Entry
類,並配置 Spring Data LDAP 倉庫。當使用 @DataLdapTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。(更多關於在 Spring Boot 中使用 LDAP 的資訊,請參見LDAP。)
由 @DataLdapTest 啟用的自動配置設定列表在附錄中可以找到。 |
以下示例展示了 @DataLdapTest
註解的使用方法
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;
import org.springframework.ldap.core.LdapTemplate;
@DataLdapTest
class MyDataLdapTests {
@Autowired
private LdapTemplate ldapTemplate;
// ...
}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest
import org.springframework.ldap.core.LdapTemplate
@DataLdapTest
class MyDataLdapTests(@Autowired val ldapTemplate: LdapTemplate) {
// ...
}
記憶體嵌入式 LDAP 通常很適合用於測試,因為它速度快且不需要開發人員進行任何安裝。然而,如果您希望針對真實的 LDAP 伺服器執行測試,則應排除嵌入式 LDAP 的自動配置,如下例所示
-
Java
-
Kotlin
import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration;
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;
@DataLdapTest(excludeAutoConfiguration = EmbeddedLdapAutoConfiguration.class)
class MyDataLdapTests {
// ...
}
import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest
@DataLdapTest(excludeAutoConfiguration = [EmbeddedLdapAutoConfiguration::class])
class MyDataLdapTests {
// ...
}
自動配置的 REST 客戶端
您可以使用 @RestClientTest
註解來測試 REST 客戶端。預設情況下,它自動配置 Jackson、GSON 和 Jsonb 支援,配置一個 RestTemplateBuilder
和一個 RestClient.Builder
,並新增對 MockRestServiceServer
的支援。當使用 @RestClientTest
註解時,不會掃描常規的 @Component
和 @ConfigurationProperties
bean。@EnableConfigurationProperties
可用於包含 @ConfigurationProperties
bean。
由 @RestClientTest 啟用的自動配置設定列表在附錄中可以找到。 |
您要測試的特定 bean 應透過使用 @RestClientTest
的 value
或 components
屬性來指定。
當在被測試的 bean 中使用 RestTemplateBuilder
並且在構建 RestTemplate
時呼叫了 RestTemplateBuilder.rootUri(String rootUri)
,則根 URI 應從 MockRestServiceServer
期望中省略,如下例所示
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.client.MockRestServiceServer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
@RestClientTest(org.springframework.boot.docs.testing.springbootapplications.autoconfiguredrestclient.RemoteVehicleDetailsService.class)
class MyRestTemplateServiceTests {
@Autowired
private RemoteVehicleDetailsService service;
@Autowired
private MockRestServiceServer server;
@Test
void getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {
this.server.expect(requestTo("/greet/details")).andRespond(withSuccess("hello", MediaType.TEXT_PLAIN));
String greeting = this.service.callRestService();
assertThat(greeting).isEqualTo("hello");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest
import org.springframework.http.MediaType
import org.springframework.test.web.client.MockRestServiceServer
import org.springframework.test.web.client.match.MockRestRequestMatchers
import org.springframework.test.web.client.response.MockRestResponseCreators
@RestClientTest(RemoteVehicleDetailsService::class)
class MyRestTemplateServiceTests(
@Autowired val service: RemoteVehicleDetailsService,
@Autowired val server: MockRestServiceServer) {
@Test
fun getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {
server.expect(MockRestRequestMatchers.requestTo("/greet/details"))
.andRespond(MockRestResponseCreators.withSuccess("hello", MediaType.TEXT_PLAIN))
val greeting = service.callRestService()
assertThat(greeting).isEqualTo("hello")
}
}
當在被測試的 bean 中使用 RestClient.Builder
,或者使用 RestTemplateBuilder
但沒有呼叫 rootUri(String rootURI)
時,必須在 MockRestServiceServer
期望中使用完整的 URI,如下例所示
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.client.MockRestServiceServer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
@RestClientTest(RemoteVehicleDetailsService.class)
class MyRestClientServiceTests {
@Autowired
private RemoteVehicleDetailsService service;
@Autowired
private MockRestServiceServer server;
@Test
void getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {
this.server.expect(requestTo("https://example.com/greet/details"))
.andRespond(withSuccess("hello", MediaType.TEXT_PLAIN));
String greeting = this.service.callRestService();
assertThat(greeting).isEqualTo("hello");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest
import org.springframework.http.MediaType
import org.springframework.test.web.client.MockRestServiceServer
import org.springframework.test.web.client.match.MockRestRequestMatchers
import org.springframework.test.web.client.response.MockRestResponseCreators
@RestClientTest(RemoteVehicleDetailsService::class)
class MyRestClientServiceTests(
@Autowired val service: RemoteVehicleDetailsService,
@Autowired val server: MockRestServiceServer) {
@Test
fun getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {
server.expect(MockRestRequestMatchers.requestTo("https://example.com/greet/details"))
.andRespond(MockRestResponseCreators.withSuccess("hello", MediaType.TEXT_PLAIN))
val greeting = service.callRestService()
assertThat(greeting).isEqualTo("hello")
}
}
自動配置的 Spring REST Docs 測試
您可以使用 @AutoConfigureRestDocs
註解在您的測試中使用 Spring REST Docs,支援 Mock MVC、REST Assured 或 WebTestClient。它消除了 Spring REST Docs 中對 JUnit 擴充套件的需求。
@AutoConfigureRestDocs
可用於覆蓋預設的輸出目錄(如果使用 Maven 則為 target/generated-snippets
,如果使用 Gradle 則為 build/generated-snippets
)。它還可以用於配置出現在任何文件化 URI 中的主機、方案和埠。
使用 Mock MVC 的自動配置 Spring REST Docs 測試
@AutoConfigureRestDocs
會定製 MockMvc
bean,以便在測試基於 Servlet 的 Web 應用時使用 Spring REST Docs。您可以使用 @Autowired
注入它,並在測試中使用它,就像您通常使用 Mock MVC 和 Spring REST Docs 時一樣,如下例所示
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
@WebMvcTest(UserController.class)
@AutoConfigureRestDocs
class MyUserDocumentationTests {
@Autowired
private MockMvcTester mvc;
@Test
void listUsers() {
assertThat(this.mvc.get().uri("/users").accept(MediaType.TEXT_PLAIN)).hasStatusOk()
.apply(document("list-users"));
}
}
如果您更喜歡使用 AssertJ 整合,MockMvcTester
也可用,如下例所示
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
@WebMvcTest(UserController.class)
@AutoConfigureRestDocs
class MyUserDocumentationTests {
@Autowired
private MockMvcTester mvc;
@Test
void listUsers() {
assertThat(this.mvc.get().uri("/users").accept(MediaType.TEXT_PLAIN)).hasStatusOk()
.apply(document("list-users"));
}
}
兩者在後臺重用相同的 MockMvc
例項,因此對其進行的任何配置都適用於兩者。
如果您需要比 @AutoConfigureRestDocs
屬性提供的對 Spring REST Docs 配置更多的控制,可以使用 RestDocsMockMvcConfigurationCustomizer
bean,如下例所示
-
Java
-
Kotlin
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsMockMvcConfigurationCustomizer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer;
import org.springframework.restdocs.templates.TemplateFormats;
@TestConfiguration(proxyBeanMethods = false)
public class MyRestDocsConfiguration implements RestDocsMockMvcConfigurationCustomizer {
@Override
public void customize(MockMvcRestDocumentationConfigurer configurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
}
}
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsMockMvcConfigurationCustomizer
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer
import org.springframework.restdocs.templates.TemplateFormats
@TestConfiguration(proxyBeanMethods = false)
class MyRestDocsConfiguration : RestDocsMockMvcConfigurationCustomizer {
override fun customize(configurer: MockMvcRestDocumentationConfigurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown())
}
}
如果您想利用 Spring REST Docs 對引數化輸出目錄的支援,可以建立一個 RestDocumentationResultHandler
bean。自動配置會使用此結果處理器呼叫 alwaysDo
,從而導致每次 MockMvc
呼叫都自動生成預設片段。以下示例展示瞭如何定義 RestDocumentationResultHandler
-
Java
-
Kotlin
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
@TestConfiguration(proxyBeanMethods = false)
public class MyResultHandlerConfiguration {
@Bean
public RestDocumentationResultHandler restDocumentation() {
return MockMvcRestDocumentation.document("{method-name}");
}
}
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler
@TestConfiguration(proxyBeanMethods = false)
class MyResultHandlerConfiguration {
@Bean
fun restDocumentation(): RestDocumentationResultHandler {
return MockMvcRestDocumentation.document("{method-name}")
}
}
使用 WebTestClient 的自動配置 Spring REST Docs 測試
@AutoConfigureRestDocs
在測試響應式 Web 應用時也可與 WebTestClient
一起使用。您可以使用 @Autowired
注入它,並在您的測試中使用它,就像您通常使用 @WebFluxTest
和 Spring REST Docs 時一樣,如下例所示
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
@WebFluxTest
@AutoConfigureRestDocs
class MyUsersDocumentationTests {
@Autowired
private WebTestClient webTestClient;
@Test
void listUsers() {
this.webTestClient
.get().uri("/")
.exchange()
.expectStatus()
.isOk()
.expectBody()
.consumeWith(document("list-users"));
}
}
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation
import org.springframework.test.web.reactive.server.WebTestClient
@WebFluxTest
@AutoConfigureRestDocs
class MyUsersDocumentationTests(@Autowired val webTestClient: WebTestClient) {
@Test
fun listUsers() {
webTestClient
.get().uri("/")
.exchange()
.expectStatus()
.isOk
.expectBody()
.consumeWith(WebTestClientRestDocumentation.document("list-users"))
}
}
如果您需要比 @AutoConfigureRestDocs
屬性提供的對 Spring REST Docs 配置更多的控制,可以使用 RestDocsWebTestClientConfigurationCustomizer
bean,如下例所示
-
Java
-
Kotlin
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsWebTestClientConfigurationCustomizer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer;
@TestConfiguration(proxyBeanMethods = false)
public class MyRestDocsConfiguration implements RestDocsWebTestClientConfigurationCustomizer {
@Override
public void customize(WebTestClientRestDocumentationConfigurer configurer) {
configurer.snippets().withEncoding("UTF-8");
}
}
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsWebTestClientConfigurationCustomizer
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer
@TestConfiguration(proxyBeanMethods = false)
class MyRestDocsConfiguration : RestDocsWebTestClientConfigurationCustomizer {
override fun customize(configurer: WebTestClientRestDocumentationConfigurer) {
configurer.snippets().withEncoding("UTF-8")
}
}
如果您想利用 Spring REST Docs 對引數化輸出目錄的支援,可以使用 WebTestClientBuilderCustomizer
為每個實體交換結果配置一個消費者。以下示例展示瞭如何定義這樣的 WebTestClientBuilderCustomizer
-
Java
-
Kotlin
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.web.reactive.server.WebTestClientBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
@TestConfiguration(proxyBeanMethods = false)
public class MyWebTestClientBuilderCustomizerConfiguration {
@Bean
public WebTestClientBuilderCustomizer restDocumentation() {
return (builder) -> builder.entityExchangeResultConsumer(document("{method-name}"));
}
}
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.boot.test.web.reactive.server.WebTestClientBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation
import org.springframework.test.web.reactive.server.WebTestClient
@TestConfiguration(proxyBeanMethods = false)
class MyWebTestClientBuilderCustomizerConfiguration {
@Bean
fun restDocumentation(): WebTestClientBuilderCustomizer {
return WebTestClientBuilderCustomizer { builder: WebTestClient.Builder ->
builder.entityExchangeResultConsumer(
WebTestClientRestDocumentation.document("{method-name}")
)
}
}
}
使用 REST Assured 的自動配置 Spring REST Docs 測試
@AutoConfigureRestDocs
提供一個預配置為使用 Spring REST Docs 的 RequestSpecification
bean 供您在測試中使用。您可以使用 @Autowired
注入它,並在測試中使用它,就像您通常使用 REST Assured 和 Spring REST Docs 時一樣,如下例所示
-
Java
-
Kotlin
import io.restassured.specification.RequestSpecification;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.is;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestDocs
class MyUserDocumentationTests {
@Test
void listUsers(@Autowired RequestSpecification documentationSpec, @LocalServerPort int port) {
given(documentationSpec)
.filter(document("list-users"))
.when()
.port(port)
.get("/")
.then().assertThat()
.statusCode(is(200));
}
}
import io.restassured.RestAssured
import io.restassured.specification.RequestSpecification
import org.hamcrest.Matchers
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
import org.springframework.boot.test.web.server.LocalServerPort
import org.springframework.restdocs.restassured.RestAssuredRestDocumentation
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestDocs
class MyUserDocumentationTests {
@Test
fun listUsers(@Autowired documentationSpec: RequestSpecification?, @LocalServerPort port: Int) {
RestAssured.given(documentationSpec)
.filter(RestAssuredRestDocumentation.document("list-users"))
.`when`()
.port(port)["/"]
.then().assertThat()
.statusCode(Matchers.`is`(200))
}
}
如果您需要比 @AutoConfigureRestDocs
屬性提供的對 Spring REST Docs 配置更多的控制,可以使用 RestDocsRestAssuredConfigurationCustomizer
bean,如下例所示
-
Java
-
Kotlin
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsRestAssuredConfigurationCustomizer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.restdocs.restassured.RestAssuredRestDocumentationConfigurer;
import org.springframework.restdocs.templates.TemplateFormats;
@TestConfiguration(proxyBeanMethods = false)
public class MyRestDocsConfiguration implements RestDocsRestAssuredConfigurationCustomizer {
@Override
public void customize(RestAssuredRestDocumentationConfigurer configurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
}
}
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsRestAssuredConfigurationCustomizer
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.restdocs.restassured.RestAssuredRestDocumentationConfigurer
import org.springframework.restdocs.templates.TemplateFormats
@TestConfiguration(proxyBeanMethods = false)
class MyRestDocsConfiguration : RestDocsRestAssuredConfigurationCustomizer {
override fun customize(configurer: RestAssuredRestDocumentationConfigurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown())
}
}
自動配置的 Spring Web Services 測試
自動配置的 Spring Web Services 客戶端測試
您可以使用 @WebServiceClientTest
來測試使用 Spring Web Services 專案呼叫 Web 服務的應用。預設情況下,它配置一個 MockWebServiceServer
bean 並自動定製您的 WebServiceTemplateBuilder
。(更多關於在 Spring Boot 中使用 Web Services 的資訊,請參見Web Services。)
由 @WebServiceClientTest 啟用的自動配置設定列表在附錄中可以找到。 |
以下示例展示了 @WebServiceClientTest
註解的使用方法
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.webservices.client.WebServiceClientTest;
import org.springframework.ws.test.client.MockWebServiceServer;
import org.springframework.xml.transform.StringSource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.ws.test.client.RequestMatchers.payload;
import static org.springframework.ws.test.client.ResponseCreators.withPayload;
@WebServiceClientTest(SomeWebService.class)
class MyWebServiceClientTests {
@Autowired
private MockWebServiceServer server;
@Autowired
private SomeWebService someWebService;
@Test
void mockServerCall() {
this.server
.expect(payload(new StringSource("<request/>")))
.andRespond(withPayload(new StringSource("<response><status>200</status></response>")));
assertThat(this.someWebService.test())
.extracting(Response::getStatus)
.isEqualTo(200);
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.webservices.client.WebServiceClientTest
import org.springframework.ws.test.client.MockWebServiceServer
import org.springframework.ws.test.client.RequestMatchers
import org.springframework.ws.test.client.ResponseCreators
import org.springframework.xml.transform.StringSource
@WebServiceClientTest(SomeWebService::class)
class MyWebServiceClientTests(@Autowired val server: MockWebServiceServer, @Autowired val someWebService: SomeWebService) {
@Test
fun mockServerCall() {
server
.expect(RequestMatchers.payload(StringSource("<request/>")))
.andRespond(ResponseCreators.withPayload(StringSource("<response><status>200</status></response>")))
assertThat(this.someWebService.test()).extracting(Response::status).isEqualTo(200)
}
}
自動配置的 Spring Web Services 伺服器測試
您可以使用 @WebServiceServerTest
來測試使用 Spring Web Services 專案實現 Web 服務的應用。預設情況下,它配置一個 MockWebServiceClient
bean,可用於呼叫您的 Web 服務端點。(更多關於在 Spring Boot 中使用 Web Services 的資訊,請參見Web Services。)
由 @WebServiceServerTest 啟用的自動配置設定列表在附錄中可以找到。 |
以下示例展示了 @WebServiceServerTest
註解的使用方法
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.webservices.server.WebServiceServerTest;
import org.springframework.ws.test.server.MockWebServiceClient;
import org.springframework.ws.test.server.RequestCreators;
import org.springframework.ws.test.server.ResponseMatchers;
import org.springframework.xml.transform.StringSource;
@WebServiceServerTest(ExampleEndpoint.class)
class MyWebServiceServerTests {
@Autowired
private MockWebServiceClient client;
@Test
void mockServerCall() {
this.client
.sendRequest(RequestCreators.withPayload(new StringSource("<ExampleRequest/>")))
.andExpect(ResponseMatchers.payload(new StringSource("<ExampleResponse>42</ExampleResponse>")));
}
}
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.webservices.server.WebServiceServerTest
import org.springframework.ws.test.server.MockWebServiceClient
import org.springframework.ws.test.server.RequestCreators
import org.springframework.ws.test.server.ResponseMatchers
import org.springframework.xml.transform.StringSource
@WebServiceServerTest(ExampleEndpoint::class)
class MyWebServiceServerTests(@Autowired val client: MockWebServiceClient) {
@Test
fun mockServerCall() {
client
.sendRequest(RequestCreators.withPayload(StringSource("<ExampleRequest/>")))
.andExpect(ResponseMatchers.payload(StringSource("<ExampleResponse>42</ExampleResponse>")))
}
}
額外的自動配置和切片
每個切片提供一個或多個 @AutoConfigure…
註解,它們主要定義了應包含在切片中的自動配置。可以透過建立自定義的 @AutoConfigure…
註解或透過將 @ImportAutoConfiguration
新增到測試中來逐個測試地新增額外的自動配置,如下例所示
-
Java
-
Kotlin
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration;
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
@JdbcTest
@ImportAutoConfiguration(IntegrationAutoConfiguration.class)
class MyJdbcTests {
}
import org.springframework.boot.autoconfigure.ImportAutoConfiguration
import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest
@JdbcTest
@ImportAutoConfiguration(IntegrationAutoConfiguration::class)
class MyJdbcTests
請確保不要使用常規的 @Import 註解匯入自動配置,因為 Spring Boot 以特定方式處理它們。 |
或者,可以透過在儲存在 META-INF/spring
中的檔案中註冊它們,為任何使用切片註解的地方新增額外的自動配置,如下例所示
com.example.IntegrationAutoConfiguration
在此示例中,對於每個使用 @JdbcTest
註解的測試,都啟用了 com.example.IntegrationAutoConfiguration
。
您可以在此檔案中使用以 # 開頭的註釋。 |
只要切片或 @AutoConfigure… 註解元註解了 @ImportAutoConfiguration ,就可以透過這種方式進行定製。 |
使用者配置和切片
如果組織您的程式碼的方式合理,您的 @SpringBootApplication
類預設被用作測試的配置。
因此,不要在應用的主類中散佈特定於其某個功能領域的配置設定變得很重要。
假設您正在使用 Spring Data MongoDB,依賴於其自動配置,並且已啟用審計。您可以如下定義您的 @SpringBootApplication
-
Java
-
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
@SpringBootApplication
@EnableMongoAuditing
public class MyApplication {
// ...
}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.data.mongodb.config.EnableMongoAuditing
@SpringBootApplication
@EnableMongoAuditing
class MyApplication {
// ...
}
因為此類是測試的源配置,所以任何切片測試實際上都會嘗試啟用 Mongo 審計,這肯定不是您想要做的。建議的方法是將該領域特定的配置移到一個單獨的 @Configuration
類中,該類與您的應用處於同一級別,如下例所示
-
Java
-
Kotlin
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
@Configuration(proxyBeanMethods = false)
@EnableMongoAuditing
public class MyMongoConfiguration {
// ...
}
import org.springframework.context.annotation.Configuration
import org.springframework.data.mongodb.config.EnableMongoAuditing
@Configuration(proxyBeanMethods = false)
@EnableMongoAuditing
class MyMongoConfiguration {
// ...
}
根據應用程式的複雜性,您可以選擇使用一個單獨的 @Configuration 類來包含所有自定義配置,或者按領域劃分,每個領域一個類。後一種方法允許您在需要時透過 @Import 註解在某個測試中啟用特定配置。有關何時可能需要為 slice test 啟用特定 @Configuration 類的更多詳細資訊,請參閱 本 how-to 部分。 |
Slice test 會從掃描中排除 @Configuration
類。例如,對於 @WebMvcTest
,以下配置不會將給定的 WebMvcConfigurer
bean 包含在 slice test 載入的應用程式上下文中
-
Java
-
Kotlin
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration(proxyBeanMethods = false)
public class MyWebConfiguration {
@Bean
public WebMvcConfigurer testConfigurer() {
return new WebMvcConfigurer() {
// ...
};
}
}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
@Configuration(proxyBeanMethods = false)
class MyWebConfiguration {
@Bean
fun testConfigurer(): WebMvcConfigurer {
return object : WebMvcConfigurer {
// ...
}
}
}
然而,下面的配置將使自定義的 WebMvcConfigurer
由 slice test 載入。
-
Java
-
Kotlin
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Component
public class MyWebMvcConfigurer implements WebMvcConfigurer {
// ...
}
import org.springframework.stereotype.Component
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
@Component
class MyWebMvcConfigurer : WebMvcConfigurer {
// ...
}
另一個容易混淆的地方是 classpath 掃描。假設您以合理的方式組織了程式碼,但需要掃描額外的包。您的應用程式可能類似於以下程式碼
-
Java
-
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan({ "com.example.app", "com.example.another" })
public class MyApplication {
// ...
}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.annotation.ComponentScan
@SpringBootApplication
@ComponentScan("com.example.app", "com.example.another")
class MyApplication {
// ...
}
這樣做實際上覆蓋了預設的元件掃描指令,副作用是無論您選擇哪種 slice,都會掃描這兩個包。例如,@DataJpaTest
似乎突然掃描了應用程式的元件和使用者配置。同樣,將自定義指令移到一個單獨的類中是解決此問題的好方法。
如果這不適用於您,您可以在測試層次結構中的某個地方建立一個 @SpringBootConfiguration ,以便它被替代使用。或者,您可以為測試指定一個源,這會停用查詢預設源的行為。 |
使用 Spock 測試 Spring Boot 應用程式
Spock 2.2 或更高版本可用於測試 Spring Boot 應用程式。為此,請在應用程式的構建中新增 Spock 的 spock-spring
模組的 -groovy-4.0
版本依賴。spock-spring
將 Spring 的測試框架整合到 Spock 中。有關更多詳細資訊,請參閱 Spock Spring 模組的文件。