web-dev-qa-db-ja.com

単体テストとTDDを使用して、データベースのCRUD操作に主に依存するアプリをテストするにはどうすればよいですか?

仕事では、私のプロジェクトの1つは、ほとんどの場合、外部クライアントから渡されたデータを取得してデータベースに永続化することです。これはJava JPAを使用するエンタープライズアプリであり、ロジックのほとんどはCRUD操作を中心に展開しています。

私たちのバグの大部分は、何らかの方法でJPAに関係しています。

  • 例1:保存ボタンを2回クリックすると、JPAは同じエンティティをもう一度データベースに挿入しようとし、主キー違反を引き起こす可能性があります。
  • 例2:データベースからエンティティを取得して編集し、そのデータを更新しようとします。 JPAは、古いインスタンスを更新する代わりに、新しいインスタンスを作成しようとする場合があります。

多くの場合、ソリューションはJPAアノテーションを追加/削除/変更する必要があります。それ以外の場合は、DAOロジックの変更に関係しています。

単体テストとTDDを使用してコードを信頼する方法がわかりません。ユニットテストとTDDの適合性が悪いためか、問題に間違って対処しているためか、わかりません

実行時にのみこれらの問題を検出でき、問題を再現するためにアプリサーバーにデプロイする必要があるため、ユニットテストは適切ではないようです。通常、データベースが関与する必要があります。これは、単体テストの定義の外にあると考えています。これらは統合テストです。

展開+テストのフィードバックループが非常に遅いため、TDDは不適切に思えます。デプロイ+テストのフィードバックループには3分以上かかります。これは、私が書いているコードに関するテストを実行した場合に限ります。すべての統合テストを実行するには、30分以上かかります。

この型の外にコードがあり、できる限りいつでもそれを単体テストします。しかし、私たちのバグの大部分と最大の時間シンクには、常にJPAまたはデータベースが関係しています。


同様の別の質問があります ですが、私がアドバイスに従えば、コードの最も不安定な部分(JPA)をラップして、それ以外のすべてをテストすることになります。私の質問の文脈では、私は同じ悪い状況になるでしょう。 JPAをラップした後の次のステップは何ですか? IMOその質問は(おそらく)私の質問に答えるステップですが、それに対する答えではありません。

22
Daniel Kaplan

1つのオプションは、 H2 などのインメモリテストデータベースを使用することです。標準のディスクを使用するデータベースよりも約10倍速く、起動/ティアダウン時間が短い傾向があります。

それが役立つかどうかは、あなたが直面しているJPAの問題が、別のデータベースでも失敗するほど一般的であるかどうかに大きく依存します。問題の大部分を見逃した場合、テストをより速く実行することはあまりありません。

しかし、フルシステムで1人につきH2で10回の実行が可能であれば、それは報われる可能性があります。

7
soru

データベースの単体テストは非常に簡単です。ストアドプロシージャとトランザクションが必要です。

Microsoftがこれについて述べている データベースの単体テスト 。データベースに対してユニットテストを実行し、JavaまたはC#にテストを書き込むには、DB接続を設定し、トランザクションを開始し、テストに使用するデータをDBに書き込みます。 、テストを実行してからロールバックします。デプロイしたものを使用していて、完全に分離されたテストを取得しても、DBに損傷はありません。

これがあなたのフレームワーク内でそれを行う方法についていくつかの洞察を与えることを願っています。

3
gbjbaanb

他の人々は「あなたのDBを模擬しなさい!」と答えました。 -しかし、実際にコードとどのように相互作用するかをテストする必要がある場合、DBレイヤーをモックアウトするポイントは何ですか?

探しているのは、統合テストや自動UIテストです。問題が発生するのは次の場合です。

*If you click the save button twice*

これをテストする唯一の方法は、ボタンを2回クリックする自動UIテストを作成することです。多分セレンをチェックしてください。

おそらく、ユニットテストDBも必要です。テストでは、それをポイントします。維持するのは難しいですが、現実の世界ではTDDへようこそ。

3
Rocklan

質問の例では、ボタンを2回クリックして非常に簡単にエラーを発生させる状況にユニットテスト/ TDDすることはできません。しかし、ユニットテストでできるのは、ボタンをクリックしたときに呼び出されるコードで、永続化レイヤーから例外を取得した場合、永続化レイヤーをモックアウトするか、メモリ内データベースを使用して適切に処理することです。他の回答で提案されています)-エラーまたは何かを再スローまたは表示することによって。

ユニットテスト(つまり、統合/システムテスト)に適していないテストを実行する必要がある場合、TDDが機能しなくなる可能性があります。これにより、最近の「Is TDDデッド?"ケントベック、マーティンファウラー、デビッドハイネマイヤーハンソンの間の議論: http://martinfowler.com/articles/is-tdd-dead/

0
Chris Cooper