如何用Springtesting一个模拟的JNDI数据源?

我对Spring相当陌生,想知道如何创build使用模拟数据源的JUnittesting,以及如何使用JNDI上下文? 目前我的应用程序使用来自tomcat的JNDI上下文来检索连接,并通过该连接从数据库中检索数据。 所以我想我需要模拟JNDI调用和数据检索。 任何好的方法来解决这个问题的方法是非常好的! 非常感谢!

我通常在独立文件中定义我的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> 

因此,在testing资源中,我可以创build另一个文件并定义testing数据源,但是它适合我,比如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> 

然后在我的testing类中使用数据源的testingconfiguration,而不是生产依赖于JNDI的configuration:

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

如果数据源未在单独的文件中定义您仍然可以轻松地对由JNDI调用返回的对象进行存根:

  • 像这样: 在容器之外注入JUnittesting的JNDI数据源
  • 或者在包org.springframework.mock.jndi使用类。 SimpleNamingContextBuilder (在这个calass的javadoc中有一个例子)。

您可以使用SimpleNamingContextBuilder将jndi数据源提供给您的testing:

  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为您的testing提供数据源。

你可以通过扩展Sp​​ring的AbstractDataSource来创build自己的模拟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查找。 将DataSource注入到数据访问对象(DAO)中,并使用MockDataSource来testingDAO。

您可以总是创build一个beans.test.xmlconfiguration,您首先引用beans.xml,然后覆盖数据源configuration:

SRC /主/资源/的beans.xml

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

SRC /testing/资源/ beans.test.xml

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

JUnittesting类:

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

在你的jndi bean中,声明引用

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

在你的testingbean中,声明数据源

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

请记住将testing数据源bean移动到testing文件夹中。

Spring的org.springframework.jndi.JndiObjectFactoryBean最适合于JNDI查找。 按照它的文档,它允许为基于spring的testing用例注入默认值。

参考下面的springconfiguration(命名为spring-test-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> 

定义在其他configuration文件上的bean应该引用dataSourceFromJndi bean

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

这种方法的优点是可以保存2个不同的DBconfiguration文件 – 一个用于生产,另一个用于unit testing。 只要input正确的一个。 testingconfiguration将包含一个默认对象。

Javaconfiguration…..

Junittesting用例

 @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()); } 

}

你也可以使用Simple-JNDI。 这是一个内存JNDI实现,用于处理J2EE容器之外的JNDI上下文。 它允许您在生产和testing中使用相同的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> 

像这样创build一个属性文件

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

把Simple-JNDI和一个jndi.properties文件放在你的类path中。 然后照常访问你的数据源。

更多关于Simple-JNDI的信息可以在这里find。