argius note

プログラミング関連

Cayenne(3.0.2)でUnitTestするときにテスト用のデータソースを設定する

Apache CayenneでUnitテストを実行する際のガイドが下記ページにあります。

ここで、UnitTestのときにデータソースを切り替える方法が書かれていて、"-DcayenneTestConnection"もしくは"-Dcayenne.test.connection"を使うとなっています。が、これがうまく行きません。
考えた末、別の方法でやることにしました。



実行環境は、OS=Win7HomePremiumと下記。

ソフト バージョン
JDK 1.6.0_29
Maven 3.0.3
Wicket 1.5.3
Cayenne 3.0.2

設定方法は、 (Apache) Wicket+CayenneでWebアプリを参照。


前提

WicketのWicketTesterでassertRenderedPageを使ってテストします。「ページを初期表示する際にデータベースから先頭10件を表示する」という機能のページがあったとして、そのテストを実行するとCayenneで動作する部分も動きます。
運用環境はJDBCデータソースで接続先を決定していますので、DataSourceFactoryは"JNDIDataSourceFactory"に設定されています。単体で実行するときにはJNDIを使いたくないor使えないので、このときだけ別の接続設定を適用したい。ただし、煩雑かつ誤登録などのミスを防ぐためにもCayenneの設定は変更したくない。
本家のガイドでは、これを実現する方法として

$ mvn test -DcayenneTestConnection=conn1

というオプションの説明がされています。
ところがこれが上手くいかず、あれこれ悩んだ結果、別の方法でやってみることにしました。

"cayenneTestConnection"を使えるようにするには

ガイドのページには、

Cayenne provides a comprehensive suite of unit tests. To execute unit tests you must first get Cayenne from SVN, install JDK 1.5 and obtain the latest Maven.

Apache Cayenne » Running Unit Tests

と書かれています。Mavenリポジトリ検索やSVNなどを見てざっと調べたところでは、どうやらこの機能は"cayenne-jdk1.5-unpublished"という非リリース?のアーティファクトに含まれる機能のようです。
さすがに面倒すぎるので、コア機能になることを期待しつつ、この方法はパス。

方法その1:テストケースに直接切り替え処理を書く

公式のWikiに書いてある方法です。

まずは説明のとおり、$HOME/.cayenne/connection.propertiesに

postgres.cayenne.adapter = org.apache.cayenne.dba.postgres.PostgresAdapter
postgres.jdbc.driver = org.postgresql.Driver
postgres.jdbc.url = jdbc:postgresql://localhost:5432:mydb
postgres.jdbc.username = username
postgres.jdbc.password = password

と記述します。
次にBasePageTestを作ります。スーパークラスの@BeforeClassで呼び出すことで、テストの最初に呼ばれることになります(...なるはず)。各ページのテストケースはこれを継承すれば、WicketTesterの初期化も一ヶ所でできて一石二鳥です。

import java.sql.*;

import org.apache.cayenne.conf.*;
import org.apache.cayenne.conn.*;
import org.apache.wicket.util.tester.*;
import org.junit.*;

public class BasePageTest {

    protected WicketTester tester;

    @BeforeClass
    public static void initializeDataSource() throws SQLException {
        ConnectionProperties connprop = ConnectionProperties.getInstance();
        DataSourceInfo dsinfo = connprop.getConnectionInfo("postgres");
        DriverDataSource ds = new DriverDataSource(dsinfo.getJdbcDriver(),
                                                   dsinfo.getDataSourceUrl(),
                                                   dsinfo.getUserName(),
                                                   dsinfo.getPassword());
        // ↓これが無いとConfiguration.getSharedConfiguration()でエラーになる
        Configuration.initializeSharedConfiguration(new DefaultConfiguration() {
            {
                setIgnoringLoadFailures(true);
            }
        });
        Configuration.getSharedConfiguration().getDomain().getNode("Node1").setDataSource(ds);
    }

    @Before
    public void setUp() throws Exception {
        tester = new WicketTester(new WicketApplication());
    }

}

"setIgnoringLoadFailures(true)"の箇所は、Configuration.getSharedConfiguration()を実行したときにJNDI参照できないとエラーになってしまいますので、それを無視して処理を続行するための仕掛けです。
実はこれが一番苦労したところです。
modelerのpreference-"Local DataSources"の設定を使えたら良いのにと思ってちょっとだけ調べたら、コア(cayenne-server)の機能にmodelerの機能が依存してしまうことになるので簡単じゃなさそうです。

方法その2:簡易JNDIサーバを立てる

「JNDIサーバが無いなら作ればいいじゃない」という方法です。
JUnitテストで使う即席のJNDIデータソースを用意するを参照してください。


ちょっとてこずりましたが、副産物が色々とあったのでやってみた甲斐はありました。