JUNITからDataSourceを利用するためには

やることは、
 1. 自前でinitialcontextを作成して、JNDIにbindしてあげる。

JNDIへのbindingには、TomcatのNamingを利用するので、いつもの通り、pom.xmlに記述して取得する。
DataSourceの取得といったらconnectionの取得なので、ついでにcommons-dbcpを利用してconnection poolingするようなつくりにする。

pom.xml

        <dependency>
            <groupId>tomcat</groupId>
            <artifactId>naming-java</artifactId>
            <version>5.0.28</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>tomcat</groupId>
            <artifactId>naming-factory</artifactId>
            <version>5.5.23</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>tomcat</groupId>
            <artifactId>naming-resources</artifactId>
            <version>5.5.23</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>[1.,)</version>
            <scope>test</scope>
        </dependency> 


そうしたら、Google-guiceでDataSourceにBindするようにAbstractModuleを記述する。
ここでは、test用として自前でJNDIにbindするconfigureTestを追加で作成している。

public abstract class AbstractDataSourceModule extends AbstractModule {

    /**
     * commons-dbcpのプロパティを取得します。
     * 
     * @return
     */
    abstract protected Properties getProperties();

    /**
     * JNDI名称を取得します。
     * 
     * @return
     */
    abstract protected String getJndiName();

    protected void configureTest() {
        final String jndiNamePrefix = "java:/comp/env/";
        String absoluteJndiName = jndiNamePrefix + getJndiName();

        try {
            // commons-dbcpによるdataSourceの生成
            DataSource dataSource =
                BasicDataSourceFactory.createDataSource(getProperties());

            // Contextの生成
            System.setProperty(
                Context.INITIAL_CONTEXT_FACTORY,
                "org.apache.naming.java.javaURLContextFactory");
            System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");

            InitialContext ic = new InitialContext();
            ic.createSubcontext("java:");
            ic.createSubcontext("java:/comp");
            ic.createSubcontext("java:/comp/env");
            ic.createSubcontext("java:/comp/env/jdbc");
            ic.bind(absoluteJndiName, dataSource);

            // Bind IntialContext
            bind(Context.class).toInstance(ic);

            // Bind DataSource
            bind(DataSource.class)
                .annotatedWith(Names.named(getJndiName()))
                .toProvider(
                    JndiIntegration
                        .fromJndi(DataSource.class, absoluteJndiName));
            bind(DataSource.class).toProvider(
                JndiIntegration.fromJndi(DataSource.class, absoluteJndiName));
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (NamingException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void configure() {
        final String jndiNamePrefix = "java:/comp/env/";
        String absoluteJndiName = jndiNamePrefix + getJndiName();

        try {
            InitialContext ic = new InitialContext();

            // Bind IntialContext
            bind(Context.class).toInstance(ic);

            // Bind DataSource
            bind(DataSource.class)
                .annotatedWith(Names.named(getJndiName()))
                .toProvider(
                    JndiIntegration
                        .fromJndi(DataSource.class, absoluteJndiName));
            bind(DataSource.class).toProvider(
                JndiIntegration.fromJndi(DataSource.class, absoluteJndiName));
        } catch (NamingException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

AbstractDataSourceModuleを継承してOracle用のパラメーター設定をサブクラスに定義する。

public class OracleDataSourceModule extends AbstractDataSourceModule {

    Object[][] dbcpProperties =
        {
            {
                "driverClassName",
                "oracle.jdbc.pool.OracleConnectionPoolDataSource" },
            { "url", "jdbc:oracle:thin:@127.0.0.1:1521:orcl" },
            { "username", "ELLECTRA" },
            { "password", "PASSWORD" },
            { "initialSize", "30" },
            { "maxActive", "100" },
            { "maxIdel", "30" },
            { "maxWait", "500" } };

    String jndiName = "jdbc/hoge";

    @Override
    protected String getJndiName() {
        return jndiName;
    }

    @Override
    protected Properties getProperties() {
        Properties properties = new Properties();
        for (Object[] prop : dbcpProperties) {
            properties.put(prop[0], prop[1]);
        }
        return properties;
    }
}

さらにテスト用でconfigureTest()でconfigureするように書き換える。

public class OracleDataSourceModuleTest extends OracleDataSourceModule {

    @Override
    protected void configure() {
        configureTest();
    }
}

これで、前回のTestRunnerを利用すれば、ModuleにOracleDataSourceModuleを指定していも、JUnit時は、OracleDataSourceModuleTestが呼ばれる。

こういう暗黙的ルールは良いのか悩みどころです。