2010-08-30 7 views
11

Después de leer un interesante artículo sobre el comportamiento de las pruebas unitarias en lugar del estado, me di cuenta de que mis pruebas unitarias a menudo están estrechamente relacionadas con mi código porque estoy usando simulaciones. No puedo realizar pruebas de unidades de escritura de imágenes sin burlarse, pero el hecho es que estos simulacros están acoplando mucho mi prueba de unidad a mi código debido a las llamadas de espera y de devolución.¿Estoy haciendo algo fundamentalmente incorrecto en mis pruebas unitarias?

Por ejemplo, cuando creo una prueba que utiliza un simulacro, grabo todas las llamadas al simulacro específico y asigno valores devueltos. Ahora cuando cambio la implementación del código real por alguna razón, se rompen muchas pruebas porque el simulacro no esperaba esa llamada, lo que me forzó a actualizar también la prueba de la unidad y me obligó a implementar cada cambio dos veces. Esto sucede mucho.

¿Este problema es intrínseco al uso de simulacros, y debería aprender a vivir con él, o estoy haciendo algo fundamentalmente malo? Por favor, ilumíname :) Los ejemplos claros que vienen con la explicación son bienvenidos, por supuesto.

+2

Definitivamente, debes googlear "cazadora ficticia clasicista", reserva uno o dos días y lee :). Iho, ambos tienen sus méritos y ambos deben usarse cuando la situación lo requiera. –

Respuesta

5

cuando creo un examen que utiliza una maqueta, Puedo grabar todas las llamadas a la específica maqueta y asignar valores de retorno

Suena como puede ser sobre-especificación de las expectativas.

Intente crear el menor código de configuración posible en sus pruebas: resuelva (en lugar de esperar) todo el comportamiento que no pertenece a la prueba actual y solo especifique los valores de retorno que son absolutamente necesarios para que la prueba funcione.

This answer incluye un ejemplo conciso (así como una explicación alternativa y más detallada).

2

Si está corrigiendo las pruebas porque se rompen, no las está utilizando como estaba previsto.

Si el comportamiento de un método cambia, en el desarrollo impulsado por prueba primero debe cambiar la prueba para esperar el nuevo comportamiento, luego implementar el nuevo comportamiento.

+0

Eso es correcto, y una definición muy concisa de TDD, pero no cambia el hecho de que siempre tiene que implementar los cambios dos veces, primero en la prueba, ver que falla, luego en el código, ver que tenga éxito. Entonces, ¿este 'siempre implementar dos veces' es intrínseco a TDD? – nkr1pt

+0

@ nkr1pt: Sí, pero no está aislado para TDD. Tendría más o menos el mismo problema en cualquier modelo de desarrollo que incorpore pruebas en cualquier forma. Es solo que es tan obvio en TDD. – Guffa

4

Mi experiencia es usar burlas solo en los límites de (sub) sistemas. Si tengo dos clases que están fuertemente relacionadas, no me burlo de ellas, sino que las pruebo juntas. Un ejemplo podría ser un compuesto y un visitante. Si pruebo a un visitante concreto, no utilizo un simulacro para el compuesto, sino que creo compuestos reales. Se podría argumentar que esto no es una prueba unitaria (depende de la definición de qué es una unidad). Pero eso no importa mucho. Lo que trato de lograr es:

  1. Escribir pruebas legibles (las pruebas sin simulaciones son en la mayoría de los casos más fáciles de leer).
  2. Pruebe solo un área enfocada de código (en el ejemplo, el visitante concreate y la parte relevante del compuesto).
  3. Escribir pruebas rápidas (siempre que instanciar unas pocas clases, en el ejemplo de los composites concretos, esto no es una preocupación ... ver para las creaciones transitivas).

Solo si encuentro el límite de un subsistema, utilizo los simulacros. Ejemplo: Tengo un compuesto que puede renderizarse en un representador. Me burlaría del representador si probara la lógica de renderizado del compuesto.

Comportamiento de prueba en lugar de estado parece prometedor al principio, pero en general probaría el estado ya que las pruebas resultantes son fáciles de mantener. Los simulacros son un cañón. No rompas una nuez con un mazo.

+1

Si bien estoy de acuerdo con el sentido de esto, muchos sistemas son lo suficientemente poco profundos en suficientes lugares que hay muy poca diferencia entre burlarse todo el tiempo y burlarse solo en los límites del subsistema. –

+0

En este caso: dele profundidad a los sistemas. ¡Separar claramente los subsistemas! – Arne

+0

Si se siente bien probando varias clases juntas como una unidad, tal vez el próximo paso para usted es consolidar esa unidad en una sola clase. – Ladlestein

0

Varias buenas respuestas aquí ya, pero para mí una buena regla general es probar los requisitos del método, no la implementación. Algunas veces eso puede significar el uso de un objeto simulado porque la interacción es el requisito, pero por lo general es mejor que pruebe el valor de retorno del método o el cambio en el estado del objeto.