我正在尝试对数据库“worker”类运行JUnit测试,这些类在InitialContext
上进行jndi查找以获得DataSource
。工作类通常在Glassfish v3 App Server上运行,该服务器定义了适当的jdbc资源。
代码在App Server上部署时运行得很好,但是没有从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);
worker类能够找到DataSource,但是没有给出错误,说“用户名无法登录到服务器”。
如果我将我在JUnit方法中创建的DataSource直接传递给worker,它可以连接并运行查询。
所以,我想知道如何绑定一个可以由worker类查找而不在Web容器中的DataSource。
答案 0 :(得分:1)
几年前,当我上次尝试这样的事情时,我终于放弃并重构了:在那一点上,你无法在容器之外创建一个DataSource。也许你可以,现在,也许有人嘲笑某事。
然而,这闻起来......你不应该有任何“业务逻辑”代码直接依赖于DataSources或JNDI查找等。这些都是在代码之外连接在一起的管道。
您的设计有多灵活?如果您测试的代码直接依赖于DataSource(甚至获得自己的Connection),请重构它。通过注入连接,您可以使用普通的JDBC来测试所有您喜欢的内容,即使使用内存中实现,也可以避免支持大量不必要的(对于测试,无论如何)基础结构。
答案 1 :(得分:1)
我发现这个例子也是错误的。这对我有用。
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:'之后的'/'是错误的,不应该在那里。