2015-02-07 102 views
0

我在做我的項目,使用Tomcat 7,JSP,Servlets,Log4jMySQL如何在Java Web應用程序中使用DataSource測試DAO?

我把這個問題用了幾個小時沒有正確的答案。

如何使用DataSourceJUnit來測試我的DAO?

最近我發現了這個article,但不知道如何配置它以達到我的目的,也不知道它是否是一種很好的方法。

我有以下DAO層次: dao hierarchy

而且我通過以下方式獲得DataSourceAbstractRepository

... 
protected final DataSource ds; 
... 
    public AbstractRepository() { 
     DataSource dataSource = null; 
     try { 
      Context initContext = new InitialContext(); 
      dataSource = (DataSource) initContext 
        .lookup("java:/comp/env/jdbc/mydb"); 
     } catch (NamingException ex) { 
      LOG.error("Cannot obtain a connection from the pool", ex); 
     } 
     ds = dataSource; 
    } 
... 

你會產生的方式,一些代碼示例解決這個問題,例如對於Entrant Repository Test

回答

1

您在AbstractRepository中的代碼很難測試。原因是「智能構造函數」,知道他從哪裏獲取數據源。但是你仍然有很多選擇。您可以更改您的代碼(我的選擇),這樣的構造函數接受DataSource作爲參數,如

public AbstractRepository(DataSource dataSource){ 
    this.ds = dataSource; 
} 

這樣你就可以初始化倉庫與一些測試數據源測試環境(模擬?) 。

或者你可以使用一些模擬框架,例如EasyMock,創建你想測試的Repository的部分模擬。 EasyMock默認創建部分模擬類,而不用調用任何構造函數。那麼你可以嘲笑getDataSource()方法(我希望你有一個,用於任何你需要訪問數據源的地方?)返回測試數據源,或者你可以使用Reflections設置最後的ds字段(我猜想更糟糕的選擇)。

+0

我做空構造函數的原因是孩子們可以覆蓋數據源,如果他們需要的話,但如果孩子使用相同的數據庫,它可以使用父數據源。雖然我同意它很難測試。我目前的目標是使用JUnit(不使用其他測試框架) – marknorkin 2015-02-07 12:21:16

+0

來測試它,如果我實現了您提出的構造函數,是否意味着每個孩子還需要使用DataSource參數創建此類構造函數?也許通過連接更好嗎? – marknorkin 2015-02-07 17:33:56

+0

如果唯一聲明的構造函數是'AbstractRepository(DataSource)'構造函數,那麼每個子類將不得不顯式調用'super(DataSource)'。在其構造函數中。我建議在每個擴展'AbstractDatasource'的'MyRepository'中提供'MyRepository(DataSource)'構造函數。您的存儲庫不需要知道'DataSource'來自哪裏。 – AGV 2015-02-07 18:44:55

1

問題是,你的代碼直接從源獲得它的依賴。我提供以前的question的建議與Alexey Gromov的建議類似,但如果由於某些原因您無法更改代碼,那麼您需要在單元測試中執行以下操作:

1)創建子上下文通常會使用Java容器爲您創建(例如Tomcat,Jetty)。可以使用這是我從您的鏈接得到了下面的命令來完成(我驗證了他們的工作):

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

    Context ic = new InitialContext(); 
    ic.createSubcontext("java:"); 
    ic.createSubcontext("java:/comp"); 
    ic.createSubcontext("java:/comp/env"); 
    ic.createSubcontext("java:/comp/env/jdbc"); 

2)你需要你的模擬對象綁定到你的代碼期待的名字。這可以使用InitialContext#bind完成。

ic.bind("java:/comp/env/jdbc/DSTest", mock(DataSource.class)); 

請注意,模擬功能是由Mockito提供的......你可以通過你想要的模擬對象。

在我實際的代碼,我有這樣的:

 mysqlDs = (DataSource) initCtx.lookup("java:/comp/env/jdbc/DSTest"); 
     System.out.println("----mysqlDs = " + mysqlDs + "\n"); 

打印出:

----mysqlDs = Mock for DataSource, hashCode: 1926808117 
+0

謝謝你的回答!我可以重新設計我的代碼。我已經創建了另一個構造函數,並在每個Repository中傳遞給它一個DataSource參數。因此,在我的測試中,我認爲我可以創建MysqlDataSource實例並將其傳遞到測試的存儲庫,但是當試圖運行此測試時,我得到了'NPE'。 – marknorkin 2015-02-07 19:26:56

+0

你在哪裏得到NPE,你如何創建模擬MysqlDataSource? – 2015-02-07 19:35:52

+0

'MysqlDataSource ds = new MysqlDataSource(); ds.setServerName(「localhost」); ds.setPort(3306); ds.setDatabaseName(「mydb」); ds。SETUSER( 「根」); ds.setPassword(「password」); userRepository = new UserRepository(ds);' 我正在用JUnit測試它。這就是我在'BeforeClass'中創建數據源的方式。 NPE正在投入創建,更新,刪除,查找方法。所以我認爲我沒有正確地獲得MysqlDataSource – marknorkin 2015-02-07 19:42:13

0

隨着TomcatJNDI您可以輕鬆地從你的類中訪問Tomcat JNDI環境,當你的應用程序將運行在Tomcat內。 TomcatJNDI利用Tomcat的JNDI系統並通過處理原始的Tomcat配置文件對其進行配置。它的使用很簡單,例如。 G。

TomcatJNDI tomcatJNDI = new TomcatJNDI(); 
tomcatJNDI.processContextXml(contextXmlFile); 
tomcatJNDI.processWebXml(webXmlFile); 
tomcatJNDI.start(); 

此後,您可以按照習慣查找數據源。 More information can be found here.

相關問題