Pregunta

Póster por primera vez y adoptante de TDD. :-) Seré un poco verboso así que por favor ten paciencia conmigo.

Recientemente comencé a desarrollar servicios web basados ??en SOAP utilizando el marco Apache CXF, Spring y Commons Chain para implementar el flujo de negocios. El problema al que me enfrento aquí es con la prueba de los servicios web: pruebas como en Pruebas de unidad y pruebas funcionales.

Mi primer intento de probar la Unidad fue un completo fracaso. Para mantener la flexibilidad de las pruebas unitarias, usé un archivo XML de Spring para mantener mis datos de prueba. Además, en lugar de crear instancias de " componentes " para ser probado, los recuperé de mi contexto Spring Application. Los archivos XML que contenían datos rápidamente se salieron de control; La creación de gráficos de objetos en XML resultó ser una pesadilla. Desde los " componentes " para ser probados se seleccionaron a partir del Contexto de Aplicación de Spring, cada ejecución de prueba cargó todos los componentes involucrados en mi aplicación, los objetos DAO utilizados, etc. Además, a diferencia del concepto de casos de prueba de unidad centralizados o concentrado en probar solo el componente, mis pruebas de unidad comenzaron a llegar a bases de datos, a comunicarse con servidores de correo, etc. Malos, muy malos.

Sabía lo que había hecho mal y comencé a pensar en formas de rectificarlo. Siguiendo los consejos de uno de los mensajes de este foro, busqué en Mockito, el marco de burla de Java para poder eliminar el uso de clases de DAO y servidores de correo reales y simplemente simular la funcionalidad.

Con las pruebas unitarias un poco bajo control, esto me lleva a mi segundo problema; La dependencia de los datos. Los servicios web que he estado desarrollando tienen muy poca lógica pero gran dependencia de los datos. Como ejemplo, considere uno de mis componentes:

public class PaymentScheduleRetrievalComponent implements Command {
  public boolean execute(Context ctx) {
    Policy policy = (Policy)ctx.get("POLICY");
    List<PaymentSchedule> list = billingDAO.getPaymentStatementForPolicy(policy);
    ctx.put("PAYMENT_SCHEDULE_LIST", list);
    return false;
  }
}

La mayoría de mis componentes siguen la misma ruta: elija un objeto de dominio del contexto, presione el DAO [estamos usando iBatis como el asignador de SQL aquí] y recupere el resultado.

Entonces, ahora las preguntas:
- ¿Cómo se prueban las clases DAO especialmente cuando una sola inserción o actualización puede dejar la base de datos en un " inestable " Estado [en casos donde digamos que 3 inserciones en diferentes tablas realmente forman una sola transacción]?
- ¿Cuál es el estándar de facto para los servicios web de pruebas funcionales que mueven una gran cantidad de datos, es decir, inserciones o recuperaciones sin sentido del almacén de datos?

Sus experiencias / comentarios personales serían muy apreciados. Por favor, avíseme en caso de que me haya perdido algunos detalles de mi parte para explicar el problema en cuestión.

-sasuke

¿Fue útil?

Solución

Recomendaría una base de datos en memoria para ejecutar sus pruebas unitarias, como HSQL. Puede usar esto para crear su esquema sobre la marcha (por ejemplo, si está usando Hibernate, puede usar sus archivos de asignaciones XML), luego inserte / actualice / elimine según sea necesario antes de destruir la base de datos al final de su prueba de unidad. En ningún momento su prueba interferirá con su base de datos real.

Para su segundo problema (pruebas de extremo a extremo de servicios web), he probado con éxito los servicios basados ??en CXF en el pasado. El truco consiste en publicar su servicio web utilizando un servidor web liviano al comienzo de su prueba (Jetty es ideal), luego usar CXF para dirigir un cliente a su punto final de servicio web, ejecutar sus llamadas y finalmente cerrar el Jetty La instancia que aloja su servicio web una vez que su prueba de unidad ha finalizado.

Para lograr esto, puede usar las clases JaxWsServerFactoryBean (lado del servidor) y JaxWsProxyFactoryBean (lado del cliente) provistas con CXF, consulte esta página para ver el código de muestra:

http: // cwiki .apache.org / CXF20DOC / a-simple-jax-ws-service.html # AsimpleJAX-WSservice-Publishingyourservice

También daría un gran impulso a la IU de SOAP para realizar pruebas funcionales de su servicio web. JMeter también es extremadamente útil para los servicios web de pruebas de estrés, lo cual es particularmente importante para aquellos servicios que realizan búsquedas en bases de datos.

