私は最初のアプローチを使用していますが、あなたが言及した問題に対処するために少し異なっています。
DAOのテストを実行するために必要なものはすべてソース管理にあります。DBを作成するためのスキーマとスクリプトが含まれています(Dockerはこれに非常に適しています)。組み込みDBを使用できる場合-速度を上げるために使用します。
説明されている他のアプローチとの重要な違いは、テストに必要なデータがSQLスクリプトまたはXMLファイルからロードされないことです。すべて(実質的に一定であるいくつかの辞書データを除く)は、ユーティリティ関数/クラスを使用してアプリケーションによって作成されます。
主な目的は、テストで使用されるデータを作成することです
- テストに非常に近い
- 明示的(データにSQLファイルを使用すると、どのデータがどのテストで使用されているかを確認するのが非常に困難になります)
- 無関係な変更からテストを分離します。
これは基本的に、これらのユーティリティがテスト自体でテストに不可欠なものだけを宣言的に指定し、無関係なものを省略できることを意味します。
実際の意味を理解するために、によって記述されたComment
sからPost
s で機能するDAOのテストを考えてみましょうAuthors
。このようなDAOのCRUD操作をテストするには、DBにいくつかのデータを作成する必要があります。テストは次のようになります。
@Test
public void savedCommentCanBeRead() {
// Builder is needed to declaratively specify the entity with all attributes relevant
// for this specific test
// Missing attributes are generated with reasonable values
// factory's responsibility is to create entity (and all entities required by it
// in our example Author) in the DB
Post post = factory.create(PostBuilder.post());
Comment comment = CommentBuilder.comment().forPost(post).build();
sut.save(comment);
Comment savedComment = sut.get(comment.getId());
// this checks fields that are directly stored
assertThat(saveComment, fieldwiseEqualTo(comment));
// if there are some fields that are generated during save check them separately
assertThat(saveComment.getGeneratedField(), equalTo(expectedValue));
}
これには、SQLスクリプトやテストデータを含むXMLファイルに比べていくつかの利点があります。
- コードの保守がはるかに簡単です(たとえば、Authorなどの多くのテストで参照されるエンティティに必須の列を追加する場合、多くのファイル/レコードを変更する必要はなく、ビルダーやファクトリを変更するだけです)。
- 特定のテストに必要なデータは、テスト自体に記述されており、他のファイルには記述されていません。この近接性は、テストをわかりやすくするために非常に重要です。
ロールバックとコミット
テストの実行時にテストをコミットする方が便利だと思います。まず、いくつかの効果(例えばDEFERRED CONSTRAINTS
コミットが発生しない場合)をチェックできません。次に、テストが失敗した場合、データはロールバックによって元に戻されないため、DBでデータを調べることができます。
これには、テストが壊れたデータを生成する可能性があり、他のテストでエラーが発生するという欠点があります。これに対処するために、テストを分離してみます。上記の例では、すべてのテストが新しくAuthor
作成され、他のすべてのエンティティがそれに関連して作成されるため、衝突はまれです。壊れる可能性はあるが、DBレベルの制約として表現できない残りの不変条件を処理するために、プログラムごとのチェックを使用して、すべてのテストの後に実行される可能性がある誤った条件をチェックします(それらはCIで実行されますが、通常はパフォーマンスのためにローカルでオフにされます理由)。