2012-07-05 11 views
14

Como recién llegado a TDD estoy luchando con las pruebas de unidades de escritura que se ocupan de las colecciones. Por ejemplo, en el momento en que estoy tratando de llegar a algunas scearios prueba para probar esencialmente el siguiente métodoTDD - pruebas de escritura para un método que itera/trabaja con colecciones

int Find(List<T> list, Predicate<T> predicate); 

Cuando el método debe devolver el índice del primer elemento de la lista list que coincide con el predicado predicate. Hasta ahora, los únicos casos de prueba que he sido capaz de llegar a haber estado en la línea de

  • list Cuando no contiene elementos - devuelve -1
  • Cuando list contiene 1 elemento que coincida con predicate - Devuelve 0
  • Cuando list contiene 1 elemento que no coincide con predicate - devuelve -1
  • Cuando list contiene 2 elementos ambos de los cuales coinciden con predicate - retorno 0
  • Cuando list contiene 2 artículos, el primero de los cuales coinciden con predicate - volver 0
  • etc ...

Como se puede ver sin embargo, estos casos de prueba son numerosas y no lo hacen de manera satisfactoria probar el comportamiento real que realmente quiero. El matemático en mí quiere hacer algún tipo de TDD por inducción

  • Cuando list no contiene elementos - devuelve -1
  • Cuando list contiene N elementos llaman predicate en el primer elemento y luego llamar de forma recursiva Find en el elementos N-1 restantes

Sin embargo, esto introduce una recursividad innecesaria. ¿Qué tipo de casos de prueba debo buscar escribir en TDD para el método anterior?


Como acotación al margen del método que estoy tratando de probar que realmente es simplemente Find, simplemente para una colección específica y predicado (que puedo escribir de forma independiente para los casos de prueba). Seguramente debería haber una forma de evitar escribir en cualquiera de los casos de prueba anteriores y simplemente probar que el método llama a alguna otra implementación de Find (por ejemplo, FindIndex) con los argumentos correctos?

Tenga en cuenta que, en cualquier caso todavía me gustaría saber cómo pude unidad de prueba Find (u otro método como él), incluso si resulta que en este caso yo no necesito.

+1

¿Qué marco de pruebas unitarias está utilizando? –

+0

@Kevin Rhino se burla + MSTest/el marco de prueba de unidad de Visual Studio – Justin

Respuesta

9

Si find() funciona, entonces debería devolver el índice del primer elemento que coincida con el predicado, ¿no?

Por lo tanto, necesitará una prueba para el caso de la lista vacía, una para el caso de los elementos no coincidentes y otra para el caso del elemento correspondiente. Yo encontraría eso suficiente. En el transcurso de TDDing find() podría escribir un caso especial de primer elemento-pasadas, que podría falsificar fácilmente.Probablemente escribiría:

emptyListReturnsMinusOne() 
singlePassingElementReturnsZero() 
noPassingElementsReturnsMinusOne() 
PassingElementMidlistReturnsItsIndex() 

Y espero que esa secuencia guíe mi correcta implementación.

+2

Es posible que desee agregar una prueba 'PassingElementAtEndOfListReturnsItsIndex()'. – Philipp

+1

Es difícil para mí imaginar una solución realista que supere la prueba de la lista intermedia pero no supere la prueba de endOfList. –

+1

Podría imaginarme que la situación en la que alguien decide que un bucle for sería más rápido que un foreach y presenta un error de apagado por uno. Esa persona sería una idiota, por supuesto, pero personalmente escribo mis pruebas para idiotas (usualmente soy el idiota que resulta :)) –

0

Sobre la base de su requisito para Find método, esto es lo que haría la prueba:

  1. list es null - tiros ArgumentNullException o devuelve -1
  2. list no contiene elementos - devuelve -1
  3. predicate es null - lanza ArgumentNullException o devuelve -1
  4. list contiene un elemento que no coincide con las declaraciones de predicate - -1
  5. list contiene un elemento que coincide con el predicate - devuelve 0
  6. list contiene varios elementos, pero no hay ningún elemento coincide con el predicate - devuelve -1
  7. list contiene varios elementos que coinciden con el predicate - devuelve el índice del primer partido

Básicamente, primero debería probar los casos finales: argumentos nulos, lista vacía. Después de eso, un elemento prueba. Finalmente, pruebe la coincidencia y la no coincidencia para varios elementos.

Para null argumentos, puede lanzar una excepción o devolver -1, según su preferencia.

0

No cambie la lista , cambie predicados.

Piensa en cómo se llamará al método. Cuando alguien llama al método Find, ya tendrá una lista y necesitará pensar en los predicados. Así que pensar en los buenos ejemplos que demuestran el comportamiento de Find:

Ejemplo: Usando misma lista 3, 4 para todos los casos de prueba hace que sea fácil de entender:

  1. predicado < 5 coincide con los dos números (devuelve 1)
  2. Predicado == 3 coincide 3 (devuelve 0)
  3. Predicado == 0 coincide con ninguno (retornos) -1

Esto es realmente todo lo que necesita para especificar el comportamiento y cambiando los predicados en lugar de la lista que dan buenos ejemplos de cómo utilizar el método Find. Una lista con cero, uno o dos elementos no está realmente cambiando el comportamiento de Find y no realmente cómo se usará el método.Siga SECO con sus cajas de prueba, concéntrese en especificar el comportamiento que no demuestra que el código es correcto o terminará gastando todo su tiempo escribiendo pruebas.

2

las pruebas de detención cuando el miedo se sustituye por el aburrimiento - Kent Beck

En este caso, ¿cuál es la probabilidad de que da una prueba de aprobación para

  • "Cuando la lista contiene 2 elementos tanto cuyo predicado coincide - devuelve 0 "

¿La siguiente prueba fallará?

  • "Cuando la lista contiene 5 artículos los cuales predicado de comparación - 0 de retorno"

me gustaría escribir la primera porque me temo que el comportamiento no funciona para varios elementos. Sin embargo, una vez que 2 funciona, escribir otro para 5 es simplemente tedioso (a menos que haya una suposición codificada de 2 en el código de producción ... que debería haber sido refactorizada. Incluso si no lo es, simplemente modificaría la prueba existente para tener 5 en lugar de 2 y hacerlo funcionar para el caso general).

Así que escriba pruebas para cosas significativamente diferentes. En este caso, liste con (cero, uno, muchos) elementos y (contiene/no contiene) operando

0

Para tratar de responder a un lado: No tengo ninguna experiencia con Rhino se burla, pero creo que debería tener algo similar a FakeItEasy (?):

var finder = A.Fake<IMyFindInterface>(); 

// ... insert code to call IMyFindInterface.Find(whatever) here 

A.CallTo(() => finder.find(A<List>.That.Matches(
        x => x.someProperty == someValue))).MustHaveHappened(); 

al poner la aplicación de Búsqueda() detrás de una interfaz, y luego pasar el método que utiliza la interfaz de una falsificación, se puede comprobar que el método se llama con ciertos parámetros (El MustHaveHappended() hará que la prueba falle si la llamada esperada no se completa).

Puesto que usted sabe que la implementación real de IMyFindInterface simplemente pasa la llamada a una implementación ya la confianza, esto debe ser una buena prueba suficiente para verificar que el código que está probando las llamadas del Find-implementación en la correcta camino.

Este mismo procedimiento puede usarse siempre que solo desee asegurarse de que su código (la unidad que está probando) llama a algún componente en el que ya confíe de forma correcta abstrayendo ese componente en sí, exactamente lo que queremos cuando unidad pruebas.

Cuestiones relacionadas