javascript
不要在 Spring Boot 集成测试中使用 @Transactional
在測試運行時,測試類中 @Transactional 注解,會導致測試中 Entity 數據的操作都是在內存中完成,最終并不會進行 commit 操作,也就是不會將 Entity 數據進行持久化操作,從而導致測試的行為和真實應用的行為不一致。
事務管理在應用開發中是種不可或缺的設計,它是數據庫持久化處理的一種標準。我們知道,應用程序開發離不開對數據的CRUD(增刪改查),事務的ACID性可以更好保證數據的完整性,保證相關數據的同生共死。單個事務生命周期主要分為三個階段,BEGIN TRANSACTION -> COMMIT TRANSACTION -> ROLLBACK TRANSACTION。
Spring Boot事務的使用分為命令式和聲明式常用的方式是聲明式注解(@Transactional)。事務管理既可以在應用層使用,也可以在測試中使用。
為了保證測試之間的相互獨立,測試之間數據不會被相互影響。也許你寫過這樣的測試:
@SpringBootTest @ActiveProfiles("test") @Transactional public class UserControllerTest { }@Transactional 通過將數據持久化操作截斷,來解決測試之間相互對立,數據相互不影響的問題。然而這樣方式會有副作用,就是數據持久化的過程不再真實,沒有了commit的過程。從而會導致:
- 無法保證 Entity 之間關聯關系,唯一索引和主外鍵關聯的準確性
- 無法保證 Entity 創建時間、更新時間和版本化(樂觀鎖)的賦值邏輯的準確性
- 無法保證 Entity 中有 @Transient 注解的屬性的賦值邏輯的準確性
- 測試的數據不是真實場景存在的問題
- 測試中,單個事務中的準備數據,無法在多線程中共享。
......
然后 Spring 在測試問題域中引入事務管理初衷是什么?為了解決什么問題才需要將它引入?官方文檔介紹 Transaction management
按照官方文檔意思,為了解決測試運行時,程序訪問真實的數據庫,改變數據的狀態,從而影響到后續的測試問題。
其實這里應該批判性思維一下,為什么測試運行時,需要訪問真實的數據庫?為什么測試之間的數據會相互影響?
對于每個測試來說,每次運行前都應該有干凈的上下文,或者說獨立的上下文,有數據清理和準備的過程,測試與測試之間相互隔離。也就是說,為什么測試不能用內存數據庫或者嵌入式數據庫?為什么不是每個測試運行前清理一下數據庫中的數據,保證測試用例運行前的一方凈土,不被上個測試數據影響?
答案當然是,可以!!!
寫在最后
如何做?實現一個 TruncateDatabaseService,只刪除表的數據,不刪除表的結果。 在測試基類的@BeforeEach,執行 truncate。源碼Truncate Database:
TruncateDatabaseBasicOnHibernateServiceTruncateDatabaseBasicOnMybatisService 原文鏈接
總結
以上是生活随笔為你收集整理的不要在 Spring Boot 集成测试中使用 @Transactional的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FZU 1901 Period II(K
- 下一篇: Vue学习笔记第一天--es6