2009-08-05 28 views
30

Esta es una pregunta un tanto extraña, pero me ha estado molestando durante algunos meses. He creado una aplicación web basada en JPA usando Wicket + Hibernate (construido con Maven), y quiero probar la capa DAO directamente. Creé un archivo src/test/resources/META-INF/persistence.xml específico que utilicé para probar, pero he tenido conflictos con WTP y similares. Para evitar estos problemas, creé un proyecto de prueba separado donde las pruebas de la unidad en vivo. ¿Existe una mejor manera de administrar las pruebas unitarias para un proyecto JPA sin tener duelos entre los archivos de persistencia?Buenas prácticas de prueba JUnit basadas en JPA

Adición: ¿Podrían hacer esto otros frameworks de prueba (TestNG, por ejemplo)?

+0

Este tipo de prueba que ha mencionado no es prueba unitaria. Creo que es una prueba de integración de tipo. Cuando escribe una prueba unitaria, prueba una clase con todas las dependencias ridiculizadas. Por lo tanto, usar una base de datos real (incluso bases de datos en memoria) en pruebas unitarias no es válida. –

+0

No es una prueba de integración completa. ¡Es válido! Simplemente no es prueba de unidad. – Gilberto

Respuesta

16

Puede intentar mockito. La prueba funciona así:

Utiliza mockito para "implementar" EntityManager. En lugar del código real, usa los métodos de mockito para decir "si la aplicación llama al getReference(), luego devuelve este objeto". En segundo plano, mockito creará una instancia proxy que interceptará las llamadas al método Java y devolverá los valores que especifique. Las llamadas a otros métodos devolverán null.

que imita cosas como createQuery() funciona de la misma manera, pero primero tiene que crear una maqueta de Query y luego utilizar el mismo enfoque que en getReference() (devolver la maqueta de consulta).

Como no usa un EM real, no necesita un persistence.xml real.

Una solución mucho más simple sería si pudiera establecer alguna propiedad para cambiar el nombre del archivo persistence.xml, pero no creo que esto sea posible.

Algunos otros enlaces que pueden ayudar:

+0

He investigado el uso de objetos simulados (lo he hecho para pruebas basadas en LDAP), y ciertamente es una opción. En este caso específico, me gustaría consultar el DB para validar las cosas de principio a fin, en lugar de simplemente asegurar que mi DAO devuelva información. – mlaccetti

+2

En ese caso, hay una solución en el primer enlace: puede especificar varias "unidades de persistencia" en persistence.xml y seleccionar una diferente en las pruebas de su unidad. –

4

Utilizamos duales persistence.xml archivos de tiempo de ejecución de producción y de prueba, sino que es sólo una cuestión relacionada con la ruta de clases (usamos Eclipse pero no dependemos mucho de los complementos de WTP). La única diferencia entre los dos es que la versión de producción no contiene definiciones de entidad.

No utilizamos un marco de burla para probar JPA ya que esto no agregaría ningún valor a nuestras pruebas. Las pruebas sí ejecutan acceso a datos reales con JPA que habla con la base de datos PostgreSQL.

Nuestro enfoque de las pruebas se basa en el marco de prueba de Spring para la capa de persistencia: prueba en la transacción. Nuestra aplicación está basada en Spring, pero este enfoque es igualmente útil para aplicaciones arbitrarias que quieran aprovechar las clases de prueba de Spring. La esencia es que cada prueba se ejecuta dentro de una única transacción que nunca se compromete y al final (en tearDown) se revierte automáticamente. Esto resuelve el problema de la contaminación de datos y la dependencia de prueba de una manera muy agradable, discreta y transparente.

El marco de prueba de Spring es flexible para permitir las pruebas de transacciones múltiples, pero estos son casos especiales que constituyen no más del 10% de las pruebas.

Todavía utilizamos legacy support for JUnit 3.8 pero el nuevo Spring TestContext Framework para JUnit 4 se ve muy atractivo.

Para configurar los datos de prueba dentro de la transacción, utilizamos la clase de utilidad interna que construye las entidades comerciales. Dado que se comparte entre todas las pruebas, la sobrecarga para mantenerla y admitirla es muy superior a los beneficios de contar con una manera estándar y confiable de configurar los datos de prueba.

Spring DI ayuda a que las pruebas sean concisas y autodescriptivas, pero no es una característica crítica.

+0

He estado utilizando JUnit 4.x (4.6, en el último recuento, creo) y las extensiones de prueba de primavera. Ayudan maravillosamente en la configuración de mi entorno JPA, pero todavía tengo problemas ya que mi producción persistence.xml hace referencia a WEB-INF/lib/common-code.jar que no funciona muy bien con las pruebas. – mlaccetti

4

El uso de las pruebas de unidad de Spring y Spring es la mejor manera de hacerlo. Con Spring, no necesita dos persistence.xml ya que su persistence.xml no tiene nada, todo está especificado para la primavera (todo lo que especificamos en nuestra persistence.xml es el nombre de la unidad de persistencia) y por lo tanto puede cambiar la configuración de la base de datos etc. con primavera.

Y como señaló topchef, las pruebas de unidades basadas en transacciones de primavera son geniales.

+0

¿Cómo se especifica qué clases cargar y qué frascos para extraer el código en Spring? Parece que me he perdido algo importante. – mlaccetti

+0

Uso OpenJPA que requiere -javaagent habilitado en tiempo de ejecución y usa persistence.xml. ¿Cómo debería decirle al agente de OpenJPA que busque entre las clases mencionadas en Spring Config, no en persistence.xml? –

+0

hmmm ... Creo que esa respuesta quizás esté un poco desactualizada. Debe especificar en su persistence.xml una lista de sus clases persistentes –

0

Como se menciona aquí: http://www.devx.com/java/Article/36785/1954, puede eliminar las siguientes líneas del proyecto .settings/org.eclipse.wst.common.component para evitar la implementación de recursos de prueba con la aplicación web.

<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/java"/> 
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/resources"/>