2009-08-18 11 views
11

Estoy construyendo una nueva aplicación y tratando de adherirme al desarrollo de "probar primero" tan fielmente como pueda. Me encuentro en situaciones en las que necesito implementar/cambiar una característica que tiene el efecto de invalidar una cantidad de pruebas unitarias existentes. ¿Cómo debería lidiar con esto? Tal como lo veo, hay 3 opciones:¿Qué hacer cuando una nueva característica causa que las pruebas de unidades existentes se vuelvan inválidas?

  • actualizar o eliminar todo pruebas existentes para cumplir los nuevos requisitos de características (añadiendo más si es necesario), y luego implementar la función

  • Implementar el función primera, pruebas realizadas para ver los fallos, y actualizar o eliminar cualquier pruebas fallidas (añadir más si es necesario)

  • añadir nuevas pruebas para la nueva característica, implementar la función, ejecutar todas las pruebas para ver la edad en es un error, eliminar o actualización de las antiguas pruebas según sea necesario

La primera opción se adhiere a TDD, pero puede ser extremadamente contraproducente. La segunda opción es la más fácil, pero no estaría probando fielmente primero y es posible que no esté adecuadamente "cubierta". La tercera opción es un compromiso de ambos y atractivo hasta cierto punto, pero usted corre el riesgo de volver a escribir una prueba cuando podría haber actualizado una anterior.

No siento que tenga una estrategia clara aquí. ¿Qué haces en estas situaciones?

+0

Esto es lo que hago cuando pienso en todo el código que probé que eventualmente entró en el cubo de basura: http://www.youtube.com/watch?v=tgBI3-q5COM – Will

+2

Suena extraño que hacer un cambio (correctamente) podría romper varias pruebas unitarias. Uno o dos tal vez, pero varios? ¿Es posible que las pruebas de su unidad se superpongan demasiado? – Beta

+0

@Beta, supongamos que agrega un requisito de que la implementación ahora requiere una clase dependiente adicional. Ahora sus otras pruebas no proporcionan una implementación simulada del objeto dependiente, de modo que cuando se ejecutan obtiene un montón de excepciones de referencia nula. Entonces necesitaría regresar y arreglar su código de configuración para que luego pasen. – tvanfosson

Respuesta

8

Elegiría una prueba y la cambiaría para que requiera la nueva función. Si no hay candidatos obvios, es decir, es realmente nuevo, crearía uno. Entonces escribiría el código para pasar esa prueba. En ese momento, ejecutaría mis otras pruebas y notaría que algunas de ellas fallan. En ese momento, volvería a revisar cada prueba, ya sea corrigiendo la prueba para reflejar la nueva característica (para que pase sin otros cambios de código) o actualicé la prueba con respecto a la nueva característica (que puede requerir algunos cambios adicionales en la prueba). código bajo prueba).

4

Crearía nuevas pruebas para la nueva característica y actualizaría las pruebas existentes para adaptarlas a su función. Si rompes una prueba que ya está funcionando, debes arreglarla.

4

La implementación de la característica incluye escribir/actualizar las pruebas unitarias; eso es fundamental para el desarrollo basado en pruebas. Entonces tus segundas dos opciones también son TDD, no solo tu primera. En la práctica Sospecho que usted quiere que su tercera opción con algunas modificaciones:

  1. pruebas de escritura para la función (ya que eso ayuda a validar su API/UI por ello)
  2. Escribir la función
  3. revisión las pruebas de unidad en esa área en general para ver los que debe romper
  4. Ejecutar las pruebas
  5. queridos Fix que se rompen, y si hay alguno en su lista de # 3 que no se rompió, solucionarlos (deberían tener roto). Si se rompió alguna que no identificó, investigue para asegurarse de que, de hecho, sea correcta: corrija la prueba o la función según corresponda.
  6. beneficio ;-)
0

deshacerse de las viejas pruebas y escribir otros nuevos. Es posible que pueda tomar prestado el código de las pruebas antiguas en algunos lugares, pero es mejor que las pruebas estén filosóficamente en línea con lo que está tratando de hacer que intentar cambiar la naturaleza de la prueba anterior.

Las pruebas están ahí para respaldar lo que está tratando de lograr y no deberían perjudicarlo.

0

Creo que hay dos cosas a considerar aquí. Y no sé si estás pensando en solo uno o ambos.

La primera parte es que ha cambiado una característica ya que la especificación (o el comportamiento esperado) cambia. En este caso, creo que lo correcto es eliminar todas las pruebas que describen el comportamiento que ya no son válidas. Como soy flojo, simplemente los comentaría o me los saltaría por el momento. Luego comenzaré a escribir nuevas pruebas (o descomentar/modificar las antiguas) para comenzar a describir el nuevo comportamiento hasta que esté listo.

La segunda parte tiene que ver si su nueva característica cambia una interfaz que otros componentes utilizan y sus pruebas comienzan a fallar solo porque usted cambió la característica. En este caso, solo corregía las pruebas una vez que se terminaba la función.

1

Creo que todos los enfoques son razonables. Obtendrás el mismo resultado.

A algunas personas les gustan los pasos más pequeños, y para trabajar más en la intención original de TDD: escribir una línea de prueba, escribir una línea de código para arreglarlo, repetir. Si es usted, primero trabaje de forma incremental en las pruebas anteriores, evolucione o eliminelas en el nuevo sistema.

Si no te importa morder un trozo más grande, sumérgete en una solución nueva. Me parece que esto es más natural, especialmente cuando la programación de pares puede ser un poco más audaz.

Realmente puede depender de su nivel de confianza y comodidad.

No estoy de acuerdo con la idea de que, idealmente, un cambio solo debería romper una prueba, por lo que es posible que desee refactorizar el código de prueba para que este sea el comportamiento que tiene. Algún tipo de método de configuración compartida puede ser la solución.

Cuestiones relacionadas