開發/產品平價旨在縮小開發和生產環境之間的差距。本文針對工具差距,特別是在使用 Spring Testcontainers 進行整合測試方面,作為使開發和生產盡可能相似的一種方式。
在進行涉及資料庫的整合測試時,我們必須仔細管理所有的CRUD操作。這在集中式資料庫環境中至關重要,在這種環境中,諸如 TestDeleteUserByID_ShouldReturnOk() 之類的測試可能會「意外地」決定刪除自 2015 年以來一直與我們合作的最忠實客戶的帳戶? ♂️
為了減輕此類風險,我們可以考慮資料庫事務等解決方案來隔離測試資料。例如,測試可以啟動一個事務來修改數據,然後在最後回滾,從而使資料庫保持原始狀態。
但是,這引發了一個關鍵問題:測驗的內容是什麼?
如果隔離失敗且程式碼執行的變更未回滾,導致資料外洩到生產環境怎麼辦?這種情況下的潛在損害是巨大的。
另外,使用 H2DB 等記憶體資料庫進行獨立測試也帶來了一些挑戰。即使設定很容易,H2DB 與 RDBMS 不同,因此開發環境和生產環境之間的測試很可能會產生不同的結果,因此我們不能相信這些結果。
https://stackoverflow.com/questions/62778900/syntax-error-h2-database-in-postgresql-compatibility
下一個問題較少的解決方案是克隆資料庫,透過類似生產的環境提供風險較小的方法。然而,這種方法也有其限制。鑑於 ORM 自動建立和設定生產資料庫模式,我們需要考慮如何保持克隆的開發資料庫同步。
「Testcontainers 是一個支援 JUnit 測試的 Java 庫,提供通用資料庫、Selenium Web 瀏覽器或任何其他可以在 Docker 容器中運行的東西的輕量級一次性實例。」
它最初是為 Java 開發的,後來擴展到支援其他語言,如 Go、Rust 和 .NET。
Testcontainers 的主要思想是提供一個可從 IDE 運行的按需基礎設施,無需模擬或使用記憶體服務即可進行測試,並且可以自動清理。
我們可以透過三個步驟來實現這一目標:
Testcontainers 庫文檔
在整合測試的基底類別ApplicationIntegrationTests中,我們定義了一個靜態的PostgreSQLContainer。此容器用於從此類派生的所有測試實例。
@Testcontainers 註解可以發現所有用 @Container 註解的字段,管理其容器生命週期方法,並啟動容器。
@DynamicPropertySource 註解讓我們動態地將屬性注入到我們的測試環境中。
@Testcontainers @ActiveProfiles("test") public abstract class ApplicationIntegrationTests { @Container protected static PostgreSQLContainer<?> postgres=new PostgreSQLContainer<>("postgres:17.2-alpine") .withDatabaseName("testcontainersproject") .withUsername("root") .withPassword("root"); @DynamicPropertySource static void initialize(DynamicPropertyRegistry registry) { registry.add("spring.datasource.url",postgres::getJdbcUrl); registry.add("spring.datasource.username",postgres::getUsername); registry.add("spring.datasource.password",postgres::getPassword); } }
或者,我們可以跳過使用@Testcontainers和@Container,而是直接使用@BeforeAll和@AfterAll來管理容器生命週期。這種方法可以更好地控制容器啟動和停止的時間和方式
@BeforeAll public static void runContainer(){ postgres.start(); } @AfterAll static void stopContainers() { postgres.stop(); }
在@AfterAll回呼方法中,我們明確停止Postgres容器。但是,即使我們沒有明確停止容器,Testcontainers 也會在測試運行結束時自動清理並關閉容器。
現在我們可以透過擴充 ApplicationIntegrationTests 來建立整合測試,如下所示。
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureMockMvc public class CategoryControllerTest extends ApplicationIntegrationTests { private static final String CATEGORY_ENDPOINT="/categories"; @Autowired private MockMvc mockMvc; @Autowired private CategoryRepository categoryRepository; @Test void TestGetAllCategories_ShouldReturnOk() throws Exception { List<Category> categories = List.of( new Category("Electronics", "All kinds of electronic gadgets from smartphones to laptops"), new Category("Books", "A wide range of books from novels to educational textbooks") ); categoryRepository.saveAll(categories); MvcResult mvcResult=mockMvc.perform( get(CATEGORY_ENDPOINT). contentType(MediaType.APPLICATION_JSON) ) .andExpect(status().isOk()) .andReturn(); var response=mvcResult.getResponse().getContentAsString(); assertNotNull(response); assertFalse(response.isEmpty()); } }
以上是開發/產品奇偶校驗:Spring Boot Testcontainers的詳細內容。更多資訊請關注PHP中文網其他相關文章!