¿Cómo probar un origen de datos JNDI burlado con Spring?

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!

Normalmente defino mis dependencias JNDI en un archivo separado, como datasource-context.xml :

    

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 :

    

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 fonts 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).

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.

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 rest del código. Inyecte el DataSource en sus objetos de acceso a datos (DAO) y use MockDataSource para probar los DAO.

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

   

src / test / resources / beans.test.xml

   

JUnit Test Class:

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

En tu jndi bean, declara la referencia

  

En su bean de prueba, declare el origen de datos

  ...  

Tenga en cuenta que debe mover el bean fuente de datos de prueba a la carpeta de prueba.

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 spring.

Consulte la configuración de resorte a continuación (nombrada como spring-test-db-config.xml)

           

Agregar bean definido en otro archivo de configuración se referirá a 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.

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

}

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:

       

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í.

    Intereting Posts