日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

使用TestContainers进行数据库测试

發布時間:2023/12/3 数据库 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用TestContainers进行数据库测试 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

如果您曾經編寫過測試數據庫交互的代碼,例如數據訪問對象,那么您很可能遇到了測試中最長期的煩惱之一:為了準確地測試這些交互,需要一個數據庫。

為了本文的方便,讓我們考慮一個將PostgreSQL用作其環境的一部分的應用程序,因為這是示例所使用的。 同樣,盡管H2被廣泛提及,但這絕不是要貶低它的意思-在正確的位置使用它是一個很好的工具。

問題

已經提出了解決該問題的各種方法,但是似乎總是存在一些缺點。

一種測試方法是使用內存數據庫,例如H2。

優點:

  • 數據庫在虛擬機本地
  • 數據庫生命周期由構建過程管理
  • 初始狀態由構建過程或測試管理

缺點:

  • 您沒有準確地對環境建模
  • 并非支持生產數據庫的所有功能
  • 不同的數據類型意味著不同的列定義
  • 涉及相同表的多個測試不能并行運行而不會產生沖突

如果您認為這些約束是不可接受的,則可以考慮保留一個眾所周知的正在運行的PostgreSQL數據庫實例用于測試。

優點:

  • 與生產數據庫100%兼容

缺點:

  • 不保證初始數據狀態
  • 同一版本中涉及相同表的多個測試不能并行運行而不會產生沖突
  • 并行構建可能導致結果不一致
  • 運行本地測試的開發人員可能會破壞持續的集成構建

這種方法的進一步改進是使每個開發人員都擁有自己的PostgreSQL數據庫實例。

優點:

  • 與生產數據庫100%兼容
  • 開發人員構建不會干擾持續集成構建

缺點:

  • 不保證初始數據狀態
  • 同一版本中涉及相同表的多個測試不能并行運行而不會產生沖突
  • 并行構建可能導致結果不一致
  • 開發人員必須保持其數據庫實例為最新(或必須添加工具來對此進行管理)

使用這些方法中的每一種,我都認為不利之處足以部分或完全抵消優點。

外賣

分解最后三段,我們可以看到以下功能是理想的:

  • 數據庫應綁定到測試(而不是虛擬機)
    • 這意味著現在可以進行測試并行化了
  • 數據庫生命周期應由內部版本管理
  • 數據庫應與生產中使用的數據庫相同

我最喜歡的新解決方案

使用TestContainers ,我們可以勾選每個功能。 使用JUnit @Rule ,TestContainers將啟動每個測試的Docker映像,該映像提供一個壽命與測試一樣長的數據庫。 由于每個Docker實例都是完全隔離的,因此可以并行運行測試以加快構建速度。

最后一點非常重要,因為如上所述,似乎總是存在一些缺點。 在這種情況下,啟動Docker映像及其包含的所有內容的開銷將增加您的總體構建時間。 我會(并且確實)認為增加的測試時間幾乎不會影響擁有我們所有所需功能的好處。

TestContainers開箱即用支持的每個數據庫都有一個特定規則,該規則可用于獲取連接到數據庫所需的所有詳細信息。

