欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot單元測(cè)試之?dāng)?shù)據(jù)隔離詳解

 更新時(shí)間:2023年08月23日 11:36:17   作者:噠噠噠打代碼  
我們?cè)趯?xiě)單元測(cè)試時(shí),有一個(gè)比較重要的要求是可以重復(fù)運(yùn)行, 那么這樣就會(huì)有一個(gè)比較麻煩的問(wèn)題:數(shù)據(jù)污染,所以本文為大家整理了兩個(gè)數(shù)據(jù)隔離的方式,希望對(duì)大家有所幫助

前言

我們?cè)趯?xiě)單元測(cè)試時(shí),有一個(gè)比較重要的要求是可以重復(fù)運(yùn)行,即只要外部參數(shù)不變,那么一定可以獲取確定的結(jié)果。 那么這樣就會(huì)有一個(gè)比較麻煩的問(wèn)題:數(shù)據(jù)污染。 以數(shù)據(jù)庫(kù)操作為例,對(duì)于一些查詢類的測(cè)試用例倒還好,因?yàn)橹灰WC數(shù)據(jù)存在,那么查詢操作天生就是冪等的,不管你查多少次,數(shù)據(jù)都不會(huì)變。 但是對(duì)于寫(xiě)入操作就不友好了,每一次運(yùn)行單元測(cè)試,都會(huì)在數(shù)據(jù)庫(kù)中產(chǎn)生新的數(shù)據(jù),可能在第一次運(yùn)行時(shí)正常,第二次運(yùn)行時(shí)就由于數(shù)據(jù)沖突導(dǎo)致失敗。那對(duì)于這種情況,我們應(yīng)該如何去解決?

下面分享兩種我使用過(guò)的數(shù)據(jù)隔離的方式,供大家參考。

數(shù)據(jù)隔離

測(cè)試事務(wù)

這種方式比較常規(guī),適用場(chǎng)景也比較廣泛,即我們?cè)跍y(cè)試用例中,通過(guò)@Transactional注解開(kāi)始事務(wù),此時(shí)整個(gè)單元測(cè)試方法會(huì)被包裹在事務(wù)中,并且會(huì)在運(yùn)行結(jié)束后,自動(dòng)回滾。

我們可以在類或方法上添加@Transactional注解

/**
 * 在類上添加 @Transactional 注解,可以讓測(cè)試方法在執(zhí)行完畢后自動(dòng)回滾,不會(huì)對(duì)數(shù)據(jù)庫(kù)造成影響。
 * 如果在方法上添加,則只影響對(duì)應(yīng)的方法
 */
@SpringBootTest
@Transactional
public class TransactionalTests extends AbstractTransactionalJUnit4SpringContextTests {
    @Resource
    private UserService userService;
    @Test
    void createRecord() {
        User user = userService.createUser();
        //to other things
    }
}

或者繼承AbstractTransactionalJUnit4SpringContextTests

/**
 * 在類上添加 @Transactional 注解,可以讓測(cè)試方法在執(zhí)行完畢后自動(dòng)回滾,不會(huì)對(duì)數(shù)據(jù)庫(kù)造成影響。
 * 如果在方法上添加,則只影響對(duì)應(yīng)的方法
 */
@SpringBootTest
public class TransactionalTests extends AbstractTransactionalJUnit4SpringContextTests {
    @Resource
    private UserService userService;
    @Test
    void createRecord() {
        User user = userService.createUser();
        //to other things
    }
}

AbstractTransactionalJUnit4SpringContextTests實(shí)際上也是添加了@Transactional注解,只不過(guò)在此之外,它還提供了一些JDBC接口,可以讓我們更方便的操作數(shù)據(jù)庫(kù)。

