JUnitなどでのテストのときJNDIから例えばDataSourceを引っ張りたいときどうするか

JNDIからリソースを引っ張ってくるコードのテストが書きたい


JNDIからDataSourceなどのリソースを取得するコードをテストしたいとき、JNDIの実装を用意したくなります。

例えばこんなコードです。

Context context = new InitialContext();
DataSource ds = (DataSource)context.lookup("java:comp/env/jdbc/mysql");
Connection con = ds.getConnection();


こういうコードをテストするときは当然ですけどコンテナなしで動かしたいです。

いろんな方法がある


調べてみるといろいろな方法があります。

例えば、TomcatのJNDI実装を使う方法とか、

http://d.hatena.ne.jp/yone098/20100330/1269929119

SimpleJNDI とかいう実装があったりとか、

http://code.google.com/p/osjava/wiki/SimpleJNDI

JNDI DataSource helper package とかいうDataSourcesのプロバイダがあったりとか、

https://www.coderanch.com/how-to/java/CodeBarnLibrariesAndFrameworks

そんな感じです。

mavenで引っ張れるのと、なんとなく名前に引かれて、私はSimpleJNDIをしばらく使っていましたが、プロパティーファイル用意したりとか、なんかいろいろシステムプロパティー設定しないといけなかったりとかちょっと大げさだなぁと思っていました。

なんかちょっと大げさ→車輪の再発明


というわけで僕がやりたいのは、
単純に
  • テストケースの中で指定した名前に任意のオブジェクトがbindできて
  • それがコード内でlookupできる
というだけなので、それだけができるMockなJNDIを作りました。
ライブラリ、というかサンプルです。



public class JUnitJndiTest {
 
    @ClassRule
    public static JndiRule jndi = new JndiRule() {
        @Override
        protected void bind(Context context) throws NamingException {
            context.bind("someobj", new Object());
            context.bind("somestring", "abc");
            
            Context cx = context.createSubcontext("java:/comp/env");
            cx.bind("jdbc/mysql", "MysqlDatasource");
        }
    };

    @Test
    public void lookup() throws NamingException {
        assertThat(new InitialContext().lookup("someobj"), is(notNullValue(Object.class)));
        assertThat((String)new InitialContext().lookup("somestring"), is("abc"));
    }
}


ついでに、JUnit4から簡単に使えるようにExternalResourceにしてみました。
lookupとbindと、なんちゃって実装ではありますが、createSubContextが動きます。
他は動きません。

多分ソースコード中で、JNDI を lookupする場所ってそんなに多くないのでlookupの方法は限定できるでしょうし、Contextオブジェクトってそんなに複雑な使われ方はあんまりしないと思うんです。(気のせいでしょうか。

なので、lookupの仕方に合わせてbindしてあげることができれば、ほとんどOKなんじゃないかなぁと思っています。

JNDI使用するコードのテストで悩んだひとは、参考にしてもらえるとうれしいです。

コメント