test - ¿Cómo probar un origen de datos JNDI burlado con Spring?
spring mock (7)
Configuración Java .....
Caso de prueba 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());
}
}
Soy bastante nuevo en Spring y me pregunto cómo crear pruebas JUnit que utilicen un origen de datos simulado y cómo usar un contexto JNDI con eso. Actualmente mi aplicación usa un contexto JNDI de tomcat para recuperar una conexión y a través de esa conexión recupera datos de una base de datos. Así que supongo que necesito burlarme de las llamadas JNDI y la recuperación de datos. Cualquier buena sugerencia sobre cuál sería la mejor manera de abordar esto sería genial! ¡Muchas gracias!
Puede crear su propio DataSource simulado extendiendo Spring''s AbstractDataSource.
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;
}
}
Yo separaría la búsqueda JNDI de la conexión del resto del código. Inyecte el DataSource en sus objetos de acceso a datos (DAO) y use MockDataSource para probar los DAO.
Puede usar SimpleNamingContextBuilder para hacer que una fuente de datos jndi esté disponible para sus pruebas:
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
builder.bind("java:comp/env/jdbc/mydatasource", dataSource);
builder.activate();
Esto no es exactamente burlarse de la fuente de datos, pero hace que la fuente de datos esté disponible a través de jndi para sus pruebas.
Siempre puede crear una configuración beans.test.xml, donde primero hace referencia a beans.xml y luego anula la configuración del origen de datos:
src / main / resources / 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 Test Class:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/beans.test.xml" })
public class ASRTests
{
...
}
En tu jndi bean, declara la referencia
<jee:jndi-lookup expected-type="javax.sql.DataSource" id="mysqlDataSource" jndi-name="jdbc/mysql"/>
En su bean de prueba, declare el origen de datos
<bean id="mysqlDataSource" ...>
...
</bean>
Tenga en cuenta que debe mover el bean fuente de datos de prueba a la carpeta de prueba.
También puedes usar Simple-JNDI. Es una implementación JNDI en memoria para trabajar con contextos JNDI fuera de un contenedor J2EE. Le permite usar el mismo archivo de definición de bean en producción y prueba. Suponga que esta es su definición de frijol en producción:
<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>
Crea un archivo de propiedades como este
type=javax.sql.DataSource
driverClassName=org.gjt.mm.mysql.Driver
url=jdbc:mysql://localhost/testdb
username=user_name
password=password
Coloque Simple-JNDI y un archivo jndi.properties con una pequeña configuración en su classpath. Luego acceda a su fuente de datos como de costumbre.
org.springframework.jndi.JndiObjectFactoryBean
es el más adecuado para las búsquedas JNDI. Según su documentación, permite inyectar valores predeterminados también para casos de prueba basados en primavera.
Consulte la configuración de resorte a continuación (nombrada como 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>
Agregar bean definido en otro archivo de configuración se referirá a dataSourceFromJndi
bean
<!-- START OF SERVICES -->
<bean class="com.sample.Service" >
<property name="dataSource" ref="dataSourceFromJndi" />
</bean>
La ventaja de este enfoque es que puede mantener 2 archivos de configuración de bases de datos diferentes, uno para producción y otro para pruebas unitarias. Solo importa el correcto. La configuración de prueba contendrá un objeto predeterminado.
Normalmente defino mis dependencias JNDI en un archivo separado, como 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>
Para que en los recursos de prueba pueda crear otro archivo y definir el origen de datos de prueba, me conviene, como 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>
Y luego en mi clase de prueba utilizo la configuración de prueba del origen de datos en lugar de la producción que depende de JNDI:
@ContextConfiguration({
"classpath*:META-INF/spring/datasource-testcontext.xml",
"classpath*:META-INF/spring/session-factory-context.xml"
})
public class MyTest {
}
Si la fuente de datos no está definida en un archivo separado, todavía puede resguardar fácilmente el objeto devuelto por las llamadas JNDI:
- así: Inyectando fuentes de datos JNDI para pruebas JUnit fuera de un contenedor
- o usando clases en el paquete
org.springframework.mock.jndi
, es decir.SimpleNamingContextBuilder
(hay un ejemplo en el javadoc de esta clase).