スケーラブルで副作用のない統合テストを作成する方法は?


14

私の現在のプロジェクトでは、副作用のないスケーラブルな統合テストを作成するための優れたソリューションを思いつくのに苦労しています。副作用のないプロパティに関する少しの明確化:それはほとんどデータベースに関するものです。テストが完了した後、データベースに変更が加えられるべきではありません(状態は保持されるべきです)。スケーラビリティと状態保存は一緒にならないかもしれませんが、私は本当にもっと良い解決策を求めています。

一般的な統合テストを次に示します(これらのテストはデータベース層に影響を与えます):

public class OrderTests {

    List<Order> ordersToDelete = new ArrayList<Order>(); 

    public testOrderCreation() {
        Order order = new Order();
        assertTrue(order.save());
        orderToDelete.add(order);
    }

    public testOrderComparison() {
        Order order = new Order();
        Order order2 = new Order();
        assertFalse(order.isEqual(order2);
        orderToDelete.add(order);
        orderToDelete.add(order2);
    }
    // More tests

    public teardown() {
         for(Order order : ordersToDelete)
             order.delete();
    }
}

ご想像のとおり、このアプローチではテストが非常に遅くなります。また、統合テスト全体に適用すると、システムのごく一部のみをテストするのに約5秒かかります。カバレッジが増加すると、この数値が増加することを想像できます。

そのようなテストを書くための別のアプローチは何でしょうか?私が考えることができる1つの選択肢は、一種のグローバル変数(クラス内)を持つことであり、すべてのテストメソッドはこの変数を共有します。その結果、少数の注文のみが作成および削除されます。テストが高速になります。ただし、これにより大きな問題が発生すると思います。テストはもはや分離されておらず、テストの理解と分析がますます困難になっています。

統合テストは、単体テストほど頻繁に実行されることを意図していないのかもしれません。したがって、これらの場合、低いパフォーマンスが許容される場合があります。いずれにせよ、誰かがスケーラビリティを改善するための代替案を思いついたかどうかを知ることは素晴らしいでしょう。

回答:


6

ユニットテスト用にHypersonicまたは別のインメモリDBの使用を検討してください。テストがより速く実行されるだけでなく、副作用も関係ありません。(各テストの後にトランザクションをロールバックすると、同じインスタンスで多くのテストを実行することもできます)

これにより、データモックアップの作成も強制されます。これは、実稼働データベースで発生した何かがテストの失敗を不可解に開始できないことを意味し、「クリーンデータベースインストール」の開始点となります。のようになります。これは、既存の実稼働サイトに接続せずに、アプリケーションの新しいインスタンスを突然デプロイする必要がある場合に役立ちます。

はい、私は自分でこの方法を使用します。はい、それは最初の時間を設定するのがPITAでしたが、私が完了しようとしているプロジェクトの存続期間中にそれ自身のために支払った以上です。データのモックアップを支援するツールも多数あります。


素晴らしいアイデアのように聞こえます。特に、完全な分離の側面が気に入っています。データベースの新規インストールから始めます。少し手間がかかるようですが、一度セットアップすれば非常に有益です。ありがとう。
21:17にGuven

3

これは、統合テストの作成中に誰もが直面する永遠の問題です。

特に本番環境でテストする場合の理想的なソリューションは、セットアップでトランザクションを開き、分解してロールバックすることです。これはあなたのニーズに合うはずだと思います。

それが不可能な場合、たとえば、クライアントレイヤーからアプリをテストする場合、別の解決策は、仮想マシンでDBを使用し、セットアップでスナップショットを取得し、分解でそれに戻ることです(それはしませんあなたが期待するかもしれない限りかかります)。


トランザクションのロールバックを考えていなかったとは信じられません。このアイデアをソリューションの簡単な修正として使用しますが、最終的にはインメモリDBは非常に有望に思えます。
Guven

3

統合テストは、実稼働セットアップに対して常に実行する必要があります。あなたの場合は、同じデータベースとアプリケーションサーバーが必要であることを意味します。もちろん、パフォーマンスのために、インメモリDBを使用することもできます。

ただし、トランザクションスコープを拡張することはできません。一部の人々は、トランザクションの制御を引き継ぎ、テスト後にロールバックすることを提案しました。これを行うと、すべてのエンティティ(JPAを使用していると想定)、テストの実行中、永続コンテキストにアタッチされたままになります。これは見つけるの非常に難しいいくつかの非常に厄介なバグをもたらすかもしれませ

代わりに、JPAUnitなどのライブラリまたはこのアプローチに類似したライブラリ(JDBCを使用してすべてのテーブルをクリア)を介してテストするたびに、データベースを手動でクリアする必要があります。

パフォーマンスの問題に関しては、すべてのビルドで統合テストを実行しないでください。継続的統合サーバーにこれをさせてください。Mavenを使用する場合、フェイルセーフプラグインを使用すると、テストを単体テストと統合テストに分離できます。

また、あなたは何もm笑するべきではありません。統合テスト、つまり、実行時実行環境内での動作のテストであることを忘れないでください。


いい答えです。ワンポイント:いくつかの外部依存関係を模倣することは許容されるかもしれません(例:電子メールの送信)。ただし、Javaコードでモックするのではなく、完全なモックサービス/サーバーを設定してモックする必要があります。
sleske

スレスケ、あなたに同意します。特に、JPA、EJB、JMSを使用する場合、または別の仕様に対して実装する場合。アプリケーションサーバー、永続化プロバイダー、またはデータベースを交換できます。たとえば、組み込みのGlassfishとHSQLDBを使用して、セットアップと速度を単純に向上させることができます(もちろん、認定された別の実装を自由に選択できます)。
BenR

2

スケーラビリティについて

統合テストの実行に時間がかかりすぎ、変更のタイトなフィードバックループで単一の開発者が継続的に実行するのは実用的ではないということは、以前にも何度かありました。これに対処するためのいくつかの戦略は次のとおりです。

