介紹
開發(fā)/產(chǎn)品平價旨在縮小開發(fā)和生產(chǎn)環(huán)境之間的差距。本文針對工具差距,特別是在使用 Spring Testcontainers 進行集成測試方面,作為使開發(fā)和生產(chǎn)盡可能相似的一種方式。
在進行涉及數(shù)據(jù)庫的集成測試時,我們必須仔細管理所有的CRUD操作。這在集中式數(shù)據(jù)庫環(huán)境中至關(guān)重要,在這種環(huán)境中,諸如 TestDeleteUserByID_ShouldReturnOk() 之類的測試可能會“意外地”決定刪除自 2015 年以來一直與我們合作的最忠實客戶的帳戶??♂?
為了減輕此類風險,我們可以考慮數(shù)據(jù)庫事務(wù)等解決方案來隔離測試數(shù)據(jù)。例如,測試可以啟動一個事務(wù)來修改數(shù)據(jù),然后在最后回滾,從而使數(shù)據(jù)庫保持原始狀態(tài)。
但是,這引發(fā)了一個關(guān)鍵問題:測試的內(nèi)容是什么?
如果隔離失敗并且代碼執(zhí)行的更改未回滾,導(dǎo)致數(shù)據(jù)泄漏到生產(chǎn)環(huán)境怎么辦?這種情況下的潛在損害是巨大的。
另外,使用 H2DB 等內(nèi)存數(shù)據(jù)庫進行獨立測試也帶來了一些挑戰(zhàn)。即使設(shè)置很容易,H2DB 與 RDBMS 不同,因此開發(fā)環(huán)境和生產(chǎn)環(huán)境之間的測試很可能會產(chǎn)生不同的結(jié)果,因此我們不能相信這些結(jié)果。
https://stackoverflow.com/questions/62778900/syntax-error-h2-database-in-postgresql-compatibility
下一個問題較少的解決方案是克隆數(shù)據(jù)庫,通過類似生產(chǎn)的環(huán)境提供風險較小的方法。然而,這種方法也有其局限性。鑒于 ORM 自動創(chuàng)建和設(shè)置生產(chǎn)數(shù)據(jù)庫模式,我們需要考慮如何保持克隆的開發(fā)數(shù)據(jù)庫同步。
測試您可以容器化的任何內(nèi)容:數(shù)據(jù)庫、消息代理等等
“Testcontainers 是一個支持 JUnit 測試的 Java 庫,提供通用數(shù)據(jù)庫、Selenium Web 瀏覽器或任何其他可以在 Docker 容器中運行的東西的輕量級一次性實例?!?br>
它最初是為 Java 開發(fā)的,后來擴展到支持其他語言,如 Go、Rust 和 .NET。
Testcontainers 的主要思想是提供一個可從 IDE 運行的按需基礎(chǔ)設(shè)施,無需模擬或使用內(nèi)存服務(wù)即可進行測試,并且可以自動清理。
我們可以通過三個步驟來實現(xiàn)這一目標:
- 啟動所需的服務(wù)并通過設(shè)置 Docker 容器來準備基礎(chǔ)設(shè)施,并將您的應(yīng)用程序配置為使用此設(shè)置作為測試基礎(chǔ)設(shè)施。
- 在 Docker 化基礎(chǔ)設(shè)施上運行測試。
- 測試結(jié)束后自動清理docker化基礎(chǔ)設(shè)施
Testcontainers 庫文檔
Spring Boot 測試容器實現(xiàn)
在集成測試的基類ApplicationIntegrationTests中,我們定義了一個靜態(tài)的PostgreSQLContainer。此容器用于從此類派生的所有測試實例。
@Testcontainers 注解可以發(fā)現(xiàn)所有用 @Container 注解的字段,管理其容器生命周期方法,并啟動容器。
- 聲明為靜態(tài)字段的容器在測試方法之間共享。它們僅在執(zhí)行任何測試方法之前啟動一次,并在執(zhí)行最后一個測試方法后停止。
- 聲明為實例字段的容器會針對每個測試方法啟動和停止。
@DynamicPropertySource 注解允許我們動態(tài)地將屬性注入到我們的測試環(huán)境中。
@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回調(diào)方法中,我們顯式停止Postgres容器。但是,即使我們沒有顯式停止容器,Testcontainers 也會在測試運行結(jié)束時自動清理并關(guān)閉容器。
現(xiàn)在我們可以通過擴展 ApplicationIntegrationTests 來創(chuàng)建集成測試,如下所示。
@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()); } }
以上是開發(fā)/產(chǎn)品奇偶校驗:Spring Boot Testcontainers的詳細內(nèi)容。更多信息請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費脫衣服圖片

Undresser.AI Undress
人工智能驅(qū)動的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover
用于從照片中去除衣服的在線人工智能工具。

Clothoff.io
AI脫衣機

Video Face Swap
使用我們完全免費的人工智能換臉工具輕松在任何視頻中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的代碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
功能強大的PHP集成開發(fā)環(huán)境

