私は最初のアプローチを使用していますが、あなたが言及した問題に対処できるようにするために少し異なります。
DAO のテストを実行するために必要なものはすべてソース管理にあります。これには、DB を作成するためのスキーマとスクリプトが含まれています (これには docker が非常に適しています)。組み込み DB を使用できる場合は、高速化のために使用します。
説明されている他のアプローチとの重要な違いは、テストに必要なデータが SQL スクリプトまたは XML ファイルから読み込まれないことです。すべて (実質的に定数である一部の辞書データを除く) は、ユーティリティ関数/クラスを使用してアプリケーションによって作成されます。
主な目的は、テストで使用されるデータを作成することです
- テストに非常に近い
- 明示的 (データに SQL ファイルを使用すると、どのデータがどのテストで使用されているかを確認するのが非常に困難になります)
- 無関係な変更からテストを分離します。
これは基本的に、これらのユーティリティが、テスト自体でテストに不可欠なものだけを宣言的に指定し、無関係なものを省略できることを意味します。
それが実際に何を意味するのかを理解するために、によって書かれたComment
s からs で動作する DAO のテストを考えてみましょう。このような DAO の CRUD 操作をテストするには、DB にデータを作成する必要があります。テストは次のようになります。Post
Authors
@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 ファイルよりもいくつかの利点があります。
- コードの保守ははるかに簡単です (たとえば、作成者など、多くのテストで参照されるエンティティに必須の列を追加すると、多くのファイル/レコードを変更する必要はなく、ビルダーやファクトリを変更するだけで済みます)。
- 特定のテストに必要なデータは、他のファイルではなく、テスト自体に記述されています。この近接性は、テストを理解しやすくするために非常に重要です。
ロールバックとコミット
テストが実行されたときにコミットする方が便利だと思います。まず、コミットが発生しない場合、一部の効果 (たとえばDEFERRED CONSTRAINTS
) をチェックできません。次に、テストが失敗した場合、データはロールバックによって元に戻されないため、DB で調べることができます。
当然のことながら、これには、テストによって壊れたデータが生成される可能性があり、これが他のテストの失敗につながるという欠点があります。これに対処するために、テストを分離しようとします。上記の例では、すべてのテストが新しいAuthor
ものを作成し、他のすべてのエンティティがそれに関連して作成されるため、衝突はまれです。壊れる可能性はあるが DB レベルの制約として表現できない残りの不変条件に対処するために、すべてのテストの後に実行される可能性のある誤った条件に対して、いくつかのプログラムによるチェックを使用します (これらは CI で実行されますが、通常はパフォーマンスのためにローカルでオフにされます)理由)。