如何在Spring Boot中實現整合測試?
整合測試可以驗證程式碼庫中的整個呼叫路徑,不幸的是,這種測試方法很難在Spring Boot應用程式中使用。本案例探索如何克服這種困難:
我們將使用一個簡單的REST服務示例,它具有我們連線使用的單個SQL資料庫依賴項spring-boot-starter-data-jpa,一個預定義的Spring元件包,可以透過JPA輕鬆訪問SQL資料,以及h2一個用Java編寫的免費SQL資料庫。
案例原始碼這裡
下面是它包含的元件,所有示例程式碼都是使用Java 10編寫的:
SpringBootApplication class SlalomiteApplication @RestController class SlalomiteController // depends on SlalomiteService @Service class SlalomiteService // depends on SlalomiteRepository interface SlalomiteRepository extends CrudRepository<Slalomite, Long> |
問題
看看CrudRepository儲存庫,雖然程式碼非常簡單,但是如何模擬Spring提供的元件並不明顯。這使得很難驗證依賴於此儲存庫類的應用程式邏輯是否正確。
import org.springframework.data.repository.CrudRepository; public interface SlalomiteRepository extends CrudRepository<Slalomite, Long> { } |
使用Spring Boot @DataJpaTest和@SpringBootTest(webEnvironment = ...)註釋,可以實現模擬資料庫併為此應用程式編寫整合測試。該整合測試看起來像這樣:
@RunWith(SpringRunner.class) @SpringBootTest(classes = SlalomiteApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @DataJpaTest public class SlalomiteIntegrationTestBroken { @Autowired private TestRestTemplate restTemplate; @Autowired private TestEntityManager entityManager; @Test public void getSlalomites_ShouldReturnAdam() { var slalomite = new Slalomite("Adam", Date.from(Instant.now())); this.entityManager.persist(slalomite); var response = restTemplate.getForEntity("/api/v1/slalomites", String.class); assertTrue(response.getBody().contains("Adam")); } |
}
透過結合Spring教程,Spring指南和許多部落格中的想法,這看起來可能是正確的,但不幸的是,在執行它時會遇到以下異常:
java.lang.IllegalStateException: Failed to load ApplicationContext... Caused by: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
這裡的問題是@DataJpaTest的。來自javadoc解釋:
使用此批註將禁用完全自動配置,而只應用與JPA測試相關的配置。
問題發生原因:@DataJpaTest只啟用執行持久層所需的元件並禁用所有其他元件。這包括Spring用於啟動servlet容器的元件。由於@SpringBootTest嘗試啟動servlet容器,因此在無法找到啟動servlet所需的bean時會產生上述異常。
解決方案
解決方案非常簡單,實際上在同一個@DataJpaTestjavadoc中暗示過,即使它沒有在Spring文件或線上的許多地方提到過:
如果您要載入完整的應用程式配置,且使用了嵌入式資料庫,則應考慮將@SpringBootTest與@AutoConfigureTestDatabase結合使用而不是使用此註釋。
使用@AutoConfigureTestDatabase 時,我們沒有提供@DataJpaTest提供的許多便利,例如,前面的例子中使用的TestEntityManager是不可用的;我們也沒有得到事務測試的好處,這意味著我們必須更加謹慎地清理自己。
但是,還是保留了關鍵優勢 - 在執行整合測試時,應用程式將連線到Spring建立的記憶體資料庫,而不是我們的實際資料庫例項。這使我們能夠從資料庫中讀取和寫入,而無需擔心預先存在的資料或擔心建立會影響其他應用程式或使用者的資料,從而使測試更安全地作為CI / CD管道的一部分執行並且更具可重複性。
由於我們無法訪問TestEntityManager此處,因此我們需要直接編寫SQL來設定和清理資料庫,或者我們需要在實際呼叫控制器方法之前利用我們的SlalomiteRepository bean來執行寫操作。
這裡演示我們將使用第二個選項。雖然它不像直接編寫SQL那樣具有“黑盒子”的方法,但它更簡單,更不易碎。新的、透過測試的程式碼如下:
@RunWith(SpringRunner.class) @SpringBootTest(classes = SlalomiteApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureTestDatabase public class SlalomiteIntegrationTest { @Autowired private TestRestTemplate restTemplate; @Autowired private SlalomiteRepository repo; @After public void cleanup() { repo.deleteAll(); } @Test public void getSlalomites_ShouldReturnAdam() { var slalomite = new Slalomite("Adam", Date.from(Instant.now())); repo.save(slalomite); var response = restTemplate.getForEntity("/api/v1/slalomites", String.class); assertTrue(response.getBody().contains("Adam")); } } |
請注意新增cleanup方法。如果在每次測試後未清除對資料的更改,則最終會出現意外故障,因為不滿足給定測試的前提條件。在實踐中,由於您的測試執行員選擇您的單元測試,這些失敗可能會隨機結束。
相關文章
- spring boot 整合測試Spring Boot
- Mokito 單元測試與 Spring-Boot 整合測試Springboot
- Spring Boot 中測試 CORSSpring BootCORS
- 使用Kotlin (Spring Boot) + MockMVC + DatabaseRider輕鬆實現API整合測試KotlinSpring BootMockMVCDatabaseIDEAPI
- 八、Spring Boot整合Spring Security之前後分離認證最佳實現對接測試Spring Boot
- Spring Boot單元和整合測試概述 | rieckpilSpring BootKPI
- Spring、Spring Boot和TestNG測試指南 – 整合測試中用Docker建立資料庫Spring BootDocker資料庫
- 如何在Spring Boot專案中整合微信支付V3Spring Boot
- Spring Boot整合MyBatis實現通用MapperSpring BootMyBatisAPP
- Spring Boot 整合 Redis 實現快取操作Spring BootRedis快取
- 每日一學:如何在 Spring Boot 整合 RabbitMQ ?Spring BootMQ
- Spring Boot(七):spring boot測試介紹Spring Boot
- Spring Boot整合Hystrix實現服務容錯Spring Boot
- 測試開發專題:如何在spring-boot中進行引數校驗Springboot
- Spring Boot中實現Thymeleaf通知Spring Boot
- Spring Boot(十二):Spring Boot 如何測試打包部署Spring Boot
- Spring Boot 整合 Elasticsearch 實戰Spring BootElasticsearch
- Spring Boot整合Spring Cloud Task實現批處理操作Spring BootCloud
- Spring Boot 單元測試Spring Boot
- Spring、Spring Boot和TestNG測試指南 – 共享測試配置Spring Boot
- 如何在測試環境中實現 API 模擬呼叫API
- Spring Boot 整合 Flyway 實現資料庫版本控制Spring Boot資料庫
- 如何實現Spring Boot和Quartz整合? - Nguyen Phuc HaiSpring BootquartzAI
- spring boot使用Jedis整合Redis實現快取(AOP)Spring BootRedis快取
- 使用Spring Boot實現資料庫整合配置案例Spring Boot資料庫
- Spring Boot中整合機器學習簡介Spring Boot機器學習
- Spring Boot整合Redis實戰操作Spring BootRedis
- 如何在spring環境中做單元測試Spring
- Spring+ActiveMQ整合測試SpringMQ
- spring 整合dubbo 測試搭建Spring
- 021-Spring Boot 測試Spring Boot
- Spring Boot 整合 Sa-Token 實現登入認證Spring Boot
- Spring Boot整合Postgres實現輕量級全文搜尋Spring Boot
- 使用Spring Boot、Kotlin和OpenFeign實現型別安全API測試Spring BootKotlin型別API
- Spring boot webflux 中實現 RequestContextHolderSpring BootWebUXContext
- Java中的單元測試與整合測試最佳實踐Java
- Spring Boot 2.0(八):Spring Boot 整合 MemcachedSpring Boot
- Spring Boot(十八):使用 Spring Boot 整合 FastDFSSpring BootAST