Otros consejos

Me mantendría alejado del " Context as global hashmap " 'patrón' si yo fuera tú.

Parece que estás probando tu mapeo de persistencia ...

Es posible que desee echar un vistazo a: probar objetos persistentes sin resorte

En primer lugar: ¿hay alguna razón por la que tenga que recuperar el tema bajo prueba (SUT) del contexto de la aplicación Spring? Para realizar pruebas de unidad eficientes, debe poder crear el SUT sin el contexto. Parece que tienes algunas dependencias ocultas en algún lugar. Esa podría ser la raíz de algunos de sus dolores de cabeza.

  

¿Cómo se evalúan las clases DAO especialmente cuando un   una sola inserción o actualización podría   dejar la base de datos en un " inestable "   Estado [en casos donde digamos 3   inserciones en diferentes tablas   en realidad formar una sola transacción]?

Parece que está preocupado por la constancia de la base de datos después de ejecutar las pruebas. Si es posible, utilice una base de datos propia para realizar pruebas, donde no necesita atención. Si tiene una base de datos de sandbox, puede eliminar los datos como desee. En este caso yo haría lo siguiente:

  1. Marca todos tus datos falsos con algún identificador común, como poner un prefijo especial en un campo.
  2. Antes de ejecutar la prueba, suelte una declaración de eliminación, que elimina los datos marcados. Si no hay ninguno, entonces no pasa nada malo.
  3. Ejecuta tu única prueba DAO. Luego repita el paso 2. para la siguiente prueba.
  

¿Cuál es el estándar de facto para   servicios web de pruebas funcionales que   moverse alrededor de una gran cantidad de datos, es decir,   inserciones sin sentido / recuperaciones de   el almacén de datos?

No tengo conocimiento de ninguna. De la pregunta que está haciendo, puedo deducir que tiene, por un lado, el servicio web y, por el otro, la base de datos. Dividir las responsabilidades. Tener suites de prueba separadas para cada lado. Un lado acaba de probar el acceso a la base de datos (como se describe anteriormente). Por otro lado, solo prueba las solicitudes y respuestas de servicios web. En este caso, paga la capa / falso / simulacro de la capa que habla a la red. O considere https://wsunit.dev.java.net/ .

Si el programa solo está introduciendo y expulsando datos, creo que no hay mucho comportamiento. Si este es el caso, entonces el trabajo más difícil es realizar una prueba unitaria del lado de la base de datos y del lado del servicio web. El punto es que puedes hacer pruebas de unidad sin la necesidad de " realista " datos. Para las pruebas funcionales necesitará datos manuales, que están cerca de la realidad. Esto puede ser engorroso, pero si ya probó la base de datos y las partes del servicio web de forma intensiva, esto debería reducir la necesidad de " realista " casos de prueba considerablemente.

En primer lugar, aclarar las cosas.

En un mundo ideal, el ciclo de vida del software que estás construyendo es algo como esto:  - sy hace un informe con el cliente, por lo que recibió una historia de usuario con ejemplos sobre cómo debería funcionar la aplicación  - generaliza la historia del usuario, por lo que tiene reglas, a las que llama como casos de uso  - empiezas a escribir una prueba funcional (de extremo a extremo), y falla ...  - después de eso, construye la interfaz de usuario y simula los servicios, de modo que obtienes una prueba funcional verde y una especificación sobre cómo deberían funcionar tus servicios ...  - su trabajo es mantener la prueba funcional en verde, e implementar los servicios paso a paso escribiendo pruebas de integración y burlándose de las dependencias con el mismo enfoque hasta que alcance el nivel de pruebas unitarias  - después de eso, realice la siguiente iteración con los casos de uso, escriba la siguiente prueba funcional, y así sucesivamente hasta el final del proyecto.  - después de eso, realiza pruebas de aceptación con el cliente que acepta el producto y paga mucho

Entonces, ¿qué aprendimos de esto:

  • Hay muchos tipos de pruebas (no confundirlas entre sí)
    • pruebas funcionales: para probar los casos de uso (no se burlan de nada)
    • pruebas de integración: para probar la aplicación, el componente, el módulo, las interacciones de clase (simular los componentes irrelevantes)
    • pruebas unitarias: para probar una sola clase de forma aislada de su entorno (simulacro de todo)
    • pruebas de aceptación del usuario: el cliente se asegura de que ella acepte el producto (pruebas funcionales manuales o presentaciones hechas de pruebas funcionales automáticas en funcionamiento)
  • No es necesario probar todo mediante pruebas funcionales y pruebas de integración, porque es imposible. ¡Pruebe solo la parte relevante mediante pruebas funcionales y de integración y pruebe todo mediante pruebas unitarias! Familiarícese con la pirámide de prueba .
  • Usa TDD, ¡hace la vida más fácil!
  
      
  • ¿Cómo se evalúan las clases DAO especialmente cuando una sola inserción o actualización puede dejar la base de datos en un " inestable " estado [en los casos donde vamos   decir 3 inserciones en diferentes tablas en realidad forman una sola   transacción]?
  •   

