測試 Spring Boot 應用程式

Spring Boot 應用程式是 Spring ApplicationContext,因此除了您通常對一般的 Spring context 執行的操作之外,不需要做任何非常特別的事情來測試它。

只有當您使用 SpringApplication 建立 context 時,Spring Boot 的外部屬性、記錄和其他功能才會預設安裝在 context 中。

Spring Boot 提供了 @SpringBootTest 註解,當您需要 Spring Boot 功能時,可以使用它來替代標準的 spring-test @ContextConfiguration 註解。此註解透過SpringApplication 建立在您的測試中使用的 ApplicationContext來運作。除了 @SpringBootTest 之外,還提供了一些其他的註解,用於測試應用程式更特定的切片

如果您使用的是 JUnit 4,請不要忘記也將 @RunWith(SpringRunner.class) 新增到您的測試中,否則這些註解將被忽略。如果您使用的是 JUnit 5,則無需新增等效的 @ExtendWith(SpringExtension.class),因為 @SpringBootTest 和其他 @…​Test 註解已經使用它進行了註解。

預設情況下,@SpringBootTest 不會啟動伺服器。您可以使用 @SpringBootTestwebEnvironment 屬性來進一步調整測試的執行方式

  • MOCK (預設):載入網路 ApplicationContext 並提供模擬網路環境。使用此註解時,不會啟動嵌入式伺服器。如果您的類別路徑上沒有可用的網路環境,則此模式會透明地回退到建立常規的非網路 ApplicationContext。它可以與 @AutoConfigureMockMvc@AutoConfigureWebTestClient 結合使用,以進行基於模擬的網路應用程式測試。

  • RANDOM_PORT:載入 WebServerApplicationContext 並提供真實網路環境。嵌入式伺服器已啟動並在隨機埠上監聽。

  • DEFINED_PORT:載入 WebServerApplicationContext 並提供真實網路環境。嵌入式伺服器已啟動並在定義的埠 (來自您的 application.properties) 或預設埠 8080 上監聽。

  • NONE:使用 SpringApplication 載入 ApplicationContext,但不提供任何網路環境 (模擬或其他)。

如果您的測試是 @Transactional,則預設情況下,它會在每個測試方法結束時回滾交易。但是,由於將此配置與 RANDOM_PORTDEFINED_PORT 結合使用會隱含地提供真實的 servlet 環境,因此 HTTP 客戶端和伺服器會在不同的執行緒中運行,因此也會在不同的交易中運行。在這種情況下,伺服器上啟動的任何交易都不會回滾。
如果您的應用程式針對管理伺服器使用不同的埠,則具有 webEnvironment = WebEnvironment.RANDOM_PORT@SpringBootTest 也會在單獨的隨機埠上啟動管理伺服器。

偵測網路應用程式類型

如果 Spring MVC 可用,則會組態常規的基於 MVC 的應用程式 context。如果您只有 Spring WebFlux,我們將偵測到這一點,並組態基於 WebFlux 的應用程式 context。

如果兩者都存在,則 Spring MVC 優先。如果您想在這種情況下測試反應式網路應用程式,則必須設定 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 註解的類別為止。只要您以合理的方式結構化您的程式碼,通常就可以找到您的主要組態。

如果您使用測試註解來測試應用程式更特定的切片,則應避免在主方法的應用程式類別上新增特定於特定區域的組態設定。

@SpringBootApplication 的底層元件掃描組態定義了排除篩選器,這些篩選器用於確保切片按預期運作。如果您在使用 @ComponentScan 指令明確標註的 @SpringBootApplication 類別上使用 @ComponentScan 指令,請注意這些篩選器將被停用。如果您正在使用切片,則應再次定義它們。

如果您想自訂主要組態,可以使用巢狀 @TestConfiguration 類別。與將用於替代應用程式主要組態的巢狀 @Configuration 類別不同,巢狀 @TestConfiguration 類別會與應用程式的主要組態一起使用。

Spring 的測試框架會在測試之間快取應用程式 context。因此,只要您的測試共用相同的組態 (無論如何發現),載入 context 這個可能很耗時的程序就只會發生一次。

使用測試組態 Main 方法

通常,@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 之外,沒有做任何其他事情。但是,main 方法有可能更複雜,可以在呼叫 SpringApplication.run 之前套用自訂設定。

例如,以下是一個變更 banner 模式並設定其他設定檔的應用程式

  • 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

