web-dev-qa-db-ja.com

JUnitテスト用にDataSourceをInitialContextにバインドするにはどうすればよいですか?

InitialContextでjndiルックアップを実行してDataSourceを取得するデータベース「ワーカー」クラスでJUnitテストを実行しようとしています。ワーカークラスは通常、適切なjdbcリソースが定義されているGlassfish v3アプリケーションサーバーで実行されます。

アプリサーバーにデプロイするとコードは問題なく実行されますが、JUnitテストリソースからは実行されません。明らかに、jndiリソースを見つけることができないためです。したがって、データソースを適切なコンテキストにバインドするテストクラスでInitialContextを設定しようとしましたが、機能しません。

ここに私がテストに持っているコードがあります

_@BeforeClass
public static void setUpClass() throws Exception {
    try {
        // Create initial 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");

        // Construct DataSource
        SQLServerConnectionPoolDataSource testDS = new SQLServerConnectionPoolDataSource();
        testDS.setServerName("sqlserveraddress");
        testDS.setPortNumber(1433);
        testDS.setDatabaseName("dbname");
        testDS.setUser("username");
        testDS.setPassword("password");

        ic.bind("Java:/comp/env/jdbc/TestDS", testDS);

        DataWorker dw = DataWorker.getInstance();
    } catch (NamingException ex) {
        Logger.getLogger(TitleTest.class.getName()).log(Level.SEVERE, null, ex);
    }
}
_

次に、DataWorkerクラスには、多かれ少なかれ次のコードを持つメソッドがあります

_InitialContext ic = null;
DataSource ds = null;
Connection c = null;
PreparedStatement ps = null;
ResultSet rs = null;
String sql = "SELECT column FROM table";
try{
    ic = new InitialContext();
    ds = (DataSource) ic.lookup("jdbc/TestDS");
    c = ds.getConnection();
    ps = c.prepareStatement(sql);
    // Setup the Prepared Statement
    rs = ps.executeQuery();
    if(rs.next){
        //Process Results
    }
}catch(NamingException e){
    throw new RuntimeException(e);
}finally{
    //Close the ResultSet, PreparedStatement, Connection, InitialContext
}
_

変更した場合
ic.createSubContext("Java:/comp/env/jdbc");
ic.bind("Java:/comp/env/jdbc/TestDS",testDS);

ic.createSubContext("jdbc");
ic.bind("jdbc/TestDS",testDS);
ワーカークラスはDataSourceを見つけることができますが、「ユーザー名がサーバーにログインできませんでした」というエラーが表示されて失敗します。

JUnitメソッドで作成したDataSourceを直接ワーカーに渡すと、接続してクエリを実行できます。

つまり、Webコンテナーに存在せずにワーカークラスでルックアップできるDataSourceをバインドする方法を知りたいと思います。

16
Rambo Commando

その例も間違っていることがわかりました。これでうまくいきました。

ic.createSubcontext("Java:comp");
ic.createSubcontext("Java:comp/env");
ic.createSubcontext("Java:comp/env/jdbc");

final PGSimpleDataSource ds = new PGSimpleDataSource();
ds.setUrl("jdbc:postgresql://localhost:5432/mydb");
ds.setUser("postgres");
ds.setPassword("pg");

ic.bind("Java:comp/env/jdbc/mydb", ds);

違いは、各コンテキストの「Java:」の後の「/」が間違っているため、そこにあるべきではないということです。

1
MarcD

数年前にこのようなことを最後に試しましたが、ようやく諦めてリファクタリングしました。その時点では、コンテナーの外にDataSourceを作成できませんでした。たぶん、今、誰かが何かをあざけっているかもしれません。

それでもにおいがします... DataSourcesやJNDIルックアップなどに直接依存する「ビジネスロジック」コードはありません。これで、コードの外で一緒に配線することができます。

あなたのデザインはどの程度柔軟ですか?テスト対象のコードがDataSourceに直接依存している(または独自の接続を取得している)場合は、リファクタリングします。接続を注入すると、インメモリ実装を使用していても、プレーンな古いJDBCで好きなようにすべてをテストでき、それを行うために多くの不必要な(テストのために)インフラストラクチャを用意する必要がなくなります。

1
Rodney Gitzel