No tienes que probar tus transacciones de base de datos. Supongamos que están funcionando bien, porque los desarrolladores de bases de datos ya los han probado, y estoy seguro de que no desea escribir pruebas de concurrencia ... Db es un componente externo, por lo que no tiene que probarlo usted mismo. Puede escribir una capa de acceso a datos para adaptar el almacenamiento de datos a su sistema, y ??escribir pruebas de integración solo para esos adaptadores. En el caso de la migración de la base de datos, estas pruebas también funcionarán con los adaptadores de la nueva base de datos, ya que las escribirá para implementar una interfaz específica ... Mediante cualquier otra prueba (excepto las pruebas funcionales) puede simular su capa de acceso a datos. Haga lo mismo con todos los demás componentes externos, escriba adaptadores y simúlelos. Coloque este tipo de pruebas de integración en un conjunto de pruebas diferente al de las otras pruebas, porque son lentas debido al acceso a la base de datos, al acceso al sistema de archivos, etc ...

  
      
  • ¿Cuál es el estándar de facto para los servicios web de pruebas funcionales que mueven una gran cantidad de datos, es decir, inserciones o recuperaciones sin sentido?   del almacén de datos?
  •   

Puedes simular tu almacén de datos con una base de datos en memoria que implementa los mismos adaptadores de almacenamiento hasta que implementes todo lo demás, excepto la base de datos. Después de eso, implemente la capa de acceso a datos para la base de datos y también pruébelo con sus pruebas funcionales. Será lento, pero debe ejecutarse solo una vez, por ejemplo, por cada nueva versión ... Si necesita pruebas funcionales al desarrollarse, puede volver a burlarse con una solución en memoria ... Un enfoque alternativo para ejecutar solo Las pruebas funcionales afectadas están desarrollando o modificando la configuración de la base de datos de prueba para hacer las cosas más rápidas, y así sucesivamente ... Estoy seguro de que hay muchas soluciones de optimización de prueba ...

  

Debo decir que realmente no entiendo   tu problema exacto Es el problema   que su base de datos se deja en una   estado alterado después de haber ejecutado el   prueba?

Sí, en realidad hay dos problemas aquí. El primero es el problema con la base de datos que queda en un estado incoherente después de ejecutar los casos de prueba. La segunda es que estoy buscando una solución elegante en términos de pruebas de servicios web de extremo a extremo.

  

Para una prueba de unidad eficiente deberías   ser capaz de crear el SUT sin el   contexto. Parece que tienes algo   Dependencias ocultas en alguna parte. Ese   podría ser la raíz de algunos de sus   dolor de cabeza.

De hecho, esa fue la causa raíz de mis dolores de cabeza que ahora estoy a punto de eliminar con la ayuda de un marco burlón.

  

Parece que estás preocupado por la   la constancia de la base de datos después de tener   ejecutando las pruebas. Si es posible, use un   propia base de datos para la prueba, donde   No necesito preocuparme por eso. Si usted tiene   una base de datos de tal caja de arena que puede eliminar   Los datos que desee.

De hecho, esta es una de las soluciones al problema que mencioné en mi publicación anterior, pero podría no funcionar en todos los casos, especialmente cuando se integra con un sistema heredado en el que la base de datos / datos no está bajo su control y en los casos cuando algunos métodos DAO requieren que ciertos datos ya estén presentes en un conjunto dado de tablas. ¿Debo mirar en los marcos de prueba de unidades de base de datos como DBUnit?

  

En este caso paga de la   Stub / falso / burlarse de la capa hablando con   la red O considerar    https://wsunit.dev.java.net/ .

Ah, parece interesante. También he oído hablar de herramientas como SOAPUI y similares que pueden usarse para pruebas funcionales. ¿Alguien aquí ha tenido éxito con tales herramientas?

Gracias por todas las respuestas y disculpas por la explicación ambigua; El inglés no es mi primer idioma.

-sasuke

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top