testcontainersに基づく現代化集積テストの進歩の道

4193 ワード

大規模なソフトウェアエンジニアリングプロジェクトには、大量の製品レベルのコードのほかに、大量の自動化テストが必要です.自動化テストには、フロントエンドからバックエンド、さらには製品ライン上の異なるモジュールと環境まで、さまざまなタイプのテストが含まれます.比較的古典的な自動化テスト分布に関する理論はテストピラミッドであり、通常のプロジェクトで合理的なテスト数はユニットテスト>コンポーネントテスト>統合テスト>エンドツーエンドテスト(システムテスト)>人工検証テストであるべきである.この理論は概ね合理的である.テストコードの複雑さと実行時間からユニットテスト<コンポーネントテスト<集積テスト<エンドツーエンドテスト(システムテスト)<人工検証テストを見るため、ユニットテストのような迅速なテストを容易に理解し、実行するために、より多くの時間と精力を割り当てるべきである.もちろん、これらのテストの分類と定義については、コンポーネントテストや統合テスト、エンドツーエンドテストなど、統合テストと呼ばれる場合もあります.これらは、2つのモジュールまたはシステム間の統合状況を異なるシステムレベルでテストしようとしているため、統合テストと呼ばれています.
最も古典的な統合テストの例は、バックエンドシステムアプリケーション層とデータ層との間の統合テストであるだろう.データ層は、従来のデータベースであってもよいし、Kafka Streamのような新しい寵愛であってもよい.通常、この統合テストにはいくつかの考え方があります.
  • はstaging環境に配備され、テストでデータ層システムBに対する読み書き操作を含む要求がシステムAに送信される.これは、統合テストをエンドツーエンドテストにスキップしたものです.しかし、このような考え方の弊害は多く、テストコードの複雑さが高く、経路カバー率が低く、バグを書くことからバグを検出するまでの周期も長く、理想的な解決策ではない.
  • テストでIn-memory Embedded Database(通常は実際のデータベースシステムBの純メモリ化実装バージョンであり、主にこのようなテスト環境で使用される)を使用すると、テストシステムAのモジュールXによるデータベースBの書き込み操作に細分化され、ローカルで作成、実行、デバッグでき、上記のソリューションよりも大幅に改善されます.しかし、この解決策にはいくつかの弊害があります.
  • 多くのIn-memory Embedded Databaseは、MongoDB 3.2などの特定のバージョンの実装のみを提供していますが、実際のデータベースバージョンが4.0であれば、多くの新しいデータベース機能がテストで上書きされません.一部のIn-memory Embedded Databaseでは、100%のインタフェース互換性を実現していないか、リレーショナル・データベースのtransaction実装などの異なる実装方法もあります.これは、あなたがテストしたとしても、オンラインのコードが間違っている可能性があります.これは、一般的な本番環境とテスト環境の不一致の問題です.

  • Dockerの普及により、testcontainersはより友好的な統合テストソリューションを提供します.簡単に言えば、Mongo 3.6のコンテナを動的に作成したり、RabbitMQの最新リリース版のコンテナを作成したりするなど、テスト環境で必要な依存サービスのコンテナを動的に作成し、テスト環境を構成して作成したコンテナが露出した呼び出し可能なアドレスをテストアプリケーションに使用させ、テスト終了後に使用したコンテナを破棄して依存サービス状態の移行を防止し、他のテストを理由もなく停止させることです.
    このソリューションには、次のいくつかの利点があります.
  • 各Test Groupは書き込みユニットテストのように細かく書き込み集積テストを書くことができ、各集積ユニットの高いテストカバー率
  • を保証する.
  • Test Group間は依存隔離を行い、つまりDockerコンテナを共有しない.両方のTest GroupがMongo 4.0を使用する場合、
  • を単独で使用するために2つのコンテナが作成されます.
  • は、本番環境とテスト環境の一貫性を保証し、コードがオンラインに配備された場合、サービスインタフェースに依存する互換性がないため、バグ
  • に遭遇することはありません.
  • Test Groupは並列化され、全体的なテスト実行時間を短縮できます.比較的in-memoryの依存サービス実装では、ポートなどのリソース分離がうまく行われていません.パラレル化が実行されると、ポート競合が発生します.
  • Dockerのおかげで、すべてのテストはローカル環境とCI/CD環境で実行でき、テストコードのデバッグと作成はライトユニットテスト
  • のようなものです.
    もちろん、いくつかの劣勢もあります.
  • テストの実行時間が長い:Test GroupごとにDockerコンテナを動的に作成および破棄する必要があるため、この2つのステップは多くの場合、テストの実行時間の大部分を消費します.もちろん客観的に言えば、この待ち時間は秒レベルなので、納得できます.テストを並列に実行する場合は、全体的な実行時間は制御できます.
  • テスト作成、デバッグ体験上記の点で影響を受ける
  • リソース使用率が高い:ほとんどのbuild agentは仮想マシンであり、dockerプロセスでもあり、さらにTest Groupごとにリソースを割り当てて依存サービスを実行する必要があるため、build agent全体のCPU、メモリ使用率は大幅に増加します.忙しいときには、パフォーマンスの劣化の問題も発生します.解決策はscale up/out build agentです.

  • プログラミング言語のサポートから言えば、現在testcotainersのgithub orgにはJava,Scala,Go,Rust,NodeJs,Python,C#のクラスライブラリが提供されている.成熟度から言えばJavaのクラスライブラリが最も成熟しているに違いなく、多くのオープンソースプロジェクトで使用されています.他の言語のクラスライブラリでは、いくつかの穴を踏むことが避けられないことが想像できます.
    公式サイトの例を挙げてtestcontainersクラスライブラリの使用方法を説明します.
    public class RedisBackedCacheIntTestStep0 {
        private RedisBackedCache underTest;
    
        @Before
        public void setUp() {
            // Assume that we have Redis running locally?
            underTest = new RedisBackedCache("localhost", 6379);
        }
    
        @Test
        public void testSimplePutAndGet() {
            underTest.put("test", "example");
    
            String retrieved = underTest.get("test");
            assertEquals("example", retrieved);
        }
    }
    

    上記のJUnitテストではredis:5.0.3-alphineコンテナを動的に作成し、setupメソッドでコンテナの公開アドレスとインタフェースを取得してテストするRedisBackedCacheインスタンスを作成し、テストでインスタンスのメソッド、検証結果を簡単に呼び出します.
    testcontainers Javaは、ほとんどのデータベース(MySQL、Postgres、Cassandra、Neo 4 j)、UIテストのWebdriver、ElasticSearch、Kafka、Nginxなど、いくつかの既存の使用頻度の高いコンテナのクラスパッケージを提供しています.既存のパッケージが見つからない場合は、常に最下位のGenericContainerを呼び出すことができます.主流のJavaテストフレームワーク、JUnit 4、JUnit 5、TestNG、Spockもサポートしています.総じてJavaを書く同級生にはこのクラスライブラリがとても使いやすいです!
    転載先:https://juejin.im/post/5d034d90e51d4550a629b26a