如果您想變更此行為,可以將 @SpringBootTestuseMainMethod 屬性變更為 UseMainMethod.ALWAYSUseMainMethod.WHEN_AVAILABLE。當設定為 ALWAYS 時,如果找不到 main 方法,測試將會失敗。當設定為 WHEN_AVAILABLE 時,如果 main 方法可用,則會使用它,否則將使用標準載入機制。

例如,以下測試將會叫用 MyApplicationmain 方法,以便建立 ApplicationContext。如果 main 方法設定了其他設定檔,則這些設定檔將在 ApplicationContext 啟動時處於活動狀態。

  • 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 不會啟動伺服器,而是設定模擬環境來測試網路端點。

使用 Spring MVC,我們可以使用 MockMvcWebTestClient 查詢我們的網路端點,如以下範例所示

  • 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 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 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.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.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import org.springframework.test.web.servlet.result.MockMvcResultMatchers

@SpringBootTest
@AutoConfigureMockMvc
class MyMockMvcTests {

	@Test
	fun testWithMockMvc(@Autowired mvc: MockMvc) {
		mvc.perform(MockMvcRequestBuilders.get("/")).andExpect(MockMvcResultMatchers.status().isOk)
			.andExpect(MockMvcResultMatchers.content().string("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")
	}

}
如果您只想專注於網路層,而不啟動完整的 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")
	}

}

在模擬環境中進行測試通常比在完整的 servlet 容器中執行更快。但是,由於模擬發生在 Spring MVC 層,因此依賴於較低層 servlet 容器行為的程式碼無法直接使用 MockMvc 進行測試。

例如,Spring Boot 的錯誤處理基於 servlet 容器提供的「錯誤頁面」支援。這表示,雖然您可以測試您的 MVC 層是否如預期拋出和處理例外狀況,但您無法直接測試是否呈現了特定的自訂錯誤頁面。如果您需要測試這些較低層次的考量,可以啟動完全運行的伺服器,如下節所述。

使用運行中的伺服器進行測試

如果您需要啟動完全運行的伺服器,我們建議您使用隨機埠。如果您使用 @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 註解您的測試類別即可。

此設定需要在類別路徑上使用 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 都會使用用於建立 WebTestClientWebTestClient.Builder 呼叫。

使用 JMX

由於測試 context 框架會快取 context,因此預設情況下會停用 JMX,以防止相同的元件在相同的網域上註冊。如果此類測試需要存取 MBeanServer,請考慮也將其標記為髒污

  • 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")
		// ...
	}

}

使用 Observability

如果您使用 @AutoConfigureObservability 註解切片測試,它會自動組態 ObservationRegistry

使用指標

無論您的類別路徑如何,當使用 @SpringBootTest 時,除了記憶體支援的儀表登錄檔之外,儀表登錄檔都不會自動組態。

如果您需要在整合測試中將指標匯出到不同的後端,請使用 @AutoConfigureObservability 註解它。

如果您使用 @AutoConfigureObservability 註解切片測試,它會自動組態記憶體中的 MeterRegistry。切片測試中的資料匯出不受 @AutoConfigureObservability 註解支援。

使用追蹤

無論您的類別路徑如何,當使用 @SpringBootTest 時,都不會自動組態報告資料的追蹤元件。

如果您需要在整合測試中使用這些元件,請使用 @AutoConfigureObservability 註解測試。

如果您建立了您自己的報告元件 (例如,自訂 SpanExporterSpanHandler),並且您不希望它們在測試中處於活動狀態,則可以使用 @ConditionalOnEnabledTracing 註解來停用它們。

如果您使用 @AutoConfigureObservability 註解切片測試,它會自動組態 no-op Tracer。切片測試中的資料匯出不受 @AutoConfigureObservability 註解支援。

模擬和間諜 Bean

在運行測試時,有時需要模擬應用程式 context 中的某些元件。例如,您可能在某些遠端服務上具有 facade,而這些服務在開發期間不可用。當您想要模擬在真實環境中可能難以觸發的失敗時,模擬也很有用。

Spring Boot 包含 @MockBean 註解,可用於在您的 ApplicationContext 內部為 Bean 定義 Mockito 模擬。您可以使用此註解來新增 Bean 或取代單個現有的 Bean 定義。此註解可以直接在測試類別、測試中的欄位或 @Configuration 類別和欄位上使用。在欄位上使用時,也會注入已建立模擬的實例。模擬 Bean 會在每個測試方法之後自動重設。

