¿Cómo debo probar mi código TEST?

22

Una de las pocas cosas en las que la mayoría de los desarrolladores de software están de acuerdo es que no debe confiar en que el código funcione correctamente a menos que lo pruebe. Si no lo prueba, puede tener errores ocultos que solo le causarán más trabajo en el futuro.

Entiendo cómo probar mi código normal, pero ¿cómo debo probar mi código de prueba para asegurarme de que pueda encontrar e informar errores de manera efectiva cuando estén presentes? Personalmente, he sido lo suficientemente estúpido como para escribir casos de prueba erróneos que pasarían cuando no deberían hacerlo, lo que en primer lugar anula el propósito de mis pruebas de escritura. Afortunadamente, encontré y arreglé los errores a tiempo, pero según el mantra de pruebas, parece que ningún conjunto de pruebas estaría completo sin tener su propio conjunto de pruebas para asegurarse de que funcionó.

Me parece que la mejor manera de hacer esto sería asegurarme de que la prueba falla para el código defectuoso. * Si paso 2 minutos alternando agregando errores al código y asegurándome de que falla, debería tener un grado aceptable de confianza de que las pruebas 'funcionan'. Esto me lleva a mi segunda pregunta: ¿Cuáles son buenas maneras de introducir errores para asegurarse de que los casos de prueba los atrapen? Debo comentar al azar las declaraciones, asegurarme de que if-elsese ejecuta la rama incorrecta de una negando su condición y cambiar el orden de ejecución del código con efectos secundarios, etc., hasta que esté satisfecho de que mis pruebas atraparán máserrores comunes? ¿Cómo validan los desarrolladores profesionales que sus pruebas realmente hacen lo que se supone que deben hacer? ¿Asumen que las pruebas funcionan o también se toman el tiempo para evaluarlas? Si es así, ¿cómo prueban las pruebas?

No estoy sugiriendo que las personas pasen tanto tiempo probando sus pruebas y luego probando las pruebas para sus pruebas que en realidad nunca escriben el código real, pero he hecho cosas lo suficientemente estúpidas como para sentir que podría beneficiarme un poco de 'meta-pruebas', y tenía curiosidad sobre la mejor manera de hacerlo. :RE

* Podría verificar si la prueba pasa al probar el código 'libre de errores', pero usar el código como una especificación para la prueba parece bastante al revés ...

Gordon Gustafson
fuente
Parece que no tiene confianza en sus pruebas unitarias, ¿probablemente porque carece de mucha experiencia en escribir pruebas? En ese caso, no sería razonable escribir más pruebas y esperar un resultado diferente. Simplemente siga haciendo lo que está haciendo, sea lo más exhaustivo posible (pruebe tanto el fracaso como el éxito) y pronto sus pruebas unitarias comenzarán a pagarse por sí mismas, y su confianza en ellas crecerá.
MattDavey
Posible duplicado de ¿Cómo probar las pruebas?
mosquito
Antes de usar más herramientas, use mejor sus herramientas reales . Escriba menos pruebas, pero más eficientes y mejores pruebas escritas. No puedes confiar en algo que no entiendes.
Steve Chamaillard

Respuestas:

16

El flujo estándar para TDD es:

  1. Escribe una prueba reprobatoria. (Rojo)
  2. Realice el cambio de código más pequeño que lo haga pasar (Verde)
  3. Refactor (Manteniéndolo verde)

La prueba para sus pruebas en este caso es el paso 1: asegúrese de que la prueba falla antes de realizar cambios en el código.

Otra prueba que me gusta es si puede eliminar algún código y volver a implementarlo de una manera diferente, y sus pruebas fallan después de la eliminación, pero funcionan con un algoritmo diferente.

Como con todas las cosas, no hay una bala mágica. Olvidar escribir una prueba requerida es tan fácil para un desarrollador como olvidar escribir el código. Al menos si estás haciendo ambas cosas, tienes el doble de oportunidades para descubrir tu omisión.

Bringer128
fuente
44
Contabilidad doble: las pruebas unitarias prueban el código de producción y viceversa. Son dos formas diferentes de plantear el mismo problema. Al igual que en la contabilidad doble, donde registra sus transacciones de dos maneras diferentes y ambas deben obtener los mismos totales.
EricSchaefer
La pregunta es sobre el problema cuando el paso 2 hace que la prueba sea verde a pesar de que el código todavía tiene errores. Ejemplo simple: tiene una función que debe devolver un puntero a un objeto de lista no vacío. Su prueba prueba si el puntero es nully falla en el paso 1. Realiza el cambio de código más pequeño que lo hace pasar al devolver una lista vacía. La prueba ahora es "verde" porque tiene dos errores.
Christian Hackl
¡@ChristianHackl en esa etapa de desarrollo es una implementación perfecta! Debe agregar una (o más) pruebas que fallan al principio para especificar aún más el comportamiento esperado. Posteriormente lo implementa, haciendo estas pruebas verdes.
Andy
@Andy: ¿Te importaría explicar cómo es una implementación perfecta cuando tengo un error tanto en el código como en la prueba, y uno me impide notar al otro? (El error en el código es que se devuelve una lista vacía, y el error en la prueba es que compruebo nully no estoy vacío.)
Christian Hackl
@ChristianHackl tienes razón según el cheque vacío. Eso, de hecho, también debe hacerse en una prueba. Cuando traduce sus requisitos a pruebas, paso a paso, hay poco espacio para errores. Excepto aquellos en los que no cumple con las especificaciones (como pasar por alto un cheque no vacío).
Andy
9