public class FooDaoTest {@Rulepublic PostgreSQLContainer postgres = new PostgreSQLContainer();@Beforepublic void setUp() {// populate database// postgres.getDriverClassName()// postgres.getJdbcUrl()// postgres.getUsername()// postgres.getPassword()} }

或者...

根據文檔 ,可以通過將JDBC URL更改為包含tc:來啟動新容器,例如jdbc:tc:postgresql://hostname/databasename 。 但是,由于驅動程序中存在這一行 ,因此在我的應用程序中失敗了。

if (!url.startsWith("jdbc:postgresql:")) {

軼事

在這里,我花了10分鐘時間將應用程序從使用H2切換為使用Dockerized PostgreSQL,這使我的生活變得更加簡單。 我們使用jOOQ進行數據庫交互,發現自己不得不刪除一些非常好的jOOQ功能,因為H2不支持它們。

讓我重復一遍。 由于測試環境的限制,我們面臨著不斷變化的生產代碼 。

那是不可能的,而且永遠不會是一個可以接受的情況,因此TestContainers的發現既是偶然的也是節省時間的。 太好了,因為它確實提供了我們所需的東西,但是省時? 我剛才說這會增加測試時間,怎么說呢? 很簡單–我不需要花時間查看是否有H2模式可以支持我正在使用的功能。 我發現自己寫的代碼以后必須刪除,因為H2不允許這樣做; 我可以編寫測試和與DB相關的代碼,然后就完成了。

哇,您沒有提到Play的整個博客文章嗎?

不。 根據我剛剛提到的應用程序,這是在Play上使用它的一種簡便方法。

首先,創建一個將TestContainer與Play的數據庫支持結合在一起的mixin。

package be.objectify.tcexample.db;import com.google.common.collect.ImmutableMap; import org.testcontainers.containers.PostgreSQLContainer; import play.db.Database; import play.db.Databases; import play.db.evolutions.Evolutions;public interface DbTestSupport {default Database create(final PostgreSQLContainer postgres) throws Exception {final Database database = Databases.createFrom("default",postgres.getDriverClassName(),postgres.getJdbcUrl(),ImmutableMap.of("username", postgres.getUsername(),"password", postgres.getPassword()));Evolutions.applyEvolutions(database);return database;}default void destroy(final Database database) {Evolutions.cleanupEvolutions(database);database.shutdown();} }

我在這里使用mixin的原因是因為傾向于在接口旁邊定義DAO測試-請參閱我的[上一篇文章](http://www.objectify.be/wordpress/2013/06/01/a-good-lazy-way -to-write-tests /)。 如果可以將測試定義為mixins,那就更好了,因為可以將通用數據庫設置代碼放入一個通用類中,然后可以將其擴展以實現測試mixins,但是JUnit無法識別以這種方式定義的測試。

因此,抽象測試類不知道它具有需要數據庫的實現-它僅測試接口的約定。

package be.objectify.tcexample;import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat;public abstract AbstractUserDaoTest {@Testpublic void testFoo() {assertThat(dao().something()).isEqualTo(whatever);}// many, many more testspublic abstract UserDao dao(); }

通過我們特定于數據庫的實現作為后盾,我們現在可以確保我們的實現按照合同要求的方式運行。

package be.objectify.tcexample.db;import be.objectify.tcexample.AbstractUserDaoTest; import be.objectify.tcexample.UserDao; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.testcontainers.containers.PostgreSQLContainer; import play.db.Database;public class JooqUserDaoTest extends AbstractUserDaoTest implements DbTestSupport,TestData {@Rulepublic PostgreSQLContainer postgres = new PostgreSQLContainer();private Database database;@Beforepublic void setup() throws Exception {// the database has all evolutions applieddatabase = create(postgres); // load some test dataloadTestData(database); }@Afterpublic void tearDown() {destroy(database);}@Overridepublic UserDao dao() {return new JooqUserDao(database);} }

現在,我們的JooqUserDao實現將針對生產中使用的數據庫類型的真實實例運行。

JooqUserDaoTest使用的TestData接口只是將某些數據加載到數據庫中的另一個mixin。 實現并不是特別重要,因為它很大程度上取決于您自己的要求,但是它看起來可能像這樣。

package be.objectify.tcexample.db;import org.jooq.impl.DSL; import play.db.Database;import java.sql.Connection; import java.sql.Timestamp; import java.time.Instant;import static be.objectify.tcexample.db.jooq.generated.Tables.ACCOUNT;public interface TestData {default void loadTestData(Database database) {database.withConnection((Connection conn) -> {DSL.using(conn).insertInto(ACCOUNT,ACCOUNT.ID,ACCOUNT.KEY,ACCOUNT.CREATED_ON).values(1,"test-account-a",Timestamp.from(Instant.now())).execute();DSL.using(conn).insertInto(ACCOUNT,ACCOUNT.ID,ACCOUNT.KEY,ACCOUNT.CREATED_ON).values(2,"test-account-b",Timestamp.from(Instant.now())).execute();});} }

翻譯自: https://www.javacodegeeks.com/2017/03/database-testing-testcontainers.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的使用TestContainers进行数据库测试的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。