ホームページ >Java >&#&チュートリアル >開発/製品パリティ : Spring Boot テストコンテナ

開発/製品パリティ : Spring Boot テストコンテナ

DDD
DDDオリジナル
2025-01-10 11:03:43518ブラウズ

導入

開発/製品パリティは、開発環境と実稼働環境の間のギャップを減らすことを目的としています。この記事では、開発と運用を可能な限り類似させる方法として、特に Spring Testcontainers との統合テストにおけるツールのギャップを対象としています。
データベースを含む統合テストを実行する場合、すべての CRUD 操作を慎重に管理する必要があります。これは、TestDeleteUserByID_ShouldReturnOk() などのテストが、2015 年以来当社を利用してくれる最も忠実なクライアントのアカウントを「誤って」消去してしまう可能性がある集中型データベース環境では非常に重要です ?‍♂️
このようなリスクを軽減するには、テスト データを分離するためのデータベース トランザクションなどのソリューションを検討できます。たとえば、テストではデータを変更するトランザクションを開始し、最後にロールバックすることで、データベースを元の状態のままにすることができます。
ただし、これによって重大な問題が生じます: テストは何をテストするのか?

Dev/prod parity : Spring Boot Testcontainers

分離が失敗し、コードが何らかの理由でロールバックされない変更を実行し、実稼働環境へのデータ漏洩につながった場合はどうなるでしょうか?このようなシナリオでは潜在的な損害は重大です。

あるいは、H2DB などのインメモリ データベースを使用した自己完結型テストにもいくつかの課題があります。たとえセットアップが簡単であっても、H2DB は RDBMS とは異なるため、開発環境と本番環境でテストの結果が異なる可能性が高く、その結果を信頼することはできません。

https://stackoverflow.com/questions/62778900/syntax-error-h2-database-in-postgresql-compatibility

次に問題の少ない解決策は、データベースのクローンを作成することです。これにより、運用環境に似た環境でリスクの少ないアプローチが提供されます。ただし、この方法には限界があります。 ORM が運用データベース スキーマの作成とセットアップを自動化することを考えると、複製された開発データベースの同期を維持する方法を考える必要があります。


コンテナ化できるものはすべてテストします: データベース、メッセージ ブローカーなど

「Testcontainers は、JUnit テストをサポートする Java ライブラリで、一般的なデータベース、Selenium Web ブラウザ、または Docker コンテナ内で実行できるその他の軽量の使い捨てインスタンスを提供します。」

元々は Java 用に開発されましたが、その後 Go、Rust、.NET などの他の言語をサポートするように拡張されました。

Testcontainers の主なアイデアは、IDE から実行可能なオンデマンドのインフラストラクチャを提供することです。そこでは、モックやメモリ内サービスを使用せずに、自動クリーンアップを使用してテストを実行できます。

これは 3 つのステップで実現できます:

  • 必要なサービスを開始し、Docker コンテナをセットアップしてインフラストラクチャを準備し、このセットアップをテスト インフラストラクチャとして使用するようにアプリケーションを構成します。
  • Docker 化されたインフラストラクチャでテストを実行します。
  • テストが完了したら、Docker 化されたインフラストラクチャを自動的にクリーンアップします

Testcontainers ライブラリのドキュメント


Spring Boot テストコンテナの実装

統合テストの基本クラスである ApplicationIntegrationTests で、静的な PostgreSQLContainer を定義します。このコンテナは、このクラスから派生したすべてのテスト インスタンスで使用されます。

@Testcontainers アノテーションを使用すると、@Container アノテーションが付けられたすべてのフィールドの検出、コンテナーのライフサイクル メソッドの管理、コンテナーの起動が可能になります。

  • 静的フィールドとして宣言されたコンテナは、テスト メソッド間で共有されます。これらは、テスト メソッドが実行される前に 1 回だけ開始され、最後のテスト メソッドが実行された後に停止されます。
  • インスタンス フィールドとして宣言されたコンテナは、テスト メソッドごとに起動および停止されます。

@DynamicPropertySource アノテーションを使用すると、プロパティをテスト環境に動的に挿入できます。

@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 コールバック メソッドで、Postgres コンテナを明示的に停止します。ただし、コンテナを明示的に停止しなくても、Testcontainers はテスト実行の終了時にコンテナを自動的にクリーンアップしてシャットダウンします。

次のように ApplicationIntegrationTests を拡張することで、統合テストを作成できるようになりました。

@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());
    }
}

以上が開発/製品パリティ : Spring Boot テストコンテナの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
前の記事:Java財団次の記事:Java財団