2010-11-05 16 views
10

Tengo un proyecto con el que intento aprender pruebas unitarias y prácticas de TDD. Me doy cuenta de que estoy llegando a casos bastante confusos en los que paso mucho tiempo montando burlas para una clase de utilidad que se usa prácticamente en todas partes.¿Es aceptable utilizar una clase de utilidad "real" en lugar de burlarse en TDD?

Por lo que he leído sobre pruebas unitarias, si estoy probando MyClass, debería burlarme de cualquier otra funcionalidad (como la proporcionada por UtilityClass). ¿Es aceptable (suponiendo que la propia UtilityClass tenga un conjunto completo de pruebas) simplemente usar la clase de utilidad en lugar de establecer simulaciones para todos los diferentes casos de prueba?

Editar: Una de las cosas que estoy haciendo un montón de configuración. Estoy modelando un mapa, con diferentes objetos en diferentes ubicaciones. Uno de los métodos comunes en mi clase de utilidad es GetDistanceBetween. Estoy probando métodos que tienen efectos en las cosas dependiendo de sus propiedades individuales, así que por ejemplo una prueba que selecciona todos los objetos dentro de 5 unidades de un punto y una edad superior a 3 necesitarán varias pruebas (obtiene objetos viejos dentro del rango, ignora objetos viejos de rango, ignora los objetos jóvenes dentro del rango, funciona correctamente con múltiplos de cada caso) y todas esas pruebas necesitan la configuración del método 'GetDistanceBetween'. Multiplique eso por cada método que use GetDistanceBetween (casi todos) y los diferentes resultados que el método debería devolver en diferentes circunstancias, y se requiere mucha configuración.

Veo cómo desarrollo esto aún más, puede haber más llamadas de clases de utilidad, grandes cantidades de objetos y mucha configuración en esas clases de utilidad simuladas.

Respuesta

20

La regla no es "simular todo" sino "hacer pruebas simples". Burlándose debe usarse si

  1. no se puede crear una instancia con un esfuerzo razonable (es decir: se necesita una sola llamada a un método, pero para crear la instancia, se necesita una base de datos de trabajo, una conexión de base de datos, y otras cinco clases)
  2. La creación de las clases adicionales es costosa.
  3. Las clases adicionales devuelven valores inestables (como la hora actual o las claves principales de una base de datos)
+1

+1 para enfatizar "hacer pruebas simples" –

1

No, no es aceptable porque ya no está probando la clase de forma aislada, que es uno de los aspectos más importantes de una prueba unitaria. Lo está probando con su dependencia a esta utilidad, incluso si la utilidad tiene su propio conjunto de pruebas. Para simplificar la creación de objetos simulados, podría usar un marco simulado. Aquí están algunas opciones populares:

Por supuesto, si esta clase de utilidad es privada y sólo se puede utilizar dentro del ámbito de la clase bajo prueba, entonces no es necesario que se burle.

+1

Probar una clase aisladamente no es realista. Si realmente quieres impulsar eso, también tendrás que burlarse de java.lang.String. –

+1

@Aaron, de acuerdo, cuando quise decir de forma aislada, quise decir de forma aislada el código que ha escrito el desarrollador. –

+0

Ya estoy usando Moq, pero aún así, si necesito respuestas específicas a las llamadas a métodos, tengo que configurarlas. Los casos de instalación son cada vez más largos a medida que las cosas se complican. –

4

En teoría, usted debe tratar de burlarse de todas las dependencias, pero en realidad nunca es posible. P.ej. no se va a burlar de las clases básicas de la biblioteca estándar. En su caso, si la clase de utilidad solo contiene algunos métodos básicos de ayuda, creo que no me molestaría en burlarme de ella.

Si es más complicado que eso o se conecta a algunos recursos externos, debe simularlo.Podría considerar crear una clase de creador de simulacros dedicada, que le crearía una simulación estándar (con algunos resquicios estándar definidos, etc.), de modo que pueda evitar la duplicación de código de burla en todas las clases de prueba.

+0

Sí. Cuando la utilidad se conecta a recursos externos, como URL, debe burlarse de eso. – freeman

9

TDD no es realmente sobre la prueba. Su principal ventaja es ayudarlo a diseñar código limpio y fácil de usar que otras personas puedan entender y cambiar. Si su principal beneficio fuera la prueba, entonces sería capaz de escribir pruebas después de su código, en lugar de antes, con gran parte del mismo efecto.

Si puede, le recomiendo que deje de pensar en ellos como "pruebas unitarias". En cambio, piense en sus pruebas como ejemplos de cómo puede usar su código, junto con descripciones de su comportamiento que muestran por qué su código es valioso.

Como parte de ese comportamiento, es posible que su clase quiera utilizar algunas clases colaboradoras. Puedes burlarte de esto.

Si sus clases de utilidad son una parte fundamental del comportamiento de su clase, y su clase no tiene ningún valor o su comportamiento no tiene sentido sin ellas, entonces no las descarte.

La respuesta de Aaron Digulla es bastante buena; Me reformular cada una de sus respuestas de acuerdo con estos principios como:.

  1. El comportamiento de la clase colaboradora es complejo e independiente del comportamiento de la clase que le interesa

  2. Creación de la clase colaboradora no es un aspecto valioso de su clase y no necesita ser parte de la responsabilidad de su clase.

  3. La clase colaboradora proporciona un contexto que cambia el comportamiento de su clase y, por lo tanto, juega con los ejemplos de cómo puede usarlo y qué tipo de comportamiento puede esperar.

Espero que tenga sentido! Si te gustó, echa un vistazo a BDD, que usa este tipo de vocabulario mucho más que "prueba".

+0

"y su clase no tiene ningún valor o su comportamiento no tiene sentido sin ellos, entonces no los burles" - Así que en mi ejemplo de obtener la distancia entre los puntos, donde la distancia es una parte determinante de la función del método que estoy probando, ¿diría 'no se burle'? –

+0

Bueno, la distancia proporciona contexto, así que tal vez. Un buen momento para simularlo sería si tuvieras diferentes estrategias, por ejemplo, si pudieras calcular por distancia o por costo, pero luego me burlaría de la estrategia en lugar de solo la distancia. Por ahora, me concentraría en hacer que las pruebas sean fáciles de leer y entender. – Lunivore

1

Sí, es aceptable. Lo que es importante es hacer que la unidad UtilityClass esté completamente probada y poder diferenciar si una prueba está fallando debido a la Clase bajo prueba o debido a la Clase de Utilidad.

Probar una clase en aislamiento significa probarla en un entorno controlado, en un entorno donde uno controla cómo se comportan los objetos.
Tener que crear demasiados objetos en una configuración de prueba es una señal de que el entorno es demasiado grande y, por lo tanto, no se controla lo suficiente. Ha llegado el momento de volver a simular objetos.

Cuestiones relacionadas