  • 統合テストの作成を減らす -システム内の単体テストを十分に網羅している場合、統合テストは(さまざまな)統合の問題、異なるコンポーネントがどのように連携するかに焦点を当てる必要があります。これらは、システムがまだ全体として機能するかどうかを確認するだけのスモークテストに似ています。したがって、理想的には、単体テストはアプリケーションの機能部分のほとんどをカバーし、統合テストはそれらの部分が互いにどのように相互作用するかをチェックするだけです。ここでは、論理パスを広範囲にカバーする必要はなく、システムを通るいくつかの重要なパスだけが必要です。
  • 一度にテストのサブセットのみを実行します。一部の機能に取り組んでいる単一の開発者として、通常、その機能をカバーするためにどのテストが必要であるかの感覚があります。変更をカバーする意味のあるテストのみを実行します。JUnitのようなフレームワークを使用すると、カテゴリ内のフィクスチャグループ化できます。持っている機能ごとに最適なカバレッジを可能にするグループを作成します。もちろん、ソース管理システムにコミットする前に、また継続的な統合サーバーでコミットする前に、ある時点ですべての統合テストを実行する必要があります。
  • システムの最適化 -統合テストと一部のパフォーマンステストを組み合わせることで、システムの低速部分を調整するために必要な入力が得られるため、テストを後で高速に実行できます。これにより、データベース内の必要なインデックス、サブシステム間のおしゃべりなインターフェイス、またはアドレス指定が必要なその他のパフォーマンスのボトルネックを発見できる場合があります。
  • テストを並行して実行する -直交テストの適切なグループ化がある場合、並行して実行してみてください。ただし、私が述べた直交要件に注意してください。テストがお互いに足を踏み入れることは望ましくありません。

これらの手法を組み合わせて、効果を高めてください。


1
本当に良いガイドライン。統合テストの作成を減らすことは、最善のアドバイスです。また、それらを並行して実行することは非常に優れた選択肢です。分離の観点からテストをまっすぐに受けたかどうかをチェックする完璧な「テスト」。
グベン

2

テスト目的で、SQLiteデータベースのファイルベースの展開を使用しました(リソースをコピーするだけです)。これは、スキーマの移行もテストできるようにするために行われました。私の知る限り、スキーマの変更はトランザクションではないため、トランザクションが中止された後にロールバックされることはありません。また、テストセットアップのトランザクションサポートに依存する必要がないため、アプリケーションからのトランザクションの動作を適切にテストできます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.