2011-05-09 51 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.

相关问题