如果您的測試使用 Spring Boot 的測試註解之一 (例如 @SpringBootTest),則會自動啟用此功能。若要將此功能與不同的配置一起使用,必須明確新增監聽器,如以下範例所示

  • Java

  • Kotlin

import org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener;
import org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;

@ContextConfiguration(classes = MyConfig.class)
@TestExecutionListeners({ MockitoTestExecutionListener.class, ResetMocksTestExecutionListener.class })
class MyTests {

	// ...

}
import org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener
import org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.TestExecutionListeners

@ContextConfiguration(classes = [MyConfig::class])
@TestExecutionListeners(
	MockitoTestExecutionListener::class,
	ResetMocksTestExecutionListener::class
)
class MyTests {

	// ...

}

以下範例使用模擬實作取代現有的 RemoteService Bean

  • 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.mock.mockito.MockBean;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;

@SpringBootTest
class MyTests {

	@Autowired
	private Reverser reverser;

	@MockBean
	private RemoteService remoteService;

	@Test
	void exampleTest() {
		given(this.remoteService.getValue()).willReturn("spring");
		String reverse = this.reverser.getReverseValue(); // Calls injected RemoteService
		assertThat(reverse).isEqualTo("gnirps");
	}

}
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.context.SpringBootTest
import org.springframework.boot.test.mock.mockito.MockBean

@SpringBootTest
class MyTests(@Autowired val reverser: Reverser, @MockBean val remoteService: RemoteService) {

	@Test
	fun exampleTest() {
		given(remoteService.value).willReturn("spring")
		val reverse = reverser.reverseValue // Calls injected RemoteService
		assertThat(reverse).isEqualTo("gnirps")
	}

}
@MockBean 無法用於模擬在應用程式 context 重新整理期間執行的 Bean 的行為。當執行測試時,應用程式 context 重新整理已完成,並且組態模擬行為為時已晚。我們建議在此情況下使用 @Bean 方法來建立和組態模擬。

此外,您可以使用 @SpyBean 將任何現有的 Bean 與 Mockito spy 包裝在一起。請參閱 SpyBean API 文件以取得完整詳細資訊。

雖然 Spring 的測試框架會在測試之間快取應用程式 context,並為共用相同組態的測試重複使用 context,但使用 @MockBean@SpyBean 會影響快取索引鍵,這很可能會增加 context 的數量。
如果您使用 @SpyBean 來監視具有 @Cacheable 方法 (這些方法依名稱引用參數) 的 Bean,則必須使用 -parameters 編譯您的應用程式。這可確保一旦 Bean 被監視,參數名稱即可用於快取基礎架構。
當您使用 @SpyBean 來監視由 Spring 代理的 Bean 時,在某些情況下您可能需要移除 Spring 的代理,例如在使用 givenwhen 設定預期時。使用 AopTestUtils.getTargetObject(yourProxiedSpy) 來執行此操作。

自動組態測試

Spring Boot 的自動組態系統適用於應用程式,但有時對測試來說有點過多。通常,僅載入測試應用程式「切片」所需的部分組態會有所幫助。例如,您可能想要測試 Spring MVC 控制器是否正確對應 URL,並且您不希望在這些測試中涉及資料庫呼叫,或者您可能想要測試 JPA 實體,並且在這些測試運行時您對網路層不感興趣。

spring-boot-test-autoconfigure 模組包含許多註解,可用於自動組態此類「切片」。它們中的每一個都以類似的方式運作,提供載入 ApplicationContext@…​Test 註解,以及可用於自訂自動組態設定的一個或多個 @AutoConfigure…​ 註解。

每個切片都將元件掃描限制為適當的元件,並載入非常受限的自動組態類別集。如果您需要排除其中一個,大多數 @…​Test 註解都提供 excludeAutoConfiguration 屬性。或者,您可以使用 @ImportAutoConfiguration#exclude
不支援在一個測試中使用多個 @…​Test 註解來包含多個「切片」。如果您需要多個「切片」,請選擇其中一個 @…​Test 註解,並手動包含其他「切片」的 @AutoConfigure…​ 註解。
也可以將 @AutoConfigure…​ 註解與標準 @SpringBootTest 註解一起使用。如果您對「切片」您的應用程式不感興趣,但想要一些自動組態的測試 Bean,則可以使用此組合。