使用這種方式來(lái)實(shí)現(xiàn)單元測(cè)試的話,由于測(cè)試用例中的所有數(shù)據(jù)庫(kù)操作都在事務(wù)中進(jìn)行,然后運(yùn)行結(jié)束后事務(wù)回滾,就可以保證不會(huì)染污數(shù)據(jù)庫(kù)數(shù)據(jù),做到數(shù)據(jù)隔離。但是它也存在一些問(wèn)題:

  • 影響單元測(cè)試結(jié)果,在方法上層添加事務(wù),本質(zhì)上還是改變了方法的邏輯。比如說(shuō)我被測(cè)試的方法中用到了不同的數(shù)據(jù)源(主從數(shù)據(jù)庫(kù)),一但被包裹了事務(wù),那么意味著我在這個(gè)事務(wù)內(nèi),都是使用同一條連接,這會(huì)對(duì)我們實(shí)際上期望運(yùn)行的邏輯生產(chǎn)影響。
  • 排查問(wèn)題困難,因?yàn)樵趩卧獪y(cè)試運(yùn)行結(jié)束之后,事務(wù)最終會(huì)回滾,也就意味著我們DB最終是沒(méi)有數(shù)據(jù)的,很難排查問(wèn)題。

數(shù)據(jù)預(yù)處理與清理

上面說(shuō)到事務(wù)會(huì)存在一些問(wèn)題,那么我們不使用事務(wù),怎么保證數(shù)據(jù)隔離?我們可以通過(guò)幾種方式來(lái)在單元測(cè)試運(yùn)行前后手動(dòng)的增加或清理數(shù)據(jù):

通過(guò)@Sql注解來(lái)定義單元測(cè)試前后需要執(zhí)行的SQL腳本

    @Sql(
            scripts = "create-data.sql",
            config = @SqlConfig(transactionMode = ISOLATED)
    )
    @Sql(
            scripts = "delete-data.sql",
            config = @SqlConfig(transactionMode = ISOLATED),
            executionPhase = AFTER_TEST_METHOD
    )
    @Test
    void createRecord() {
        User user = userService.createUser();
        //to other things
    }

我們通過(guò)@Sql注解定義指定了兩個(gè)SQL腳本,分別用于在運(yùn)行單元測(cè)試前創(chuàng)建測(cè)試數(shù)據(jù),以及在運(yùn)行結(jié)束后,刪除數(shù)據(jù),這樣就可以保證我們的每次運(yùn)行單元測(cè)試時(shí)的數(shù)據(jù)都是隔離的。

@Sql只是一種方式,我們還可以通過(guò)其它各種方式來(lái)執(zhí)行,比如@BeforeEach、@AfterEach來(lái)定義單元測(cè)試執(zhí)行前后的攔截器,或者Junit的@ExtendWith來(lái)定義外部的監(jiān)聽(tīng)器等各種方式來(lái)處理數(shù)據(jù)的預(yù)處理與清理。

總結(jié)

上面分享了兩種數(shù)據(jù)隔離的方式,一般情況下都可以滿足我們的單元測(cè)試需求,但是實(shí)際上兩種方式都還存在一些問(wèn)題,比如不管是哪種方式,都依賴于外部的數(shù)據(jù)庫(kù),如果我們依賴的數(shù)據(jù)庫(kù)出現(xiàn)了異常,也會(huì)影響到我們的單元測(cè)試運(yùn)行。而且使用外部數(shù)據(jù)庫(kù)也是無(wú)法完全做到數(shù)據(jù)隔離的,還是會(huì)有數(shù)據(jù)沖突的風(fēng)險(xiǎn)。那還有沒(méi)有更好的方法? 如果大家的單元測(cè)試環(huán)境有docker環(huán)境的話,那么可以考慮引入Testcontainers,可以很好的解決這個(gè)問(wèn)題。下篇文章我會(huì)詳細(xì)講一下Testcontainers在單測(cè)數(shù)據(jù)隔離中的實(shí)踐。

以上就是SpringBoot單元測(cè)試之?dāng)?shù)據(jù)隔離詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot單元測(cè)試的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論