2011-05-09 79 views
27

我對Spring相當陌生,想知道如何創建使用模擬數據源的JUnit測試以及如何使用JNDI上下文來處理這些測試?目前,我的應用程序使用來自tomcat的JNDI上下文來檢索連接,並通過該連接從數據庫中檢索數據。所以我想我需要模擬JNDI調用和數據檢索。對於解決這個問題的最佳方法,任何好的指針都會很棒!非常感謝!如何用Spring測試一個模擬的JNDI數據源?

回答

30

我通常是在單獨的文件中定義我的JNDI的依賴,就像datasource-context.xml

<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:jee="http://www.springframework.org/schema/jee" 
    xmlns:p="http://www.springframework.org/schema/p" 
    xsi:schemaLocation=" 
     http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
     http://www.springframework.org/schema/jee 
     http://www.springframework.org/schema/jee/spring-jee-3.0.xsd"> 

    <jee:jndi-lookup id="dataSource" 
     jndi-name="java:comp/env/dataSource" 
     expected-type="javax.sql.DataSource" /> 

</beans> 

因此,在測試資源,我可以創建另一個文件,並定義測試數據源但它適合我,就像datasource-testcontext.xml

<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:p="http://www.springframework.org/schema/p" 
    xsi:schemaLocation=" 
     http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> 

    <bean id="dataSource" 
     class="org.springframework.jdbc.datasource.DriverManagerDataSource" 
     p:driverClassName="org.hsqldb.jdbcDriver" 
     p:url="jdbc:hsqldb:hsql://localhost:9001" 
     p:username="sa" 
     p:password="" /> 

</beans> 

然後在我的測試類I 中使用數據源的測試配置,而不是依賴於JNDI的產品

@ContextConfiguration({ 
    "classpath*:META-INF/spring/datasource-testcontext.xml", 
    "classpath*:META-INF/spring/session-factory-context.xml" 
}) 
public class MyTest { 

} 

如果數據源不是在一個單獨的文件仍然可以存根通過JNDI返回的對象定義容易調用:

+0

我這樣做了,但我仍然收到異常導致:javax.naming.NoInitialContextException:需要在環境或系統屬性中,或作爲applet參數或應用程序資源文件中指定類名稱:java.naming.factory .initial – fastcodejava 2012-07-30 00:29:22

+0

@fastcodejava你做了什麼?用於JNDI相關配置的單獨文件?在測試設置中創建了JNDI上下文?或者使用'SimpleNamingContextBuilder'? – Roadrunner 2012-08-10 18:40:09

5

您可以通過擴展Sp​​ring的AbstractDataSource來創建自己的模擬DataSource。

import java.sql.Connection; 
import java.sql.SQLException; 

import org.springframework.jdbc.datasource.AbstractDataSource; 

/** 
* Mock implementation of DataSource suitable for use in testing. 
* 
* 
*/ 
public class MockDataSource extends AbstractDataSource { 
    private Connection connection; 

    /** 
    * Sets the connection returned by javax.sql.DataSource#getConnection() 
    * and javax.sql.DataSource#getConnection(java.lang.String, java.lang.String) 
    * 
    * @param connection 
    */ 
    public void setConnection(Connection connection) { 
     this.connection = connection; 
    } 

    /* 
    * (non-Javadoc) 
    * @see javax.sql.DataSource#getConnection() 
    */ 
    public Connection getConnection() 
      throws SQLException { 
     return connection; 
    } 

    /* 
    * (non-Javadoc) 
    * @see javax.sql.DataSource#getConnection(java.lang.String, java.lang.String) 
    */ 
    public Connection getConnection(String username, String password) 
      throws SQLException { 
     return connection; 
    } 
} 

我想將連接的JNDI查找與其餘代碼分開。將數據源注入數據訪問對象(DAO)並使用MockDataSource來測試DAO。

+0

如果我注入數據源,將這種無法消除JNDI查找的需求? – Marco 2011-05-09 20:10:27

+0

它可以。在Spring中有很多方法來獲取數據源。一旦你有了它,你可以注入。不過,Spring可以從JNDI讀取一個DataSource。 – 2011-05-09 20:30:22

+1

我編輯了您的答案以刪除第一行的縮進。現在語法突出顯示工作。我希望你不介意。 – 2011-05-09 21:27:20

31

您可以使用SimpleNamingContextBuilder使可用的JNDI數據源到你的測試:

SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); 
    builder.bind("java:comp/env/jdbc/mydatasource", dataSource); 
    builder.activate(); 

https://fisheye.springsource.org/browse/spring-framework/spring-test/src/main/java/org/springframework/mock/jndi/SimpleNamingContextBuilder.java?hb=true

這不正是嘲諷數據源,但它確實使現有數據源通過jndi進行測試。

+0

我這樣做了,但我仍然收到異常導致:javax.naming.NoInitialContextException:需要在環境或系統屬性中,或作爲applet參數或應用程序資源文件中指定類名稱:java.naming.factory 。初始 – fastcodejava 2012-07-30 00:30:08

2

可以八方通創建beans.test.xml配置,您首先引用beans.xml中,然後覆蓋數據源配置:

的src /主/資源/的beans.xml

