with test run mock example spring testing junit mocking datasource

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

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

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.

Más sobre Simple-JNDI se encuentra aquí.


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: