Para el proyecto en el que estamos trabajando mi equipo y yo, a menudo encontramos que necesitamos grandes piezas de código de andamios. Crear objetos de dominio con valores correctos, configurar simulacros para repositorios, lidiar con el caché, ... son cosas que ocurren comúnmente durante las pruebas. Muchas veces estamos trabajando con los mismos objetos básicos que son centrales para nuestro dominio (persona, ...) por lo que muchas pruebas crean instancias de estos objetos para que otros objetos trabajen. Tenemos muchas soluciones diferentes que utilizan el dominio base, por lo que este tipo de código a menudo se distribuye entre esas soluciones.
He estado pensando en crear clases comunes que hagan mucho de este andamiaje. Esto nos permitiría solicitar una persona totalmente instanciada con todo configurado (acceso a través del repositorio, almacenamiento en caché ...). Esto elimina el código duplicado de nuestras pruebas unitarias individuales, pero también significaría que hay una gran cantidad de código que probablemente hace "demasiado" por prueba (ya que configuraría un objeto completo y no solo las partes requeridas).
¿Alguien ha hecho esto alguna vez? ¿Hay alguna idea, comentario, pensamiento ... que pueda ofrecer que pueda validar o invalidar este enfoque?
fuente
Respuestas:
Utilizo el patrón de creación para crear objetos de dominio para pruebas como se detalla en el libro " Crecimiento de software orientado a objetos ". Los constructores tienen métodos estáticos que generan valores predeterminados para objetos comunes con métodos para anular los valores predeterminados.
Puede combinarlos para generar objetos más complejos.
También utilizamos la herencia de clase de caso de prueba con simulacros utilizados comúnmente para tipos específicos de pruebas unitarias; por ejemplo, las pruebas de controlador mvc requieren con frecuencia los mismos simulacros / apéndices para los objetos de solicitud y respuesta.
fuente
La configuración para todas las pruebas puede ser una buena idea, especialmente si realiza una implementación. En lugar de usar simulacros, creamos, implementamos y llenamos una base de datos de prueba y luego apuntamos la prueba a la instancia. No es exactamente la forma en que debe hacerlo según el manual, pero funciona, aún más para nosotros porque utilizamos nuestro código de implementación para hacerlo.
fuente
Bedwyr Humphreys está hablando de una solución Builder que he usado un par de veces, y realmente funciona bien. Casi no hay duplicación de código y la construcción de objetos de dominio de una manera agradable y limpia.
No soy tan fanático de la generación de código (andamios, codemith, lblgen, ...). Solo le ayuda a escribir código duplicado mucho más rápido, no es realmente fácil de mantener. Si un marco de trabajo está causando que escriba un montón de código duplicado (prueba), tal vez necesite encontrar una forma de alejar la base de código del marco.
Si sigue escribiendo código de acceso al repositorio, es posible que pueda resolver esto con un repositorio base genérico y tener una clase de prueba base genérica de la que hereden las pruebas unitarias.
Para evitar la duplicación de código, AOP también puede ayudar para cosas como el registro, el almacenamiento en caché, ...
fuente
Es posible que desee reconsiderar el diseño del código que está probando. ¿Quizás necesita algunas instancias del patrón de diseño de Fachada? Su código de prueba podría usar las fachadas, y sería más simple.
fuente
Me puedo relacionar con esta pregunta. En mi equipo, hemos intentado hacer TDD antes y era la misma historia, demasiadas pruebas requerían muchos métodos de andamiaje / utilidad que simplemente no teníamos. Debido a las presiones de tiempo y algunas otras decisiones no tan correctas, terminamos con pruebas unitarias que fueron muy largas y reinventaron las cosas. En el transcurso de un lanzamiento, esas pruebas unitarias se volvieron tan complicadas y difíciles de mantener que tuvimos que abandonarlas.
Actualmente estoy trabajando con algunos otros desarrolladores para reintroducir TDD en el equipo, pero en lugar de simplemente decirle a la gente, ir a escribir pruebas, queremos hacerlo con cuidado esta vez y las personas tienen las habilidades y las herramientas adecuadas. La ausencia del código de soporte común es una cosa que identificamos donde necesitamos mejorar para que cuando otros comiencen a escribir pruebas, todo el código que escriban sea pequeño y vaya al grano.
Todavía no tengo tanta experiencia en esta área como me gustaría, pero pocas cosas sugeriría en base al trabajo que hemos hecho hasta ahora y algunos deberes que he hecho:
fuente
"Cualquier problema en informática puede resolverse con una capa adicional de indirección. Pero eso generalmente creará otro problema". - David Wheeler
(descargo de responsabilidad: soy parte del equipo de JDT, por lo que tengo más conocimiento interno del problema presentado aquí)
El problema esencial aquí es que los objetos en el marco en sí mismos esperan una conexión de base de datos, ya que se basa libremente en el marco CSLA de Rockford Lhotka. Esto hace que burlarse de ellos sea casi imposible (ya que tendrías que cambiar el marco para admitir esto) y también viola el principio de caja negra que debería tener una prueba unitaria.
Su solución propuesta, aunque no es una mala idea en sí misma, no solo requerirá MUCHO trabajo para llegar a una solución estable, sino que también agregará otra capa de clases que debe mantenerse y ampliarse, agregando aún más complejidad a una situación compleja
Si bien estoy de acuerdo en que siempre debe buscar la mejor solución, en una situación del mundo real como esta, ser práctico también tiene sus valores.
Y la practicidad sugiere la siguiente opción:
Utiliza una base de datos.
Sí, sé que técnicamente hablando ya no es una prueba de unidad "real", pero estrictamente hablando en el momento en que cruzas un límite de clase en tu prueba, tampoco es una prueba de unidad real. Lo que debemos preguntarnos aquí es, ¿queremos pruebas unitarias 'puras' que requieran un montón de andamios y código de pegamento, o queremos un código comprobable ?
También podría aprovechar el hecho de que el marco utilizado encapsula todo el acceso a la base de datos por usted y ejecuta sus pruebas en una base de datos de sandbox limpia. Si luego ejecuta cada prueba en su propia transacción y revierte al final de cada conjunto 'lógico' de pruebas, no debería tener ningún problema de interdependencia u orden de prueba.
No intentes eliminar una base de datos de una base de datos.
fuente
Advertiría por tener demasiado código que hace demasiada 'magia negra' sin que los desarrolladores sepan exactamente qué se está configurando. Además, con el tiempo, se volverá muy dependiente de este código / datos. Es por eso que no soy fanático de basar sus pruebas en bases de datos de prueba. Creo que las bases de datos de prueba son para probar como usuario, no para pruebas automatizadas.
Dicho esto, tu problema es real. Haría algunos métodos comunes para configurar los datos que necesita regularmente. Idealmente, intente parametrizar los métodos, porque ciertas pruebas necesitan datos diferentes.
Pero evitaría crear gráficos de objetos grandes. Es mejor tener pruebas ejecutadas con el mínimo de datos que necesitan. Si hay muchos otros datos, puede influir inesperadamente en los resultados de su prueba (peor de los casos).
Me gusta mantener mis pruebas lo más "silos" posible. Sin embargo, es una pregunta subjetiva. Pero elegiría métodos comunes con parámetros para que pueda configurar sus datos de prueba en solo unas pocas líneas de código.
fuente
Todas las posibilidades resumidas en las respuestas:
Utilice el patrón Builder (Bedwyr Humphreys, DXM y Pascal Mestdach)
Ventajas:
Desventajas
Use una base de datos de prueba (Tony Hopkinson y Sam)
Ventajas:
Desventajas
Crear objetos de dominio por prueba (Peter)
Ventajas:
Desventajas
Usar fachadas para objetos de dominio (Raedwald)
Ventajas:
Desventajas
fuente