Un enfoque es la prueba de mutación , utilizando una herramienta como Jester :

Jester realiza algún cambio en su código, ejecuta sus pruebas y, si las pruebas pasan, Jester muestra un mensaje que dice lo que cambió.

parsifal
fuente
4

¿Pruebas para pruebas? No te vayas por ese camino. Entonces probablemente necesitará exámenes para exámenes para exámenes, y luego exámenes para exámenes para exámenes para exámenes ... ¿dónde se detiene?

El flujo de prueba habitual es así, y como desarrollador, pasará la mayor parte de su tiempo en los puntos 1-3:

  1. Código
  2. Pruebas unitarias
  3. Pruebas de integración
  4. Sistema / otro automatizado
  5. QA / probadores humanos

Si paso 2 minutos alternativamente agregando errores al código (...)

Su código eventualmente "desarrollará" sus propios errores, no pierda el tiempo introduciéndolos a mano. Sin mencionar, ¿es algo que sabías por adelantado realmente un error? Los errores vendrán, no me preocuparía por eso.

Debo comentar al azar las declaraciones, asegúrese de que se ejecuta la rama incorrecta de un if-else negando su condición (...)

Este es realmente un enfoque viable para verificar si realmente prueba lo que cree que hace. No creo que siempre sea tan bueno, ya que sufre el mismo problema que "prueba por prueba por prueba ...": ¿cuándo deja de alterar el código sabiendo que el código que está probando funciona al 100%?

También es bueno recordar los consejos clásicos de programación pragmáticos de todos los tiempos: no los necesitará . Sé ágil, escribe pruebas y codifica errores reales, en lugar de aquellos hipotéticos que pueden aparecer o no.

km
fuente
3
No me preocupa que mi código produzca sus propios errores, me preocupa que mis pruebas los detecten cuando sucedan. Si mis pruebas son defectuosas, no harán su trabajo y pensaré que me he librado de una cierta clase de error cuando todavía existen, lo que hace que mi trabajo sea más difícil porque estoy viendo resultados de prueba inexactos (pasar cuando deberían fallar).
Gordon Gustafson
@CrazyJugglerDrummer: sus pruebas no detectarán todos los errores, eso es seguro. No sirven para ese propósito: aquí es donde entra el control de calidad. Si lo hicieran, significaría que el software está libre de errores, a menos que el código fuente cambie, lo que nunca he visto.
km
3

Por construcción, el código funcional y el código de prueba se prueban uno contra el otro. Queda un problema: el caso de los errores de modo común, cuando un error en el código funcional está oculto por un error en el código de prueba. TDD no es inmune a este efecto. Esta es la razón por la cual las pruebas generalmente se realizan en múltiples niveles por diferentes personas para disminuir esta probabilidad.

Mouviciel
fuente
0

Usted prueba su unidad de prueba una vez cuando la escribe, en el depurador. Luego lo dejas solo y te olvidas de eso. No hay ningún problema aquí.

Considera esto. ¿Cuál es el propósito de una prueba unitaria? Te notifica cuando alguno de los numerosos cambios que harás en tu programa principal cambia accidentalmente la lógica en ese programa. Desea tener eso porque sabe que cualquier cambio potencialmente rompe algo. Es por eso que no hay ningún problema si no prueba su prueba: no se mete con su prueba hasta que cambie deliberadamente la lógica de su programa (lo que requeriría que revise la prueba y la pruebe una vez más), por lo que su No es probable que la prueba se rompa accidentalmente.

Martin Maat
fuente
-2

Hay una prueba de mutación que evalúa y mide la idoneidad y la calidad de la prueba.

Podemos usar esto para evaluar "la prueba" en sí.

En resumen, podemos evaluar nuestra prueba (por ejemplo, TestA) probando que TestA puede encontrar la diferencia entre el código y sus códigos de mutación (código muy similar pero ligeramente diferente con el código original).

Si TestA no puede encontrar la diferencia entre el código y sus códigos de mutación, significa que TestA tiene regulaciones demasiado estrictas para probar el código original.

Cazador de pollo
fuente