Play Framework2.1.0でリレーショナルデータベースを使用するコードをカバーする単体テストを作成したいと思います。これには多くの可能性があり、すべてが問題を引き起こします。
Play Frameworkのドキュメントでは、開発および本番環境で使用されるメインデータベースが他のソフトウェア(MySQLなど)を使用している場合でも、H2インメモリデータベースで単体テストを実行することを提案しています。
_app = Helpers.fakeApplication(Helpers.inMemoryDatabase());
_
私のアプリケーションは、ストアドプロシージャなどの複雑なRDBMS機能を使用せず、ほとんどのデータベースアクセスケースはebean呼び出しであるため、MySQLとH2の両方と互換性があるはずです。
ただし、エボリューションのテーブル作成ステートメントは、_ENGINE = InnoDB
_、_DEFAULT CHARACTER SET = utf8
_などの指定などのMySQL固有の機能を使用します。_CREATE TABLE
_のこれらの独自の部分を削除すると、MySQLはいくつかを使用します。制御できないデフォルト設定であり、バージョンによって異なるため、アプリケーションのメインMySQL構成をテストおよび開発するには、変更する必要があります。
誰かがこのアプローチを使用しました(進化をMySQLとH2の両方と互換性を持たせる)?
それをどのように扱うことができるかの他のアイデア:
create table
_の追加のMySQLのものを無視させるいくつかの方法(MySQL互換モードは機能せず、_default character set
_でも文句を言います)。方法がわかりません。H2インメモリデータベースの唯一の利点は、高速であり、開発/本番データベースよりも同じデータベースドライバーでテストする方が、実際の環境に近いため、優れている可能性があります。
Playフレームワークでどのように正しく行うことができますか?
試した:
_Map<String, String> settings = new HashMap<String, String>();
settings.put("db.default.url", "jdbc:mysql://localhost/sometestdatabase");
settings.put("db.default.jndiName", "DefaultDS");
app = Helpers.fakeApplication(settings);
_
ここでは進化が機能しているように見えますが、各テストの前にデータベースをクリーンアップするのが最善の方法は何ですか?各テーブルを切り捨てるカスタムコードを作成することによって?テーブルを削除する場合、次のテストの前に進化が再度実行されますか、それとも_play test
_コマンドごとに1回適用されますか?または、Helpers.fakeApplication()
呼び出しごとに1回ですか?
ここでのベストプラクティスは何ですか? dbunit について聞いたことがありますが、それほど苦痛や癖なしに統合することは可能ですか?
まず、テストと本番環境で同じRDBMSを使用することをお勧めします。これにより、見つけにくいバグを回避できるからです。
各テストの間にデータベースをクリーンアップする必要性に関しては、Ebean DdlGenerator
を使用してスクリプトを生成し、クリーンなデータベースを作成し、JUnitの@Before
アノテーションを使用して、すべてのテストの前にこれらのスクリプトを自動的に実行できます。
DdlGenerator
の使用は、次のように実行できます。
EbeanServer server = Ebean.getServer(serverName);
ServerConfig config = new ServerConfig();
DdlGenerator ddl = new DdlGenerator((SpiEbeanServer) server, new MySqlPlatform(), config);
このコードは、テストを継承させることができる基本クラスに配置できます(または、@RunWith
アノテーションで使用できるカスタムRunner
内に配置できます)。
また、ボイラープレートコードを回避して、FakeApplication
の作成を簡単に自動化することもできます。
役立つリンク:
メインデータベースと同じデータベースエンジンを使用し、各テストの前にクリーンアップするために dbunit を使用しました。
public class SomeTest {
// ...
@Before
public void startApp() throws Exception {
// Set up connection to test database, different from main database. Config better should be used instead of hard-coding.
Map<String, String> settings = new HashMap<String, String>();
settings.put("db.default.url", "jdbc:mysql://localhost/somedatabase?characterEncoding=UTF-8&useOldAliasMetadataBehavior=true");
settings.put("db.default.user", "root");
settings.put("db.default.password", "root");
settings.put("db.default.jndiName", "DefaultDS"); // make connection available to dbunit through JNDI
app = Helpers.fakeApplication(settings);
Helpers.start(app);
databaseTester = new JndiDatabaseTester("DefaultDS");
IDataSet initialDataSet = new FlatXmlDataSetBuilder().build(play.Play.application()
.resourceAsStream("/resources/dataset.xml"));
databaseTester.setDataSet(initialDataSet);
databaseTester.onSetup();
}
@After
public void stopApp() throws Exception {
databaseTester.onTearDown();
Helpers.stop(app);
}
}
私のdataset.xml
には、各テストの前にこれらのテーブルを空にするようにdbunitに指示するテーブル名が含まれています。また、器具を含めることもできます。
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<name_of_my_first_table />
<name_of_my_second_table />
</dataset>
このアプローチを使用すると、Evolutionはテストデータベースで自動的に実行されるため、テストデータベースからすべてのテーブルを削除すると、それらが再作成されます。
テーブルをクリーンアップするだけでよい場合は、dbunitを使用するのはやり過ぎです。クエリを直接発行するか、ebean DdlGenerator
を使用してテーブルをクリーンアップできます。しかし、私はデータの比較にもdbunitを使用しています。
Runnable
が必要でRunnable
の実装では例外をスローできないため、Helpers.running
は使用しません。テストには非常に不便です。しかし、running()
のコードを見ると、Helpers.start()
とHelpers.stop()
を呼び出すだけなので、これらのメソッドを@Before
と@After
で直接呼び出します。
テストの実行にH2を使用しないことを決定しました。はい、実行速度は速くなりますが、MySQLとの違いが大きすぎます。
Postgresデータベースのテストを作成したときは、データベースに接続するためのHashMapを作成し、次にテストクエリを作成して、正しい量のレコードが存在することなどを確認しました...これが私のコードです。
@Test
public void testDataBase() {
final HashMap<String,String> postgres = new HashMap<String, String>();
postgres.put("db.default.driver","org.postgresql.Driver");
postgres.put("db.default.url","jdbc:postgresql://localhost/myDataBase");
postgres.put("db.default.user", "postgres");
postgres.put("db.default.password", "password");
running(fakeApplication(postgres), new Runnable() {
@Override
public void run() {
//Insert Assertions Here
}
});
}
誰かがこのアプローチを使用しました(進化をMySQLとH2の両方と互換性を持たせる)?
MySQL固有の機能に対する答えを見つけました: Play 2.xを使用してMySQLデータベースの単体テストを行うにはどうすればよいですか?
に基づいてSlick | JPA | Anormマッピングと関数の両方を検証することが目標である場合は、DBモックを使用することもできます。
適切な場合は、テストDBよりも単体テストに準拠し、管理が容易であるという利点があります(タスクのセットアップ/クリアではなく、同じテストテーブルへのアクセスを回避するためのテストの同期ではありません)。
Anorm自体の仕様で使用されている私のフレームワークAcolyte( http://github.com/cchantep/acolyte )を見ることができます(例: https://github.com /playframework/playframework/blob/master/framework/src/anorm/src/test/scala/anorm/SqlResultSpec.scala )。