<!-- Database configuration --> 
<import resource="beans.datasource.jndi.xml" /> 

src/test/resources/beans.test。XML

<import resource="beans.xml" /> 
<import resource="beans.datasource.test.xml" /> 

JUnit測試類:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:/beans.test.xml" }) 
public class ASRTests 
{ 
... 
} 

在你的JNDI豆,申報參考

<jee:jndi-lookup expected-type="javax.sql.DataSource" id="mysqlDataSource" jndi-name="jdbc/mysql"/> 

在您的測試豆,申報數據源

<bean id="mysqlDataSource" ...> 
... 
</bean> 

保持記住移動測試數據源將bean放入測試文件夾。

1

Spring的org.springframework.jndi.JndiObjectFactoryBean最適合用於JNDI查找。按照其文檔,它允許爲基於彈簧的測試用例注入默認值。

請參考下面的彈簧結構(命名爲彈簧測試-DB-config.xml中)

<bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource"> 
    <property name="URL" value="jdbc:oracle:thin:@localhost:1521:XE"/> 
    <property name="user" value="UNITTEST"/> 
    <property name="password" value="UNITTEST"/> 
</bean> 

<bean id="dataSourceFromJndi" class="org.springframework.jndi.JndiObjectFactoryBean"> 
    <!-- Any junk value will suffice as that is always gonna throw NamingException --> 
    <property name="jndiName" value="jdbc/Ds"/> 
    <property name="defaultObject" ref="dataSource"/> 
</bean> 

添加上其它配置文件中定義的豆應指dataSourceFromJndi

<!-- START OF SERVICES --> 
<bean class="com.sample.Service" > 
    <property name="dataSource" ref="dataSourceFromJndi" /> 
</bean> 

的這種方法的優點是可以保存2個不同的DB配置文件 - 一個用於生產,另一個用於單元測試。只需導入正確的一個。測試配置將包含一個默認對象。

0

Java的配置.....

JUnit測試用例

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = {DatabaseConfigStub.class}, loader= AnnotationConfigContextLoader.class) 
public class DatabaseConfigTest { 

@Autowired 
private DataSource datasource; 
@Autowired 
private JdbcTemplate jdbcTemplate; 


@Before 
public void setUp() throws Exception { 

} 

@After 
public void tearDown() throws Exception { 
} 

@Test 
public void testDataSource() { 
    assertNotNull(datasource); 
    assertNotNull(jdbcTemplate); 
} 

} 

DatabaseConfigStub

public class DatabaseConfigStub { 

private static final Logger log = Logger.getLogger(DatabaseConfigStub.class); 

     private static final String DS_NAME = "jdbc/DS_NAME"; 

@Bean 
DataSource dataSource() { 
    JndiObjectFactoryBean jndiObjectBean = EasyMock.createMock(JndiObjectFactoryBean.class); 
    jndiObjectBean.setJndiName(DS_NAME); 
    jndiObjectBean.setResourceRef(true); 
    jndiObjectBean.setProxyInterfaces(DataSource.class); 

    EasyMock.expect((DataSource)jndiObjectBean.getObject()).andReturn(new DataSource() { 

      public <T> T unwrap(Class<T> iface) throws SQLException { 
       // TODO Auto-generated method stub 
       return null; 
      } 

      public boolean isWrapperFor(Class<?> iface) throws SQLException { 
       // TODO Auto-generated method stub 
       return false; 
      } 

      public void setLoginTimeout(int seconds) throws SQLException { 
       // TODO Auto-generated method stub 

      } 

      public void setLogWriter(PrintWriter out) throws SQLException { 
       // TODO Auto-generated method stub 

      } 

      public int getLoginTimeout() throws SQLException { 
       // TODO Auto-generated method stub 
       return 0; 
      } 

      public PrintWriter getLogWriter() throws SQLException { 
       // TODO Auto-generated method stub 
       return null; 
      } 

      public Connection getConnection(String username, String password) 
        throws SQLException { 
       // TODO Auto-generated method stub 
       return null; 
      } 

      public Connection getConnection() throws SQLException { 
       // TODO Auto-generated method stub 
       return null; 
      } 
     } 
    ); 
    EasyMock.replay(jndiObjectBean); 

    return (DataSource) jndiObjectBean.getObject(); 
} 

@Bean 
JdbcTemplate jdbcTemplate(){ 
    return new JdbcTemplate(dataSource()); 
} 

}

0

您還可以使用簡單的JNDI。這是一個內存JNDI實現,用於處理J2EE容器之外的JNDI上下文。它允許您在生產和測試中使用相同的bean定義文件。假設這是你的bean定義中的生產:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> 
    <property name="jndiName" value="java:comp/env/jdbc/DataSource"/> 
</bean> 
<bean id="dao" class="my.Dao"> 
    <property name="dataSource" ref="dataSource" /> 
</bean> 

創建一個屬性文件這樣

type=javax.sql.DataSource 
driverClassName=org.gjt.mm.mysql.Driver 
url=jdbc:mysql://localhost/testdb 
username=user_name 
password=password 

將簡單JNDI和jndi.properties在classpath中一個小的配置文件。然後照常訪問您的數據源。

More about Simple-JNDI is found here.

相關問題