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をバインドする方法を知りたいと思います。
その例も間違っていることがわかりました。これでうまくいきました。
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:」の後の「/」が間違っているため、そこにあるべきではないということです。
数年前にこのようなことを最後に試しましたが、ようやく諦めてリファクタリングしました。その時点では、コンテナーの外にDataSourceを作成できませんでした。たぶん、今、誰かが何かをあざけっているかもしれません。
それでもにおいがします... DataSourcesやJNDIルックアップなどに直接依存する「ビジネスロジック」コードはありません。これで、コードの外で一緒に配線することができます。
あなたのデザインはどの程度柔軟ですか?テスト対象のコードがDataSourceに直接依存している(または独自の接続を取得している)場合は、リファクタリングします。接続を注入すると、インメモリ実装を使用していても、プレーンな古いJDBCで好きなようにすべてをテストでき、それを行うために多くの不必要な(テストのために)インフラストラクチャを用意する必要がなくなります。