02-10-2006 Raul Vicente
Hace poco estuve en una reunión con mi colega Luis y me comento que había oído que Spring daba soporte a los Test Unitarios y que se integraba perfectamente con JUnit pero que no sabía muy bien cómo iba. La verdad es que no he posteado sobre esto antes porque no se me había ocurrido que puediera ser interesante pero visto que se me hace una petición aquí teneís el resultado.
Me imagino que muchos habreís utilizado antes herramientas XUnit en Java la más usada y conocida es JUnit ya que viene con los IDE Eclipse y WebSphere entre otros.
En JUnit un test es una clase que extiende la clase TestCase y cada uno de los test que testean los métodos de la clase tienen la forma testXXX(). Ahora que os he puesto un poco harina, vamos con los beneficios de Spring, para empezar una cosa que no aporta JUnit es inyección de dependencias y otro problema asociado es que si el método que testeo inserta tuplas en una BD, ¿que hago con las tuplas basura que se quedan de los tests?
Bien pues Spring soluciona estos problemas de manera contundente y natural para el programador. En vez de extender TestCase el programador deberá extender o AbstractDependencyInjectionSpringContextTests o bien AbstractTransactionalDataSourceSpringContextTests.
El primer test simplemente soporta inyección de dependecias mientras que el segundo crea una transacción por cada uno de los métodos que accedan a la BD y hace Rollback al final de cada test, pero obliga a declarar un Data Source en el contexto de la aplicación como es lógico y te da acceso a la template de jdbc para poder lanzar consultas y compararlas con los resultados de los métodos de la lógica de negocio. En definitiva el primer test es más básico que el segundo.
Para inyectar un objeto en una clase test basta con crear un atributo en la clase y llamarle con el identificador que se le ha asignado a ese bean en el applicationContext.xml y crear un método get y set para ese atributo (como siempre) y ahora viene la novedad hay que añadir un método String[] getConfigLocations() que devuelva un String con el path donde se encuentra el archivo applicationContext.xml para que sepa de dónde tiene que leer para generar los beans y voilá magic Andreu ya tenemos nuestro Test con Spring.
Como el movimiento se demuestra andando aquí teneís un ejemplo de un proyectillo que hice yo:
public class AplicacionFacadeImplTest extends
AbstractTransactionalDataSourceSpringContextTests {
private AplicacionFacade aplicacionFacade;
public void setAplicacionFacade(AplicacionFacade aplicacionFacade) {
this.aplicacionFacade = aplicacionFacade;
}
protected String[] getConfigLocations() {
return new String[] { “/org/cim/core/domain/logic/applicationContext.xml” };
}
public void testGetAplicaciones() {
List lista = this.aplicacionFacade.getAplicaciones();
System.out.println(lista.size());
assertNotNull(lista);
}
Para los que esteís interesados en indagar más la URL original es:
http://static.springframework.org/spring/docs/2.0.x/reference/testing.html
1. Rafael Perez | septiembre 27th, 2007 at 6:19 pm
Interesante articulo Raul, permite conocer como podemos explortar de mejor manera las bondades de JUnit al momento de generar pruebas unitarias con la inyeccion de dependencias y a la vez hacer pruebas cn el manejo de BD y no solamente con negocio.
Gracias por tu aportacion.
2. Raúl Vicente | septiembre 27th, 2007 at 9:16 pm
Me alegro de que te haya gustado esto anima a seguir escribiendo.
Gracias.
3. Alex | enero 22nd, 2008 at 4:32 pm
Enhorabuena por tus aportaciones (no solo por estas). Tengo una pregunta por si tienes la respuesta. Al evolucionar a Junit 4 se pierde esta caracteristica, al menos la de inyección de dependencias porque el tema de las transacciones lo trata de forma distinta (con anotaciones).
¿sabes si se puede usar la inyección dedependencias en esta versión de Junit?
Gracias y enhorabuena (de nuevo)
4. Raúl Vicente | enero 23rd, 2008 at 1:16 am
No he trabajado con esta versión, en mi trabajo he trabajado con versiones anteriores, dentro de poco voy a trabajar con la última versión de JUnit, voy a mirar esta característica. En cuanto tenga una respuesta prometo postear el comentario. Gracias por la colaboración.
5. Spring y JUnit 4 | orient&hellip | febrero 18th, 2008 at 11:31 am
[...] poco un lector de mi post Spring y JUnit se mostraba inquieto porque pensaba que la capacidad de integración de Spring con JUnit se había [...]
6. ramon | febrero 16th, 2009 at 5:07 pm
Hola Raul, he estado probando esto del junit de spring y me da un error:
java.lang.NoSuchMethodError: org.springframework.util.ObjectUtils.nullSafeToString(Ljava/lang/Object;)Ljava/lang/String;
at org.springframework.test.AbstractSpringContextTests.contextKeyString(AbstractSpringContextTests.java:134)
at org.springframework.test.AbstractSpringContextTests.getContext(AbstractSpringContextTests.java:101)
at org.springframework.test.AbstractSingleSpringContextTests.setUp(AbstractSingleSpringContextTests.java:87)
at junit.framework.TestCase.runBare(TestCase.java:125)
at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:69)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Esta es mi clase Test:
package XX.XX.XX.XX.XX.XX.impl;
import java.util.List;
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
import XX.XX.XX.XX.XX.AccesoCentros;
public class HibernateDAOAccesoCentrosJunit extends AbstractTransactionalDataSourceSpringContextTests{
private FactoriaHibernateDAO factoriaDAO;
public void testLoadAccesoCentros() throws Exception {
List lista = this.factoriaDAO.getDAOAccesoCentros().getAccesoCentros();
System.out.println(lista.size());
assertNotNull(lista);
}
protected String[] getConfigLocations() {
return new String[] { “/WebContent/WEB-INF/applicationContext.xml” };
}
public FactoriaHibernateDAO getFactoriaDAO() {
return factoriaDAO;
}
public void setFactoriaDAO(FactoriaHibernateDAO factoriaDAO) {
this.factoriaDAO = factoriaDAO;
}
}
y te pego un trozo de mi aplication-context.xml
7. Raul | febrero 16th, 2009 at 10:53 pm
Buenas Ramon,
yo para empezar tengo una pregunta ¿utilizas JUnit 4 ó 3? Ya que la configuración cambia.
En segundo lugar, yo cuando lo pruebo no hago tirar mis test de mi carpeta Web directamente. Me creo un Source Folder y meto ahí mis test, con la misma ruta de paquetes y duplico el applicationContext.xml.
Prueba con esto, si no te funciona creo que tengo un ejemplo hecho con Spring+Hibernate+JUnit+HiperSonic, que te podría pasar, pero inténtalo siempre es más gratificante conseguirlo por uno mismo.
Un saludo y gracias por colaborar.