Dreamweaver CS6
視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版
神級代碼編輯軟件(SublimeText3)

Java中的枚舉(enum)是一種特殊的類,用于表示固定數(shù)量的常量值。1.使用enum關(guān)鍵字定義;2.每個枚舉值都是該枚舉類型的公共靜態(tài)最終實例;3.可以包含字段、構(gòu)造函數(shù)和方法,為每個常量添加行為;4.可在switch語句中使用,支持直接比較,并提供name()、ordinal()、values()和valueOf()等內(nèi)置方法;5.枚舉可提升代碼的類型安全性、可讀性和靈活性,適用于狀態(tài)碼、顏色或星期等有限集合場景。

接口隔離原則(ISP)要求不強制客戶端依賴未使用的接口。其核心是用多個小而精的接口替代大而全的接口。違反該原則的表現(xiàn)包括:類實現(xiàn)接口時拋出未實現(xiàn)異常、存在大量無效方法實現(xiàn)、無關(guān)功能被強行歸入同一接口。應(yīng)用方法包括:按常用方法組劃分接口、依據(jù)客戶端使用拆分接口、必要時使用組合替代多接口實現(xiàn)。例如將包含打印、掃描、傳真方法的Machine接口拆分為Printer、Scanner和FaxMachine。在小型項目或所有客戶端均使用全部方法時可適當放寬規(guī)則。

Java支持異步編程的方式包括使用CompletableFuture、響應(yīng)式流(如ProjectReactor)以及Java19 中的虛擬線程。1.CompletableFuture通過鏈式調(diào)用提升代碼可讀性和維護性,支持任務(wù)編排和異常處理;2.ProjectReactor提供Mono和Flux類型實現(xiàn)響應(yīng)式編程,具備背壓機制和豐富的操作符;3.虛擬線程減少并發(fā)成本,適用于I/O密集型任務(wù),與傳統(tǒng)平臺線程相比更輕量且易于擴展。每種方式均有適用場景,應(yīng)根據(jù)需求選擇合適工具并避免混合模型以保持簡潔性

Callable和Runnable在Java中主要有三點區(qū)別。第一,Callable的call()方法可以返回結(jié)果,適合需要返回值的任務(wù),如Callable;而Runnable的run()方法無返回值,適用于無需返回的任務(wù),如日志記錄。第二,Callable允許拋出checked異常,便于錯誤傳遞;而Runnable必須在內(nèi)部處理異常。第三,Runnable可直接傳給Thread或ExecutorService,而Callable只能提交給ExecutorService,并返回Future對象以

在Java中,枚舉(enum)適合表示固定常量集合,最佳實踐包括:1.用enum表示固定狀態(tài)或選項,提升類型安全和可讀性;2.為枚舉添加屬性和方法以增強靈活性,如定義字段、構(gòu)造函數(shù)、輔助方法等;3.使用EnumMap和EnumSet提高性能和類型安全性,因其基于數(shù)組實現(xiàn)更高效;4.避免濫用enum,如動態(tài)值、頻繁變更或復(fù)雜邏輯場景應(yīng)使用其他方式替代。正確使用enum能提升代碼質(zhì)量并減少錯誤,但需注意其適用邊界。

JavaNIO是Java1.4引入的新型IOAPI,1)面向緩沖區(qū)和通道,2)包含Buffer、Channel和Selector核心組件,3)支持非阻塞模式,4)相比傳統(tǒng)IO更高效處理并發(fā)連接。其優(yōu)勢體現(xiàn)在:1)非阻塞IO減少線程開銷,2)Buffer提升數(shù)據(jù)傳輸效率,3)Selector實現(xiàn)多路復(fù)用,4)內(nèi)存映射加快文件讀寫。使用時需注意:1)Buffer的flip/clear操作易混淆,2)非阻塞下需手動處理不完整數(shù)據(jù),3)Selector注冊需及時取消,4)NIO并非適用于所有場景。

Javaprovidesmultiplesynchronizationtoolsforthreadsafety.1.synchronizedblocksensuremutualexclusionbylockingmethodsorspecificcodesections.2.ReentrantLockoffersadvancedcontrol,includingtryLockandfairnesspolicies.3.Conditionvariablesallowthreadstowaitfor

Java的類加載機制通過ClassLoader實現(xiàn),其核心工作流程分為加載、鏈接和初始化三個階段。加載階段由ClassLoader動態(tài)讀取類的字節(jié)碼并創(chuàng)建Class對象;鏈接包括驗證類的正確性、為靜態(tài)變量分配內(nèi)存及解析符號引用;初始化則執(zhí)行靜態(tài)代碼塊和靜態(tài)變量賦值。類加載采用雙親委派模型,優(yōu)先委托父類加載器查找類,依次嘗試Bootstrap、Extension和ApplicationClassLoader,確保核心類庫安全且避免重復(fù)加載。開發(fā)者可自定義ClassLoader,如URLClassL