自動組態 JSON 測試

若要測試物件 JSON 序列化和反序列化是否按預期運作,您可以使用 @JsonTest 註解。 @JsonTest 自動組態可用的受支援 JSON 對應器,它可以是以下程式庫之一

  • Jackson ObjectMapper、任何 @JsonComponent Bean 和任何 Jackson Module

  • Gson

  • Jsonb

@JsonTest 啟用的自動組態清單可以在附錄中找到

如果您需要組態自動組態的元素,可以使用 @AutoConfigureJsonTesters 註解。

Spring Boot 包含基於 AssertJ 的輔助程式,這些輔助程式與 JSONAssert 和 JsonPath 程式庫一起使用,以檢查 JSON 是否如預期顯示。 JacksonTesterGsonTesterJsonbTesterBasicJsonTester 類別分別可用於 Jackson、Gson、Jsonb 和字串。當使用 @JsonTest 時,測試類別上的任何輔助欄位都可以 @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 輔助類別也可以直接在標準單元測試中使用。若要執行此操作,如果您不使用 @JsonTest,請在 @Before 方法中呼叫輔助程式的 initFields 方法。

如果您使用 Spring Boot 基於 AssertJ 的輔助程式來斷言給定 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@JsonComponentConverterGenericConverterFilterHandlerInterceptorWebMvcConfigurerWebMvcRegistrationsHandlerMethodArgumentResolver。當使用 @WebMvcTest 註解時,不會掃描常規的 @Component@ConfigurationProperties Bean。 @EnableConfigurationProperties 可用於包含 @ConfigurationProperties Bean。

@WebMvcTest 啟用的自動組態設定清單可以在附錄中找到
如果您需要註冊額外的元件,例如 Jackson Module,您可以使用測試中的 @Import 匯入其他組態類別。

通常,@WebMvcTest 僅限於單個控制器,並與 @MockBean 結合使用,以為所需的協作者提供模擬實作。

@WebMvcTest 也會自動組態 MockMvc。 Mock MVC 提供了一種強大的方法,可以快速測試 MVC 控制器,而無需啟動完整的 HTTP 伺服器。

您也可以在非 @WebMvcTest (例如 @SpringBootTest) 中自動組態 MockMvc,方法是使用 @AutoConfigureMockMvc 註解它。以下範例使用 MockMvc
  • 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.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import static org.mockito.BDDMockito.given;
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;

@WebMvcTest(UserVehicleController.class)
class MyControllerTests {

	@Autowired
	private MockMvc mvc;

	@MockBean
	private UserVehicleService userVehicleService;

