2010-08-11 16 views
15

我試圖在InitialContext上執行jndi查找以獲得DataSource的數據庫「worker」類上運行JUnit測試。工作者類通常在Glassfish v3 App Server上運行,該服務器具有相應的jdbc資源定義。如何將DataSource綁定到InitialContext以進行JUnit測試?

代碼在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);
工人階級是能夠找到數據源,但未能給出一個錯誤,指出「用戶名無法登錄到服務器」。

如果我將在JUnit方法中創建的DataSource直接傳遞給worker,它可以連接並運行查詢。

所以,我想知道如何綁定一個DataSource,可以被工作人員類查找而不在Web容器中。

回答

1

當我上次在幾年前嘗試過這樣的事情時,我終於放棄了重構:在這一點上,您不能在容器外創建一個DataSource。也許你現在可能會有人嘲笑某事。

不過,這種氣味......你不應該有任何「業務邏輯」代碼直接依賴於DataSources或JNDI查找等。這就是要將所有代碼連接在一起。

您的設計有多靈活?如果你的代碼被直接依賴於一個數據源(甚至獲得它自己的連接),則重構它。通過注入連接,您可以使用普通的舊JDBC來測試所有您喜歡的東西,即使使用內存中的實現,也不必爲支持大量不必要的(用於測試,無論如何)支持。

0

我發現這個例子也是錯誤的。這對我有效。

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:」在每個上下文是錯誤的,不應該存在。