ユニットテストに「実際の」データベースを使用する場合の問題は、テストのセットアップ、停止、および分離です。完全に新しいMySQLデータベースを起動し、1つの単体テストのためだけにテーブルとデータを作成する必要はありません。この問題は、データベースの外部の性質に関係しており、テストデータベースがダウンしているため、ユニットテストは失敗します。また、テスト用の一意のデータベースがあることを確認することにも問題があります。それらは克服できますが、より簡単な答えがあります。
データベースのモックは、1つの選択肢であるが、それが実行されている実際のクエリをテストしません。DAOからのデータがシステムを適切に通過することを確認したい場合は、はるかに簡単なソリューションとして使用できます。しかし、DAO自体をテストするには、データとクエリが適切に実行されるDAOの背後に何かが必要です。
最初に行うことは、メモリ内データベースを使用することです。 HyperSQLは、別のデータベースの方言をエミュレートする機能を備えているため、このための優れた選択肢です。したがって、データベース間のわずかな違いは同じままです(データ型、関数など)。hsqldbには、単体テスト用の優れた機能もいくつかあります。
db.url=jdbc:hsqldb:file:src/test/resources/testData;shutdown=true;
これにより、データベースの状態(テーブル、初期データ)がtestData
ファイルからロードされます。 shutdown=true
最後の接続が閉じたときにデータベースを自動的にシャットダウンします。
依存性注入を使用して、ユニットテストで本番(またはテスト、またはローカル)ビルドが使用するデータベースとは異なるデータベースを選択します。
次に、DAOは、データベースに対してテストを起動できる注入されたデータベースを使用します。
単体テストは次のようになります(簡潔さのために含まれていない退屈なものの束):
@Before
public void setUpDB() {
DBConnection connection = new DBConnection();
try {
conn = connection.getDBConnection();
insert = conn.prepareStatement("INSERT INTO data (txt, ts, active) VALUES (?, ?, ?)");
} catch (SQLException e) {
e.printStackTrace();
fail("Error instantiating database table: " + e.getMessage());
}
}
@After
public void tearDown() {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
private void addData(String txt, Timestamp ts, boolean active) throws Exception {
insert.setString(1, txt);
insert.setTimestamp(2, ts);
insert.setBoolean(3, active);
insert.execute();
}
@Test
public void testGetData() throws Exception {
// load data
Calendar time = Calendar.getInstance();
long now = time.getTimeInMillis();
long then1h = now - (60 * 60 * 1000); // one hour ago
long then2m = now - (60 * 1000 * 2); // two minutes ago
addData("active_foo", new Timestamp(then1h), true); // active but old
addData("inactive_bar", new Timestamp(then1h), false); // inactive and old
addData("active_quz", new Timestamp(then2m), true); // active and new
addData("inactive_baz", new Timestamp(then2m), false); // inactive and new
DataAccess dao = new DataAccess();
int count = 0;
for (Data data : dao.getData()) {
count++;
assertTrue(data.getTxt().startsWith("active"));
}
assertEquals("got back " + count + " rows instead of 1", count, 1);
}
したがって、DAOを呼び出す単体テストがあり、テスト中に存在するオンザフライデータベースにセットアップされたデータを使用しています。実行前、または既知の状態に復元する前に、外部リソースやデータベースの状態を心配する必要はありません(「既知の状態」は「存在しない」ため、元に戻すのは簡単です)。
DBUnitは、データベースのセットアップ、テーブルの作成、データのロードにおいて、私が説明したより単純なプロセスの多くを行うことができます。何らかの理由で実際のデータベースを使用する必要がある場合、これははるかに優れたツールです。
上記のコードは、githubのTestingWithHsqldbの概念実証のために書いたMavenプロジェクトの一部です