不要在 Spring Boot 集成測試中使用 @Transactional

在測試運行時,測試類中 @Transactional 註解,會致使測試中 Entity 數據的操做都是在內存中完成,最終並不會進行 commit 操做,也就是不會將 Entity 數據進行持久化操做,從而致使測試的行爲和真實應用的行爲不一致。html

事務管理在應用開發中是種不可或缺的設計,它是數據庫持久化處理的一種標準。咱們知道,應用程序開發離不開對數據的CRUD(增刪改查),事務的ACID能夠更好保證數據的完整性,保證相關數據的同生共死。單個事務生命週期主要分爲三個階段,BEGIN TRANSACTION -> COMMIT TRANSACTION -> ROLLBACK TRANSACTIONjava

Spring Boot事務的使用分爲命令式聲明式經常使用的方式是聲明式註解(@Transactional)。事務管理既能夠在應用層使用,也能夠在測試中使用。git

爲了保證測試之間的相互獨立,測試之間數據不會被相互影響。也許你寫過這樣的測試:github

@SpringBootTest
@ActiveProfiles("test")
@Transactional
public class UserControllerTest { }

@Transactional 經過將數據持久化操做截斷,來解決測試之間相互對立,數據相互不影響的問題。然而這樣方式會有反作用,就是數據持久化的過程再也不真實,沒有了commit的過程。從而會致使:spring

  • 沒法保證 Entity 之間關聯關係,惟一索引和主外鍵關聯的準確性
  • 沒法保證 Entity 建立時間、更新時間和版本化(樂觀鎖)的賦值邏輯的準確性
  • 沒法保證 Entity 中有 @Transient 註解的屬性的賦值邏輯的準確性
  • 測試的數據不是真實場景存在的問題
  • 測試中,單個事務中的準備數據,沒法在多線程中共享。

......數據庫

而後 Spring 在測試問題域中引入事務管理初衷是什麼?爲了解決什麼問題才須要將它引入?官方文檔介紹 Transaction management多線程

圖片描述

按照官方文檔意思,爲了解決測試運行時,程序訪問真實的數據庫,改變數據的狀態,從而影響到後續的測試問題。測試

其實這裏應該批判性思惟一下,爲何測試運行時,須要訪問真實的數據庫?爲何測試之間的數據會相互影響?
對於每一個測試來講,每次運行前都應該有乾淨的上下文,或者說獨立的上下文,有數據清理和準備的過程,測試與測試之間相互隔離。也就是說,爲何測試不能用內存數據庫或者嵌入式數據庫?爲何不是每一個測試運行前清理一下數據庫中的數據,保證測試用例運行前的一方淨土,不被上個測試數據影響?spa

答案固然是,能夠!!!線程

寫在最後

如何作?實現一個 TruncateDatabaseService,只刪除表的數據,不刪除表的結果。 在測試基類的@BeforeEach,執行 truncate。源碼Truncate Database

TruncateDatabaseBasicOnHibernateService
TruncateDatabaseBasicOnMybatisService
原文連接
相關文章
相關標籤/搜索