2008-10-04 21 views
6

Siendo nuevo en el desarrollo basado en pruebas, esta pregunta me ha estado molestando. ¿Cuánto es demasiado? ¿Qué debería probarse, cómo debería probarse y por qué debería probarse? Los ejemplos dados están en C# con NUnit, pero asumo que la pregunta en sí es independiente del idioma.Casos de prueba, "cuándo", "qué" y "por qué"?

He aquí dos ejemplos actuales de mi propia, pruebas de un objeto de lista genérica (siendo probado con cadenas, la función de inicialización añade tres elementos {"Foo", "Bar", "Baz"}):

[Test] 
public void CountChanging() 
{ 
    Assert.That(_list.Count, Is.EqualTo(3)); 
    _list.Add("Qux"); 
    Assert.That(_list.Count, Is.EqualTo(4)); 
    _list[7] = "Quuuux"; 
    Assert.That(_list.Count, Is.EqualTo(8)); 
    _list.Remove("Quuuux"); 
    Assert.That(_list.Count, Is.EqualTo(7)); 
} 

[Test] 
public void ContainsItem() 
{ 
    Assert.That(_list.Contains("Qux"), Is.EqualTo(false)); 
    _list.Add("Qux"); 
    Assert.That(_list.Contains("Qux"), Is.EqualTo(true)); 
    _list.Remove("Qux"); 
    Assert.That(_list.Contains("Qux"), Is.EqualTo(false)); 
} 

El código es bastante auto-comentando, por lo No entraré en lo que está pasando, pero ¿este tipo de cosas lo lleva demasiado lejos? Add() y Remove() se prueban por separado, por supuesto, ¿a qué nivel debería acudir con este tipo de pruebas? ¿Debería incluso tener este tipo de pruebas?

Respuesta

7

Yo diría que lo que realmente está probando son las clases de equivalencia.En mi opinión, no hay diferencia entre agregar una lista que tiene 3 elementos o 7 elementos. Sin embargo, hay una diferencia entre 0 artículos, 1 artículo y> 1 artículos. Probablemente tendría 3 pruebas cada una para los métodos Agregar/Eliminar para estos casos inicialmente.

Una vez que comiencen a aparecer los errores de QA/usuarios, agregaría cada informe de error como un caso de prueba; ver el error reproducir al obtener una barra roja; arregla el error obteniendo una barra verde Cada prueba de "detección de errores" está ahí para quedarse: es mi red de seguridad (léase: prueba de regresión) que incluso si vuelvo a cometer este error, tendré un feedback instantáneo.

+0

La razón por la que lo rellené previamente (usando .Add()) fue para que la mayoría de los métodos, que necesitan trabajar con datos de prueba, tengan algo con lo que trabajar. –

+0

Entiendo eso. Sin embargo, su lista también puede estar vacía, que es un estado válido (es decir, Count debe devolver 0, etc.) Esto es fundamentalmente "diferente" de agregar a una lista que ya tiene elementos, de ahí el término "clases de equivalencia". – Yuval

+0

Tengo una prueba para .Clear() y una prueba para agregar después de una .Clear(), así como una prueba para crear y agregar a una lista que se crea sin capacidad inicial. Creo que todavía estoy cubierto, a menos que se te ocurra otra cosa. –

1

¿Es _list una instancia de una clase que usted escribió? Si es así, yo diría que probarlo es razonable. Aunque en ese caso, ¿por qué estás construyendo una clase de lista personalizada?

Si no se trata de un código que escribió, no lo pruebe a menos que sospeche que tiene alguna falla.


Intento probar el código que es independiente y modular. Si hay algún tipo de función de Dios en el código que tengo que mantener, elimino todo lo posible en las subfunciones y las pruebo de forma independiente. Entonces la función de Dios puede escribirse para ser "obviamente correcta", sin ramificaciones, sin lógica, simplemente pasando resultados de una subfunción bien probada a otra.

+0

Es mi propio código y, por escrito, las pruebas realmente han revelado errores, aunque no sospeché que tuviera errores. En cuanto a por qué estoy reinventando la rueda por así decirlo, necesitaba una clase de tipo List que admitía eventos cuando se agregaban/eliminaban elementos, etc. –

+0

Dado que es su código, entonces sí, escriba pruebas para ello. Incluso si escribirlos es aburrido o se siente como un desperdicio, cada prueba para una clase no trivial puede evitar horas de frustración en el futuro. Las únicas pruebas que no escribo en C# son para cosas como {get; set;} propiedades. –

+0

¿Por qué no simplemente escribir un decorador para la lista genérica predeterminada que dispara esos eventos en add/remove, pasando el trabajo real a la superclase? – jdmichal

6

Piense en sus pruebas como una especificación. Si su sistema puede romperse (o tener errores materiales) sin que sus pruebas fallen, entonces no tiene suficiente cobertura de prueba. Si un único punto de falla hace que se rompan muchas pruebas, es probable que tenga demasiado (o que esté demasiado unido).

Esto es realmente difícil de definir de una manera objetiva. Supongo que diría que estoy equivocado por el lado de las pruebas demasiado. Entonces, cuando las pruebas comiencen a molestarlo, esas son las pruebas particulares para refactorizar/reutilizar (porque son demasiado frágiles o prueban lo incorrecto, y sus fallas no son útiles).

2

Algunos consejos:

  1. Cada caso de prueba sólo se debe probar una cosa. Eso significa que la estructura del testcase debe ser "setup", "execute", "assert". En tus ejemplos, mezclas estas fases. Intenta dividir tus métodos de prueba. Eso hace que sea más fácil ver exactamente lo que está probando.

  2. Intente darle a sus métodos de prueba un nombre que describa lo que está probando. Es decir. los tres testcases contenidos en su ContainsItem() se convierten en: containsReportsFalseIfTheItemHasNotBeenAdded(), containsReportsTrueIfTheItemHasBeenAdded(), containsReportsFalseIfTheItemHasBeenAddedThenRemoved(). Encuentro que forzarme a pensar en un nombre descriptivo como ese me ayuda a conceptualizar lo que tengo que probar antes de codificar la prueba real.

  3. Si hace TDD, debe escribir sus primeras pruebas y solo agregar código a su implementación cuando tenga una prueba que falla. Incluso si no lo hace, le dará una idea de cuántas pruebas son suficientes. Alternativamente, use una herramienta de cobertura. Para una clase simple como un contenedor, debe apuntar a una cobertura del 100%.

+0

Antes de ahora, no he hecho TDD, este es mi primer intento, y estoy convirtiendo una pequeña biblioteca (6-8 clases más o menos) de otro proyecto y escribiendo casos de prueba como introducción. Entiendo las ventajas de escribir la prueba primero, pero en este caso, simplemente no sabía nada mejor. –

+0

"containsReportsFalseIfTheItemHasBeenAddedThenRemoved" hoooooooly shit! Al escribir pruebas, no hay nada de malo con "TestContains1", "TestContains2", etc. –

+1

Nada excepto que cuando la prueba falla, no tiene idea de qué falló realmente sin mirar el código de prueba. ¿Todo para guardar escribiendo algunos caracteres una vez y nunca volver a mirarlo? – jdmichal

Cuestiones relacionadas