如下內容,翻譯自官方文檔,並結合了學習過程的demo。html
Spring Boot提供了許多實用程序和註解,幫助測試應用程序。測試支持由兩個模塊提供:spring-boot-test
包含核心項,spring-boot-test-autoconfigure
支持測試的自動配置。大多數開發人員使用
spring-boot-starter-test
,它同時導入 SpringBoot 測試模塊以及JUnit Jupiter、AssertJ、Hamcrest和許多其餘有用的庫。java
此文使用當前最新穩定版本: SpringBoot 2.2.2.RELEASE
此 starter 還帶來了 vintage 引擎,所以能夠同時運行JUnit 4和JUnit 5測試。若是已經將測試遷移到JUnit5,那麼應該排除JUnit4支持,以下例所示:react
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <exclusions> <exclusion> <!-- 此模塊兼容junit4 和 junit 5,此示例直接使用 junit5 --> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> <scope>test</scope> </dependency>
spring-boot-starter-test
(依賴 scope
爲 test
)包含如下庫:git
依賴注入的一個主要優勢是它應該使代碼更容易進行單元測試。可使用新的操做符實例化對象,甚至不涉及Spring。也可使用模擬對象而不是實際依賴項。一般,您須要超越單元測試,開始集成測試(使用Spring ApplicationContext)。可以在不須要部署應用程序或鏈接到其餘基礎結構的狀況下執行集成測試是很是有用的。github
Spring框架包含了一個專門的集成測試模塊。能夠直接向
org.springframework:spring
測試聲明一個依賴項,或者使用spring-boot-starter-test
。web若是之前沒有使用過
spring-test
模塊,那麼應該從閱讀spring框架參考文檔的相關部分開始。redis
SpringBoot 應用程序是 Spring ApplicationContext
,所以除了使用普通的Spring上下文以外,沒必要作任何特別的事情來測試它。算法
默認狀況下,只有在使用 SpringApplication
建立 Spring Boot時,它的外部屬性、日誌記錄和其餘特性纔會安裝在上下文中。spring
SpringBoot 提供了一個 @SpringBootTest
註解,當須要SpringBoot 特性時,它能夠做爲標準 spring-test
@ContextConfiguration
註解的替代。註解的工做方式是經過 SpringApplication
建立測試中使用的ApplicationContext。除了 @SpringBootTest
以外,還提供了一些其餘註解,用於測試應用程序的更具體的部分。數據庫
若是使用的是JUnit4,不要忘記將 @RunWith(SpringRunner.class)
添加到測試中,不然註解將被忽略。若是使用的是JUnit5,則不須要添加與 @SpringBootTest
和 其餘已經使用的註解等效的 @ExtendWith(SpringExtension.class)
默認狀況下,@SpringBootTest
不會啓動服務器。可使用 @SpringBootTest
的 webEnvironment
屬性進一步優化測試的運行方式:
MOCK
(默認):加載 web ApplicationContext
並提供模擬web環境。使用此註解時,嵌入式服務器未啓動。若是類路徑上沒有可用的web環境,則此模式會透明地回退到建立常規的非web ApplicationContext
。它能夠與 @AutoConfigureMockMvc
或 @AutoConfigureWebTestClient
結合使用,對web應用程序進行基於模擬的測試。RANDOM_PORT
:加載 WebServerApplicationContext
並提供真正的web環境。嵌入式服務器啓動並在隨機端口上監聽。DEFINED_PORT
:加載 WebServerApplicationContext
並提供真正的web環境。嵌入式服務器將啓動並在定義的端口(從 application.properties
)或默認端口8080上監聽。NONE
:使用 SpringApplication
加載 ApplicationContext
,但不提供任何web環境(mock或其餘)。若是測試是 @Transactional
,那麼默認狀況下,它會在每一個測試方法結束時回滾事務。然而,因爲對隨機端口或定義的端口使用這種安排隱式地提供了一個真正的servlet環境,HTTP客戶機和服務器在單獨的線程中運行,所以在單獨的事務中運行。在這種狀況下,服務器上啓動的任何事務都不會回滾。
@使用 webEnvironment=webEnvironment.RANDOM_PORT
的 @SpringBootTest
也將在單獨的隨機端口上啓動管理服務器,若是應用程序對管理服務器使用不一樣的端口。
若是 Spring MVC 可用,那麼將配置一個常規的基於MVC的應用程序上下文。若是隻有Spring WebFlux,將檢測並配置基於 WebFlux 的應用程序上下文。
若是二者都存在,則以Spring MVC爲準。若是要在此方案中測試響應式web應用程序,則必須設置 spring.main.web-application-type
屬性:
@SpringBootTest(properties = "spring.main.web-application-type=reactive") class MyWebFluxTests { ... }
Spring 測試框架中,可使用 @ContextConfiguration(classes=…)
來指定加載那個 Spring @Configuration
。
在測試 Spring Boot 應用程序時,這一般不是必需的。Spring Boot的 @Test 類註解在沒有顯式定義主配置時自動搜索主配置。
搜索算法從包含測試的包開始工做,直到找到用 @SpringBootApplication
或 @SpringBootConfiguration
註解的類爲止。只要以合理的方式構造代碼,一般都會找到主配置。
若是要自定義主配置,可使用嵌套的 @TestConfiguration
類。與嵌套的 @Configuration
類(將用於替代應用程序的主配置)不一樣,嵌套的 @TestConfiguration
類是在應用程序的主配置額外使用的。
Spring的測試框架在測試之間緩存應用程序上下文。所以,只要您的測試共享相同的配置(不管如何發現),加載上下文的潛在耗時過程只發生一次。
若是使用了@SpringBootApplication
或@ComponentScan
掃描,針對特定測試的頂級配置類可能在任何地方都可以被獲取到。
如前所述,@TestConfiguration
可用於測試的內部類,以自定義主要配置。當放置在頂級類上時,@TestConfiguration
表示 src/test/java
中的類不該該經過掃描來獲取。而後,能夠在須要時顯式導入該類,以下例所示:
@SpringBootTest @Import(MyTestsConfiguration.class) class MyTests { @Test void exampleTest() { //... } }
若是應用程序須要參數,可使用 @SpringBootTest
的 args
屬性注入它們。
@SpringBootTest(args = "--app.name=test", webEnvironment = WebEnvironment.NONE) public class ArgTests { @Test public void applicationArgsTest(@Autowired ApplicationArguments args) { assertThat(args.getOptionNames()).containsOnly("app.name"); assertThat(args.getOptionValues("app.name")).containsOnly("test"); } }
默認狀況下,@SpringBootTest
不會啓動服務器。若是在此模擬環境中有要測試的web端點,則能夠另外配置MockMvc,以下例所示:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
public interface ConstantUtil { String body = "Hello World!"; }
@RestController public class HelloWorldController { @RequestMapping public String helloWorld(){ return ConstantUtil.body; } }
@SpringBootTest @AutoConfigureMockMvc public class MockMvcTests { @Test public void test(@Autowired MockMvc mvc) throws Exception { mvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string(ConstantUtil.body)); } }
若是您只想關注web層而不想啓動一個完整的ApplicationContext
,能夠考慮改用@WebMvcTest
。
另外,能夠配置 WebTestClient
,以下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
/** * WebTestClient<br> * WebTestClient 屬於 reactive,設置spring.main.web-application-type=reactive */ @SpringBootTest(properties = "spring.main.web-application-type=reactive") @AutoConfigureWebTestClient public class MockWebTestClientTests { @Test public void test(@Autowired WebTestClient webTestClient) { webTestClient .get() .uri("/") .exchange() .expectStatus() .isOk() .expectBody(String.class) .isEqualTo(ConstantUtil.body); } }
在模擬環境中進行測試一般比使用完整的Servlet容器運行要快。可是,因爲模擬發生在Spring MVC層,依賴於低級Servlet容器行爲的代碼不能直接用MockMvc測試。
例如,Spring Boot的錯誤處理基於Servlet容器提供的「錯誤頁」支持。這意味着,雖然能夠按預期測試MVC層拋出和處理異常,但不能直接測試是否呈現了特定的自定義錯誤頁。若是須要測試這些較低級別的關注點,能夠按照下一節中的說明啓動徹底運行的服務器。
若是須要啓動徹底運行的服務器,建議使用隨機端口。若是使用 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
,則每次運行測試時都會隨機選擇一個可用端口。
@LocalServerPort
註解可用於將實際使用的端口注入測試。爲了方便起見,須要對啓動的服務器進行REST調用的測試還能夠 @Autowire
一個 WebTestClient
,它解析到正在運行的服務器的相關連接,並附帶用於驗證響應的專用API,以下例所示:
/** * 使用運行中的server<br> * 使用 webflux * * @author YiFeiXi */ @SpringBootTest( webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=reactive") public class RandomPortWebTestClientTests { @Test public void test(@Autowired WebTestClient webTestClient) { webTestClient .get() .uri("/") .exchange() .expectStatus() .isOk() .expectBody(String.class) .isEqualTo(ConstantUtil.body); } }
此設置須要類路徑上的 spring-webflux
。若是您不能或不想添加webflux,Spring Boot 還提供了一個 TestRestTemplate
工具:
/** * 使用運行中的server<br> * 不使用 webflux * * @author YiFeiXi */ @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) public class RandomPortTestRestTemplateTests { @Test public void test(@Autowired TestRestTemplate restTemplate) { String body = restTemplate.getForObject("/", String.class); assertThat(body).isEqualTo(ConstantUtil.body); } }
要自定義 WebTestClient
bean,需配置 WebTestClientBuilderCustomizer
bean。使用用於建立 WebTestClient
的 WebTestClient.Builder
調用任何此類bean。
因爲測試上下文框架緩存上下文的緣由,默認狀況下禁用JMX以防止相同的組件在同一域上註冊。若是此類測試須要訪問 MBeanServer
,請考慮將其標記爲dirty :
@ExtendWith(SpringExtension.class) @SpringBootTest(properties = "spring.jmx.enabled=true") @DirtiesContext class SampleJmxTests { @Autowired private MBeanServer mBeanServer; @Test void exampleTest() { // ... } }
運行測試時,有時須要在應用程序上下文中模擬某些組件。例如,可能有一個表面覆蓋了一些在開發期間不可用的遠程服務。當您但願模擬在實際環境中可能難以觸發的故障時,模擬也頗有用。
Spring Boot包含一個 @MockBean
註解,能夠用來爲 ApplicationContext
中的 bean 定義Mockito 模擬。可使用註解添加新bean或替換單個現有bean定義。註解能夠直接用於測試類、測試中的字段或 @Configuration
類和字段。在字段上使用時,建立的模擬的實例也會被注入。模擬bean在每一個測試方法以後自動重置。
若是測試使用了Spring Boot的一個測試註解(例如 @SpringBootTest
),則會自動啓用此功能。要將此功能與其餘排列一塊兒使用,必須顯式添加 listener,以下例所示:
@TestExecutionListeners(MockitoTestExecutionListener.class)
下面的示例用模擬實現替換現有的 testService
bean:
@SpringBootTest public class MockBeanTests { @Autowired private TestController testController; @MockBean private TestService testService; @Test public void test(){ given(testService.hello()).willReturn("哈哈"); String hello = testController.hello(); assertThat(hello).isEqualTo("哈哈"); } }
@MockBean
不能用於模擬在應用程序上下文刷新期間執行的bean的行爲。在執行測試時,應用程序上下文刷新已經完成,如今配置模擬行爲已經太晚了。咱們建議在這種狀況下使用 @Bean
方法來建立和配置mock。
另外,您可使用 @SpyBean
來使用 Mockito spy
以包裝任何現有的bean
CGLIB代理,如爲範圍bean建立的代理,將代理方法聲明爲 final
。這會阻止Mockito正常工做,由於它沒法在默認配置中模擬或監視 final 方法。若是想模擬或監視這樣的bean,能夠經過將 org.mockito:mockito-inline
添加到應用程序的測試依賴項中來配置 Mockito 以使用其內聯mock maker。這容許Mockito模擬和監視 final 方法。
雖然Spring的測試框架在測試之間緩存應用程序上下文,併爲共享相同配置的測試重用上下文,但使用 @MockBean
或 @SpyBean
會影響緩存鍵,這極可能會增長上下文的數量。
若是使用 @SpyBean
監視具備按名稱引用參數的 @Cacheable
方法的bean,則必須使用 -parameters
編譯應用程序。這確保了一旦bean被監視,參數名就可用於緩存基礎結構。
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序列化和反序列化是否按預期工做,可使用 @JsonTest
註解。@JsonTest
自動配置可用的受支持JSON mapper,該 mapper 能夠是如下庫之一:
ObjectMapper
,任何 @JsonComponent
bean 和 任何 Jackson Module
能夠在附錄中找到@JsonTest啓用的自動配置列表。
若是須要配置自動配置的元素,可使用 @AutoConfigureJsonTesters
註解。
Spring Boot包括基於AssertJ的輔助程序,它們與 JSONAssert 和 JsonPath 庫一塊兒工做,檢查JSON是否如預期的那樣出現。JacksonTester
、GsonTester
、JsonbTester
和 BasicJsonTester
類能夠分別用於Jackson、Gson、Jsonb和字符串。使用 @JsonTest
時,測試類上的任何輔助字段均可以 @Autowired
。如下示例顯示了Jackson的測試類:
/** @author YiFeiXi */ @JsonTest public class JsonTests { @Autowired private JacksonTester<UserInfo> json; @Test public void testSerialize() throws Exception { UserInfo u = new UserInfo(1, "張", "三"); assertThat(this.json.write(u)) .isEqualToJson("{\"id\":1,\"firstName\":\"張\",\"lastName\": \"三\"}"); } @Test public void testDeserialize() throws Exception { String content = "{\"firstName\":\"張\",\"lastName\": \"三\"}"; assertThat(this.json.parseObject(content).getFirstName()).isEqualTo("張"); } }
JSON輔助類也能夠直接用於標準單元測試。爲此,若是不使用 @JsonTest
,請在 @Before
方法中調用輔助類的 initFields
方法。
若是使用Spring Boot的基於AssertJ的輔助程序來 assert 給定JSON路徑上的數值,則可能沒法根據類型使用isEqualTo。相反,您可使用 AssertJ 的 satisfies
來 assert 該值與給定條件匹配。例如,下面的示例 assert 實際數字是偏移量0.01內接近0.15的浮點值。
assertThat(json.write(message)) .extractingJsonPathNumberValue("@.test.numberValue") .satisfies((number) -> assertThat(number.floatValue()).isCloseTo(0.15f, within(0.01f)));
要測試Spring MVC controllers 是否按預期工做,使用 @WebMvcTest
註解。@WebMvcTest
自動配置Spring MVC基礎結構,並將掃描的bean限制爲@Controller、@ControllerAdvice、@JsonComponent、Converter、GenericConverter、Filter、HandlerInterceptor、WebMVCConfiguer和HandlerMethodArgumentResolver。使用此註解時,不掃描常規@Component bean。
附錄中列出了@WebMvcTest啓用的自動配置設置。
若是須要註冊額外的組件,好比Jackson模塊,能夠在測試中使用@import導入額外的配置類。
一般,@WebMvcTest
僅限於一個控制器,並與 @MockBean
結合使用,爲所需的協做者提供模擬實現。
@WebMvcTest還自動配置MockMvc。Mock MVC提供了一種快速測試MVC控制器的強大方法,無需啓動完整的HTTP服務器。
還能夠在非@WebMvcTest(如@SpringBootTest)中使用 @AutoConfigureMockMvc
對MockMvc進行自動配置。如下示例使用MockMvc:
/** @author YiFeiXi */ @WebMvcTest(TestController.class) public class WebMvcTests { @Autowired private MockMvc mvc; @MockBean private TestService testService; @Test public void test() throws Exception { given(this.testService.hello()).willReturn("哈哈"); this.mvc .perform(get("/hello").accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andExpect(content().string("哈哈")); } }
若是須要配置自動配置的元素(例如,當應用servlet過濾器時),可使用 @AutoConfigureMockMvc
註解中的屬性。
若是使用HtmlUnit或Selenium,自動配置還提供HtmlUnit WebClient
bean 或 Selenium WebDriver
bean。如下示例使用HtmlUnit:
@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"); } }
默認狀況下,Spring Boot 將 WebDriver
bean 放置在一個特殊的「scope」中,以確保在每次測試以後驅動程序退出,並注入新的實例。若是不但願出現這種行爲,能夠將 @Scope("singleton")
添加到 WebDriver
@Bean
定義中。
由Spring Boot建立的 webDriver
做用域將替換任何用戶定義的同名做用域。若是定義了本身的webDriver做用域,則在使用 @WebMvcTest
時可能會發現它中止工做。
若是類路徑上有Spring Security ,@WebMvcTest
還將掃描 WebSecurityConfigurer
bean。可使用Spring Security的測試支持,而不是徹底禁用此類測試的安全性。有關如何使用Spring Security的 MockMvc
支持的更多詳細信息,請參見 SpringSecurity 測試操做步驟部分。
要測試Spring WebFlux controllers 是否按預期工做,可使用 @WebFluxTest
註解。@WebFluxTest 自動配置Spring WebFlux基礎結構,並將掃描的bean限制爲@Controller、@ControllerAdvice、@JsonComponent、Converter、GenericConverter、WebFilter和WebFluxConfigurer。使用@WebFluxTest註解時,不掃描常規@Component bean。
附錄中列出了 @WebFluxTest 啓用的自動配置。
若是須要註冊額外的組件,好比Jackson模塊,能夠在測試中使用@import導入額外的配置類。
一般,@WebFluxTest 僅限於一個控制器,並與@MockBean註解結合使用,爲所需的協做者提供模擬實現。
@WebFluxTest還能夠自動配置WebTestClient,這爲快速測試WebFlux controllers提供了一種強大的方法,而無需啓動完整的HTTP服務器。
還能夠在非@WebFluxTest(如@SpringBootTest)中使用@AutoConfigureWebTestClient 註解,從而自動配置web測試客戶端。如下示例顯示同時使用@WebFluxTest和WebTestClient的類:
/** * WebTestClient<br> * WebTestClient 屬於 reactive,設置spring.main.web-application-type=reactive */ @SpringBootTest(properties = "spring.main.web-application-type=reactive") @AutoConfigureWebTestClient public class MockWebTestClientTests { @Test public void test(@Autowired WebTestClient webTestClient) { webTestClient .get() .uri("/") .exchange() .expectStatus() .isOk() .expectBody(String.class) .isEqualTo(ConstantUtil.body); } }
此設置僅受WebFlux應用程序支持,由於在模擬的web應用程序中使用WebTestClient目前僅適用於WebFlux。
@WebFluxTest沒法檢測經過功能性web框架註冊的路由。要在上下文中測試 RouterFunction
bean,請考慮經過@Import或使用@SpringBootTest親自導入RouterFunction。
@WebFluxTest沒法檢測經過 SecurityWebFilterChain
類型的@Bean註冊的自定義安全配置。要將其包含在測試中,須要經過@import或使用@SpringBootTest導入註冊bean的配置。
可使用 @DataJpaTest
註解來測試JPA應用程序。默認狀況下,它掃描@Entity類並配置Spring Data JPA repositories。若是類路徑上有可用的嵌入式數據庫,它也會配置一個。常規@Component bean不會加載到ApplicationContext中。
附錄中列出了 @WebFluxTest 啓用的自動配置。
默認狀況下,Data JPA 測試是事務性的,並在每一個測試結束時回滾。有關更多詳細信息,請參閱Spring框架參考文檔中的 相關部分。若是這不是你想要的,能夠禁用測試或整個類的事務管理,以下所示:
@DataJpaTest @Transactional(propagation = Propagation.NOT_SUPPORTED) class ExampleNonTransactionalTests { }
Data JPA 測試還能夠注入一個 TestEntityManager
bean,它提供了一個專門爲測試設計的標準 JPA EntityManager
的替代。若是要在 @DataJpaTest
實例以外使用TestEntityManager
,還可使用 @AutoConfigureTestEntityManager
註解。若是須要,還可使用 JdbcTemplate
。如下示例使用了@DataJpaTest註解:
<!-- 內存嵌入式數據庫 --> <dependency> <groupId>org.apache.derby</groupId> <artifactId>derby</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
/** @author YiFeiXi */ @DataJpaTest public class DataJpaTests { @Autowired private TestEntityManager entityManager; @Autowired private UserRepository userRepository; @Test public void find() throws Exception { this.entityManager.persist(new UserInfo(1, "張", "三")); UserInfo user = this.userRepository.findByFirstName("張"); assertThat(user.getLastName()).isEqualTo("三"); } }
內存嵌入式數據庫一般能夠很好地用於測試,由於它們速度快,不須要任何安裝。可是,若是但願對真實數據庫運行測試,則可使用 @AutoConfigureTestDatabase
註解,以下例所示:
@DataJpaTest @AutoConfigureTestDatabase(replace=Replace.NONE) class ExampleRepositoryTests { // ... }
@JdbcTest
相似於 @DataJpaTest
,但只用於只須要 DataSource
而不使用 Spring Data JDBC 的測試。默認狀況下,它配置內存嵌入式數據庫和 JdbcTemplate
。常規@Component bean不會加載到ApplicationContext中。
@Slf4j @JdbcTest public class JdbcTests { @Autowired private JdbcTemplate jdbcTemplate; @Test void test() { jdbcTemplate.execute( "create table user_info(id int primary key, first_name varchar(20), last_name varchar(20))"); jdbcTemplate.execute("insert into user_info(id, first_name, last_name) values(1,'張','三')"); Map<String, Object> user = jdbcTemplate.queryForMap("select * from user_info where id = ?", 1); log.info("{} -> {}", user.get("first_name"), user.get("last_name")); assertThat(user.get("last_name")).isEqualTo("三"); } }
附錄中列出了 @WebFluxTest 啓用的自動配置。
默認狀況下,JDBC測試是事務性的,並在每一個測試結束時回滾。有關更多詳細信息,請參閱Spring框架參考文檔中的 相關部分。若是這不是您想要的,您能夠爲測試或整個類禁用事務管理,以下所示:
@JdbcTest @Transactional(propagation = Propagation.NOT_SUPPORTED) class ExampleNonTransactionalTests {}
若是您但願在真實數據庫上運行測試,可使用 @AutoConfigureTestDatabase
註解,方法與對 DataJpaTest
的方法相同。
@DataJdbcTest
相似於 @JdbcTest
,但用於使用 Spring Data JDBC repositories 的測試。默認狀況下,它配置內存嵌入式數據庫、JdbcTemplate
和 Spring Data JDBC repositories。常規@Component bean不會加載到ApplicationContext中。
附錄中列出了 @WebFluxTest 啓用的自動配置。
默認狀況下,Data JDBC 測試是事務性的,並在每一個測試結束時回滾。若是這不是您想要的,您能夠爲測試或整個測試類禁用事務管理,如JDBC示例所示。
若是但願在真實數據庫上運行測試,可使用 @AutoConfigureTestDatabase
註解,方法與對DataJpaTest的方法相同。
略
略
略
可使用@DataRedisTest
來測試Redis應用程序。默認狀況下,它掃描@RedisHash
類並配置Spring Data Redis repositories。常規@Component bean不會加載到ApplicationContext中。(有關在Spring Boot中使用Redis的更多信息,請參閱本章前面的「 Redis」。)
附錄中列出了 @WebFluxTest 啓用的自動配置。
如下示例展現了 @DataRedisTest
的使用
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
/** @author YiFeiXi */ @DataRedisTest public class DataRedisTests { @Autowired StringRedisTemplate stringRedisTemplate; @Test void test() { stringRedisTemplate.opsForValue().set("sex", "girl"); } @Test void valueHasSet() { assertThat(stringRedisTemplate.opsForValue().get("sex")).isEqualTo("girl"); } }
略
可使用 @RestClientTest
註解來測試 REST clients。默認狀況下,它自動配置Jackson、GSON和Jsonb支持,配置 RestTemplateBuilder
,並添加對 MockRestServiceServer
的支持。常規@Component bean不會加載到ApplicationContext中。
附錄中列出了 @WebFluxTest 啓用的自動配置。
應該使用 @RestClientTest
的 value
或 components
屬性指定要測試的特定bean,以下例所示:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-rest</artifactId> </dependency>
/** @author YiFeiXi */ @RestClientTest public class RestClientTests { private MockRestServiceServer server; @Autowired private RestTemplateBuilder restTemplateBuilder; private TestService testService; @BeforeEach void before() { RestTemplate restTemplate = restTemplateBuilder.build(); testService = new TestService(restTemplate); server = MockRestServiceServer.createServer(restTemplate); } @Test void test() { server.expect(requestTo("/greet")).andRespond(withSuccess("suc", MediaType.TEXT_PLAIN)); assertThat(testService.restReq()).isEqualTo("suc"); } }
可使用 @AutoConfigureRestDocs
註解在 Mock MVC、REST Assured 或WebTestClient 的測試中使用 Spring Rest Docs。它消除了Spring REST Docs 對JUnit擴展的需求。
@AutoConfigureRestDocs
可用於覆蓋默認輸出目錄(若是使用Maven,則爲`
target/generated-snippets;若是使用Gradle,則爲
build/generated-snippets`)。它還能夠用於配置出如今任何文檔化uri中的host、
scheme 和 port 。
<dependency> <groupId>org.springframework.restdocs</groupId> <artifactId>spring-restdocs-mockmvc</artifactId> <scope>test</scope> </dependency>
/** @author YiFeiXi */ @WebMvcTest(HelloWorldController.class) @AutoConfigureRestDocs(outputDir = "target/generated-snippets") public class RestDocsTests { @Autowired private MockMvc mockMvc; @Test void hello() throws Exception { this.mockMvc .perform(get("").accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andDo(document("list-users")); } }
@AutoConfigureRestDocs
自定義 MockMvc
bean 以使用 Spring REST Docs。可使用 @Autowired
注入它,並在測試中使用它,就像使用Mock MVC和Spring REST Docs 時同樣,以下例所示:
@WebMvcTest(UserController.class) @AutoConfigureRestDocs class UserDocumentationTests { @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")); } }
若是須要比 @AutoConfigureRestDocs
的屬性更多地控制Spring REST Docs配置,可使用 RestDocksMockMvcConfigurationCustomizer
bean,以下例所示:
@TestConfiguration static class CustomizationConfiguration implements RestDocsMockMvcConfigurationCustomizer { @Override public void customize(MockMvcRestDocumentationConfigurer configurer) { configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); } }
若是想使用Spring REST Docs對參數化輸出目錄的支持,能夠建立 RestDocumentationResultHandler
bean。自動配置使用此結果處理程序調用 alwaysDo
,從而使每一個 MockMvc
調用自動生成默認代碼段。如下示例顯示了被定義的RestDocumentationResultHandler
:
@TestConfiguration(proxyBeanMethods = false) static class ResultHandlerConfiguration { @Bean public RestDocumentationResultHandler restDocumentation() { return MockMvcRestDocumentation.document("{method-name}"); } }
@AutoConfigureRestDocs
也能夠與 WebTestClient
一塊兒使用。可使用 @Autowired
注入它,並在測試中使用它,就像使用 @WebFluxTest
和 Spring REST Docs 時同樣,以下例所示:
@WebFluxTest @AutoConfigureRestDocs class UsersDocumentationTests { @Autowired private WebTestClient webTestClient; @Test void listUsers() { this.webTestClient.get().uri("/").exchange().expectStatus().isOk().expectBody() .consumeWith(document("list-users")); } }
若是須要比 @AutoConfigureRestDocs
的屬性更多地控制Spring REST Docs配置,可使用 RestDocsWebTestClientConfigurationCustomizer
bean,以下例所示:
@TestConfiguration(proxyBeanMethods = false) public static class CustomizationConfiguration implements RestDocsWebTestClientConfigurationCustomizer { @Override public void customize(WebTestClientRestDocumentationConfigurer configurer) { configurer.snippets().withEncoding("UTF-8"); } }
@AutoConfigureRestDocs
使一個 RequestSpecificatioin
bean(預配置爲使用Spring REST Docs)可用於您的測試。您可使用 @Autowired
注入它,並像使用 REST-Assured 和 Spring REST Docs 時同樣在測試中使用它,以下例所示:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @AutoConfigureRestDocs class UserDocumentationTests { @Test void listUsers(@Autowired RequestSpecification documentationSpec, @LocalServerPort int port) { given(documentationSpec).filter(document("list-users")).when().port(port).get("/").then().assertThat() .statusCode(is(200)); } }
若是須要比 @AutoConfigureRestDocs
的屬性更多地控制Spring REST Docs配置,那麼可使用 RestDocsRestAssuredConfigurationCustomizer
bean,以下例所示:
@TestConfiguration(proxyBeanMethods = false) public static class CustomizationConfiguration implements RestDocsRestAssuredConfigurationCustomizer { @Override public void customize(RestAssuredRestDocumentationConfigurer configurer) { configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); } }
每一個片斷提供一個或多個 @AutoConfigure…
註解,即定義應該做爲片斷一部分包含的自動配置。能夠經過建立自定義 @AutoConfigure…
註解或向測試添加 @ImportAutoConfiguration
來添加其餘自動配置,以下例所示:
@JdbcTest @ImportAutoConfiguration(IntegrationAutoConfiguration.class) class ExampleJdbcTests {}
請確保不要使用常規的@Import 註解來導入自動配置,由於它們是由Spring Boot以特定方式處理的。
若是以合理的方式構造代碼,那麼默認狀況下,@SpringBootApplication
類將用做測試的配置。
所以,重要的是不要在應用程序的主類中添加特定於其功能特定區域的配置設置。
假設使用的是Spring Batch,而且依賴於它的自動配置。能夠按以下方式定義 @SpringBootApplication
:
@SpringBootApplication @EnableBatchProcessing public class SampleApplication { //... }
由於這個類是測試的源配置,因此任何片斷測試實際上都會嘗試啓動Spring Batch,這絕對不是您想要作的。建議的方法是將特定於區域的配置移動到與應用程序處於同一級別的單獨 @Configuration
類,以下例所示:
@Configuration(proxyBeanMethods = false) @EnableBatchProcessing public class BatchConfiguration { //... }
根據應用程序的複雜性,您能夠爲您的自定義設置一個單獨的 @Configuration 類,也能夠爲每一個域區域設置一個類。後一種方法容許您在一個測試中啓用它,若是須要,可使用@Import 註解。
測試片斷從掃描中排除 @Configuration 類。例如,對於 @WebMvcTest
,如下配置不會在測試片斷加載的應用程序上下文中包含給定的 WebMvcConfigurer
bean:
@Configuration public class WebConfiguration { @Bean public WebMvcConfigurer testConfigurer() { return new WebMvcConfigurer() { //... }; } }
可是,下面的配置將致使測試片斷加載自定義 WebMvcConfiguer
。
@Component public class TestWebMvcConfigurer implements WebMvcConfigurer { //... }
另外一個混亂的來源是類路徑掃描。假設,當您以合理的方式構造代碼時,您須要掃描另外一個包。您的應用程序可能相似於如下代碼:
@SpringBootApplication @ComponentScan({"com.example.app", "org.acme.another"}) public class SampleApplication{ //... }
這樣作有效地覆蓋了默認的組件掃描指令,其反作用是掃描這兩個包,而不考慮您選擇的片斷。例如,@DataJpaTest
彷佛忽然掃描應用程序的組件和用戶配置。一樣,將自定義指令移動到單獨的類是解決此問題的好方法。
若是這不適合,能夠在測試層次結構中的某個位置建立@SpringBootConfiguration,以便使用它。或者,能夠爲測試指定一個 source,這將禁用查找默認源的行爲。
若是但願使用Spock測試一個Spring Boot 應用,那麼應該在應用程序的構建中添加對Spock的 spock-spring
模塊的依賴。spock-spring
將Spring的測試框架集成到 Spock 中。建議使用Spock 1.2或更高版本,以從Spock的Spring框架和SpringBoot集成的許多改進中獲益。有關更多詳細信息,請參閱Spock的Spring模塊的文檔。
當測試應用程序類打包爲spring boot的一部分時,一些在測試應用程序一般是有用的。
ConfigFileApplicationContextInitializer
是一個 ApplicationContextInitializer
,能夠將其應用於測試加載 Spring Boot application.properties
文件。當不須要@SpringBootTest提供的全套功能時,可使用它,以下例所示:
@ContextConfiguration(classes = Config.class, initializers = ConfigFileApplicationContextInitializer.class)
單獨使用 ConfigFileApplicationContextInitializer
不支持 @Value(${…})
注入。它的惟一工做是確保 application.properties
文件加載到Spring的環境中。對於 @Value
支持,須要另外配置 PropertySourcesPlaceholderConfigurer
或使用 @SpringBootTest
,後者會自動配置一個。
/** @author YiFeiXi */ @Configuration public class UserConfig { @Bean public UserInfo defaultUserInfo() { return new UserInfo(1, "張", "三"); } }
/** @author YiFeiXi */ @ExtendWith(SpringExtension.class) @ContextConfiguration( classes = UserConfig.class, initializers = ConfigFileApplicationContextInitializer.class) public class ConfigFileTests { @Autowired private UserInfo userInfo; @Test void test() { assertThat(userInfo.getFirstName()).isEqualTo("張"); assertThat(userInfo.getLastName()).isEqualTo("三"); } }
TestPropertyValues
容許快速將屬性添加到 ConfigurableEnvironment
或ConfigurableApplicationContext
。可使用 key=value
字符串調用它,以下所示:
/** @author YiFeiXi */ @SpringBootTest public class TestPropertyValueTests { @Autowired private ConfigurableEnvironment environment; @Test void test() { TestPropertyValues.of("org=spring", "name=boot").applyTo(environment); String org = environment.getProperty("org"); String name = environment.getProperty("name"); assertThat(org).isEqualTo("spring"); assertThat(name).isEqualTo("boot"); } }
OutputCapture
是一個JUnit擴展,可用於捕獲 System.out
和 System.err
輸出。添加 @ExtendWith(OutputCaptureExtension.class)
並將 CapturedOutput
做爲參數注入測試類構造函數或測試方法來使用,以下所示:
/** * 輸出捕捉 * * @author YiFeiXi */ @ExtendWith(OutputCaptureExtension.class) public class OutputCaptureTests { @Test void test(CapturedOutput output) { System.out.print("hello world!"); assertThat(output).isEqualTo("hello world!"); } }
TestRestTemplate
是Spring的 RestTemplate
的一個方便的替代品,它在集成測試中很是有用。您能夠獲得一個普通模板或一個發送基本HTTP身份驗證的模板(帶有用戶名和密碼)。在這兩種狀況下,模板都以測試友好的方式運行,不會在服務器端錯誤上引起異常。
Spring Framework 5.0提供了一個新的WebTestClient,可用於WebFlux集成測試以及WebFlux和MVC端到端測試。它爲斷言提供了一個流暢的API,與 TestRestTemplate 不一樣。
建議使用ApacheHTTP客戶端(4.3.2或更高版本),但不是強制的。若是在類路徑中有,TestRestTemplate 將經過適當配置 client 來響應。若是您確實使用了Apache的HTTP客戶端,則會啓用一些附加的測試友好功能:
TestRestTemplate
能夠在集成測試中直接實例化,以下例所示:
/** @author YiFeiXi */ @SpringBootTest(webEnvironment = WebEnvironment.NONE) public class RestTemplateTests { @Test void test() { TestRestTemplate template = new TestRestTemplate(); String responseBody = template.getForObject("http://127.0.0.1:8080/", String.class); assertThat(responseBody).isEqualTo("Hello World!"); } }
或者,若是將 @SpringBootTest
註解與 WebEnvironment.RANDOM_PORT
或 WebEnvironment.DEFINED_PORT
一塊兒使用,則能夠插入徹底配置的 TestRestTemplate
並開始使用它。若是須要,能夠經過 RestTemplateBuilder
bean應用其餘定製。任何未指定 host 和 port 的URL都會自動鏈接到嵌入式服務器,以下例所示:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) class SampleWebClientTests { @Autowired private TestRestTemplate template; @Test void testRequest() { HttpHeaders headers = this.template.getForEntity("/example", String.class).getHeaders(); assertThat(headers.getLocation()).hasHost("other.example.com"); } @TestConfiguration(proxyBeanMethods = false) static class Config { @Bean RestTemplateBuilder restTemplateBuilder() { return new RestTemplateBuilder().setConnectTimeout(Duration.ofSeconds(1)) .setReadTimeout(Duration.ofSeconds(1)); } } }
官方文檔
代碼示例
公衆號:逸飛兮(專一於 Java 領域知識的深刻學習,從源碼到原理,系統有序的學習)