	@Test
	void testExample() throws Exception {
		given(this.userVehicleService.getVehicleDetails("sboot"))
			.willReturn(new VehicleDetails("Honda", "Civic"));
		this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
			.andExpect(status().isOk())
			.andExpect(content().string("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.servlet.WebMvcTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import org.springframework.test.web.servlet.result.MockMvcResultMatchers

@WebMvcTest(UserVehicleController::class)
class MyControllerTests(@Autowired val mvc: MockMvc) {

	@MockBean
	lateinit var userVehicleService: UserVehicleService

	@Test
	fun testExample() {
		given(userVehicleService.getVehicleDetails("sboot"))
			.willReturn(VehicleDetails("Honda", "Civic"))
		mvc.perform(MockMvcRequestBuilders.get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
			.andExpect(MockMvcResultMatchers.status().isOk)
			.andExpect(MockMvcResultMatchers.content().string("Honda Civic"))
	}

}
如果您需要組態自動組態的元素 (例如,何時應套用 servlet 篩選器),則可以使用 @AutoConfigureMockMvc 註解中的屬性。

如果您使用 HtmlUnit 和 Selenium,自動組態也會提供 HtmlUnit WebClient Bean 和/或 Selenium WebDriver Bean。以下範例使用 HtmlUnit

  • Java

  • Kotlin

import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.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.boot.test.mock.mockito.MockBean;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;

@WebMvcTest(UserVehicleController.class)
class MyHtmlUnitTests {

	@Autowired
	private WebClient webClient;

	@MockBean
	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 com.gargoylesoftware.htmlunit.WebClient
import com.gargoylesoftware.htmlunit.html.HtmlPage
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.boot.test.mock.mockito.MockBean

@WebMvcTest(UserVehicleController::class)
class MyHtmlUnitTests(@Autowired val webClient: WebClient) {

	@MockBean
	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("singleton") 新增到您的 WebDriver @Bean 定義中。
由 Spring Boot 建立的 webDriver scope 將會取代任何使用者定義的同名 scope。如果您定義了自己的 webDriver scope,您可能會發現當您使用 @WebMvcTest 時它會停止運作。

如果您的 classpath 中有 Spring Security,@WebMvcTest 也會掃描 WebSecurityConfigurer beans。您可以改用 Spring Security 的測試支援,而不是完全停用此類測試的安全性。關於如何使用 Spring Security 的 MockMvc 支援的更多詳細資訊,可以在「操作指南」章節的使用 Spring Security 進行測試中找到。

有時編寫 Spring MVC 測試可能還不夠;Spring Boot 可以幫助您執行使用實際伺服器的完整端對端測試

自動配置 Spring WebFlux 測試

為了測試 Spring WebFlux controllers 是否如預期般運作,您可以使用 @WebFluxTest 註解。@WebFluxTest 自動配置 Spring WebFlux 基礎架構,並將掃描的 beans 限制為 @Controller@ControllerAdvice@JsonComponentConverterGenericConverterWebFilterWebFluxConfigurer。當使用 @WebFluxTest 註解時,常規的 @Component@ConfigurationProperties beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。

關於 @WebFluxTest 啟用的自動配置列表,可以在附錄中找到
如果您需要註冊額外的組件,例如 Jackson Module,您可以使用測試中的 @Import 匯入額外的配置類別。

通常,@WebFluxTest 僅限於單一 controller,並與 @MockBean 註解結合使用,以為所需的協作者提供模擬實作。

@WebFluxTest 還自動配置了 WebTestClient,它提供了一種強大的方法來快速測試 WebFlux controllers,而無需啟動完整的 HTTP 伺服器。

您也可以在非 @WebFluxTest 的環境(例如 @SpringBootTest)中自動配置 WebTestClient,方法是使用 @AutoConfigureWebTestClient 註解它。以下範例顯示了一個同時使用 @WebFluxTestWebTestClient 的類別
  • 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.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;

import static org.mockito.BDDMockito.given;

@WebFluxTest(UserVehicleController.class)
class MyControllerTests {

	@Autowired
	private WebTestClient webClient;

	@MockBean
	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.boot.test.mock.mockito.MockBean
import org.springframework.http.MediaType
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) {

	@MockBean
	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 無法偵測透過 functional web framework 註冊的路由。為了在上下文中測試 RouterFunction beans,請考慮使用 @Import 自行匯入您的 RouterFunction,或使用 @SpringBootTest
@WebFluxTest 無法偵測註冊為 SecurityWebFilterChain 類型的 @Bean 的自訂安全性配置。為了將其包含在您的測試中,您需要使用 @Import 或使用 @SpringBootTest 匯入註冊該 bean 的配置。
有時編寫 Spring WebFlux 測試可能還不夠;Spring Boot 可以幫助您執行使用實際伺服器的完整端對端測試

自動配置 Spring GraphQL 測試

Spring GraphQL 提供了一個專用的測試支援模組;您需要將其新增到您的專案中

Maven
<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>
Gradle
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 Controllers@GraphQlTest 自動配置 Spring GraphQL 基礎架構,不涉及任何傳輸或伺服器。這將掃描的 beans 限制為 @ControllerRuntimeWiringConfigurerJsonComponentConverterGenericConverterDataFetcherExceptionResolverInstrumentationGraphQlSourceBuilderCustomizer。當使用 @GraphQlTest 註解時,常規的 @Component@ConfigurationProperties beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。

關於 @GraphQlTest 啟用的自動配置列表,可以在附錄中找到

通常,@GraphQlTest 僅限於一組 controllers,並與 @MockBean 註解結合使用,以為所需的協作者提供模擬實作。

  • 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 測試是完整的整合測試,涉及整個應用程式。當使用隨機或定義的埠時,會配置即時伺服器,並且會自動貢獻 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 儲存庫。當使用 @DataCassandraTest 註解時,常規的 @Component@ConfigurationProperties beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。(有關將 Cassandra 與 Spring Boot 一起使用的更多資訊,請參閱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 應用程式。預設情況下,它會配置 CouchbaseTemplateReactiveCouchbaseTemplate,掃描 @Document 類別,並配置 Spring Data Couchbase 儲存庫。當使用 @DataCouchbaseTest 註解時,常規的 @Component@ConfigurationProperties beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。(有關將 Couchbase 與 Spring Boot 一起使用的更多資訊,請參閱本章稍早的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 應用程式。預設情況下,它會配置 ElasticsearchRestTemplate,掃描 @Document 類別,並配置 Spring Data Elasticsearch 儲存庫。當使用 @DataElasticsearchTest 註解時,常規的 @Component@ConfigurationProperties beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。(有關將 Elasticsearch 與 Spring Boot 一起使用的更多資訊,請參閱本章稍早的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 儲存庫。如果 classpath 上有可用的嵌入式資料庫,它也會配置一個。SQL 查詢預設會透過將 spring.jpa.show-sql 屬性設定為 true 來記錄。可以使用註解的 showSql 屬性來停用此功能。

當使用 @DataJpaTest 註解時,常規的 @Component@ConfigurationProperties beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。

關於 @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 beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。

關於 @JdbcTest 啟用的自動配置列表,可以在附錄中找到

預設情況下,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 beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。

關於 @DataJdbcTest 啟用的自動配置列表,可以在附錄中找到

預設情況下,Data JDBC 測試是事務性的,並且在每個測試結束時回滾。有關更多詳細資訊,請參閱 Spring Framework 參考文件中的相關章節。如果那不是您想要的,您可以為測試或整個測試類別停用事務管理,如JDBC 範例中所示

如果您希望您的測試針對真實資料庫運行,則可以使用 @AutoConfigureTestDatabase 註解,方式與 @DataJpaTest 相同。(請參閱自動配置 Data JPA 測試。)

自動配置 Data R2DBC 測試

@DataR2dbcTest 類似於 @DataJdbcTest,但適用於使用 Spring Data R2DBC 儲存庫的測試。預設情況下,它會配置記憶體中的嵌入式資料庫、R2dbcEntityTemplate 和 Spring Data R2DBC 儲存庫。當使用 @DataR2dbcTest 註解時,常規的 @Component@ConfigurationProperties beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。

關於 @DataR2dbcTest 啟用的自動配置列表,可以在附錄中找到

預設情況下,Data R2DBC 測試不是事務性的。

如果您希望您的測試針對真實資料庫運行,則可以使用 @AutoConfigureTestDatabase 註解,方式與 @DataJpaTest 相同。(請參閱自動配置 Data JPA 測試。)

自動配置 jOOQ 測試

您可以像 @JdbcTest 一樣使用 @JooqTest,但適用於 jOOQ 相關的測試。由於 jOOQ 非常依賴與資料庫 schema 對應的基於 Java 的 schema,因此會使用現有的 DataSource。如果您想用記憶體資料庫替換它,可以使用 @AutoConfigureTestDatabase 來覆寫這些設定。(有關將 jOOQ 與 Spring Boot 一起使用的更多資訊,請參閱使用 jOOQ。)當使用 @JooqTest 註解時,常規的 @Component@ConfigurationProperties beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。

關於 @JooqTest 啟用的自動配置列表,可以在附錄中找到

@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 beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。(有關將 MongoDB 與 Spring Boot 一起使用的更多資訊,請參閱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 beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。(有關將 Neo4J 與 Spring Boot 一起使用的更多資訊,請參閱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 beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。(有關將 Redis 與 Spring Boot 一起使用的更多資訊,請參閱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 beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。(有關將 LDAP 與 Spring Boot 一起使用的更多資訊,請參閱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 Clients

您可以使用 @RestClientTest 註解來測試 REST clients。預設情況下,它會自動配置 Jackson、GSON 和 Jsonb 支援,配置 RestTemplateBuilderRestClient.Builder,並新增對 MockRestServiceServer 的支援。當使用 @RestClientTest 註解時,常規的 @Component@ConfigurationProperties beans 不會被掃描。可以使用 @EnableConfigurationProperties 來包含 @ConfigurationProperties beans。

關於 @RestClientTest 啟用的自動配置設定列表,可以在附錄中找到

您要測試的特定 beans 應透過使用 @RestClientTestvaluecomponents 屬性來指定。

當在測試中的 beans 中使用 RestTemplateBuilder,並且在建構 RestTemplate 時已呼叫 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(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")
	}

}

當在測試中的 beans 中使用 RestClient.Builder,或在使用 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(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 註解,在您的測試中搭配 Mock MVC、REST Assured 或 WebTestClient 使用 Spring REST Docs。它消除了 Spring REST Docs 中 JUnit 擴充功能的需要。

@AutoConfigureRestDocs 可以用於覆寫預設輸出目錄(如果您使用 Maven 則為 target/generated-snippets,如果您使用 Gradle 則為 build/generated-snippets)。它也可以用於配置任何已記錄 URI 中顯示的主機、scheme 和埠。

使用 Mock MVC 自動配置 Spring REST Docs 測試

@AutoConfigureRestDocs 自訂了 MockMvc bean,以便在測試基於 servlet 的 Web 應用程式時使用 Spring REST Docs。您可以使用 @Autowired 注入它,並在您的測試中使用它,就像您通常在使用 Mock MVC 和 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.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(UserController.class)
@AutoConfigureRestDocs
class MyUserDocumentationTests {

	@Autowired
	private MockMvc mvc;

	@Test
	void listUsers() throws Exception {
		this.mvc.perform(get("/users").accept(MediaType.TEXT_PLAIN))
			.andExpect(status().isOk())
			.andDo(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.servlet.WebMvcTest
import org.springframework.http.MediaType
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import org.springframework.test.web.servlet.result.MockMvcResultMatchers

@WebMvcTest(UserController::class)
@AutoConfigureRestDocs
class MyUserDocumentationTests(@Autowired val mvc: MockMvc) {

	@Test
	fun listUsers() {
		mvc.perform(MockMvcRequestBuilders.get("/users").accept(MediaType.TEXT_PLAIN))
			.andExpect(MockMvcResultMatchers.status().isOk)
			.andDo(MockMvcRestDocumentation.document("list-users"))
	}

}

如果您需要比 @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 測試

在測試反應式 Web 應用程式時,@AutoConfigureRestDocs 也可以與 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 來為每個實體交換結果配置 consumer。以下範例顯示了如何定義這樣的 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 使 RequestSpecification bean 可用於您的測試,該 bean 預先配置為使用 Spring REST Docs。您可以使用 @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 services 的應用程式。預設情況下,它會配置 mock WebServiceServer bean 並自動自訂您的 WebServiceTemplateBuilder。(有關將 Web Services 與 Spring Boot 一起使用的更多資訊,請參閱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 services 的應用程式。預設情況下,它會配置 MockWebServiceClient bean,可用於呼叫您的 web service endpoints。(有關將 Web Services 與 Spring Boot 一起使用的更多資訊,請參閱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 中的檔案中,為任何切片註解的使用新增它們,如下列範例所示

META-INF/spring/org.springframework.boot.test.autoconfigure.jdbc.JdbcTest.imports
com.example.IntegrationAutoConfiguration

在此範例中,com.example.IntegrationAutoConfiguration 在每個使用 @JdbcTest 註解的測試中啟用。

您可以在此檔案中使用 # 註解。
只要切片或 @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 註解在您的其中一個測試中啟用它。有關您可能想要為切片測試啟用特定 @Configuration 類別的更多詳細資訊,請參閱此操作指南章節

測試切片排除掃描 @Configuration 類別。例如,對於 @WebMvcTest,以下配置將不會在測試切片載入的應用程式上下文中包含給定的 WebMvcConfigurer bean

  • 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

  • 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 {

	// ...

}

另一個造成混淆的來源是類別路徑掃描。假設您以合理的方式組織了程式碼,但您需要掃描額外的套件。您的應用程式可能類似於以下程式碼

  • 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 {

	// ...

}

這樣做會有效地覆寫預設的元件掃描指令,其副作用是不論您選擇哪個切片,都會掃描這兩個套件。例如,@DataJpaTest 似乎會突然掃描您應用程式的元件和使用者組態。同樣地,將自訂指令移到單獨的類別是解決此問題的好方法。

如果這不是您的選項,您可以在測試階層結構中的某處建立一個 @SpringBootConfiguration,以便改為使用它。或者,您可以為您的測試指定一個來源,這會停用尋找預設來源的行為。

使用 Spock 測試 Spring Boot 應用程式

Spock 2.2 或更高版本可用於測試 Spring Boot 應用程式。為此,請將 Spock 的 spock-spring 模組的 -groovy-4.0 版本相依性新增至您應用程式的建置中。spock-spring 將 Spring 的測試框架整合到 Spock 中。請參閱 Spock Spring 模組的文件 以取得更多詳細資訊。