¿Adherirse a una afirmación por prueba es una consistencia tonta en este caso?

10

Tengo una clase que estoy probando. La clase tiene una función:apply(List<IRule> rules, List<ITarget> targets);

En una prueba, quiero asegurarme de que cada objetivo se haya pasado a una regla, a la:

rule1.AssertWasCalled(fnord => fnord.Test(target1));
rule1.AssertWasCalled(fnord => fnord.Test(target2));
rule1.AssertWasCalled(fnord => fnord.Test(target3));

Me parece que limitarme a una sola declaración de afirmación sería bastante difícil . ¿Estoy en lo cierto en esta suposición, o hay alguna otra forma en que pueda afirmar que cada objetivo, de hecho, ha sido probado?

Wayne Werner
fuente
¡Puedo ver los fnords!
Ross Patterson

Respuestas:

15

Las tres afirmaciones son, en esencia, una prueba. Está probando el comportamiento de un método en una colección para asegurarse de que cada elemento haya sido un parámetro para una llamada específica (es decir, que cada elemento se haya procesado correctamente).

Configurar los datos tres veces y en tres métodos diferentes es un desperdicio y menos legible que la alternativa de tener varias afirmaciones.

La "regla" de afirmación única se trata más de hacer afirmaciones de diferentes tipos en los mismos métodos (esencialmente probar cosas diferentes), lo que realmente no se aplica en este caso, donde está probando un solo comportamiento.

Oded
fuente
3
De hecho: la regla es más una afirmación lógica por prueba unitaria. Podría agruparlos en un nivel superior para afirmar que podría reutilizarlos en diferentes pruebas.
Laurent Bourgault-Roy
5

Creo que esta afirmación por regla de prueba existe para mantener sus pruebas enfocadas en un tema. Si prueba 20 cosas en una prueba, es realmente difícil saber cuál es su cobertura. Sabes que está causando un problema cuando no puedes nombrar el método de prueba sin la palabra y en ella. Por ejemplo, si su método de prueba se denominaría con mayor precisión como testFooIsTrueAndDbExistsAndBarIsNullAndAnExceptionDoesntOccur(), probablemente esté probando demasiado en una prueba.

En su caso, creo que probablemente esté bien afirmar tres veces. Si desea que su código sea más legible, puede extraer esas tres afirmaciones en un método llamado assertWasCalledOnTargets(...).

Daniel Kaplan
fuente
3

Para su ejemplo particular, puede salirse con la afirmación de "uno" si hace algo como:

foreach target in targets
{
     rule1.AssertWasCalled(fnord => fnord.Test(target))
}

Es lo que hago para evitar sentirme culpable por tener múltiples afirmaciones en una prueba.

Jeff B
fuente
He hecho esto antes. No es una mala manera de irse. Es fácil de leer y puedes entender la naturaleza de lo que está haciendo.
CokoBWare
1

He luchado con este también.

El purista (en mí) insiste en una afirmación por prueba, así sabré * exactamente * dónde explotaron las cosas.

Y luego me encuentro cortando / pegando mucho del mismo código de configuración de prueba redundante. Después de la tercera o cuarta capa de esto, comienzas a decir "¡Oy! ¡Suficiente!"

Mi compromiso ha sido encontrar los aspectos que "nunca" se rompen. Y pondré esas piezas juntas y luego agregaré un nuevo elemento que podría romperse. Para ser claros, superponer varias áreas volátiles en una prueba sería una violación de este compromiso.


fuente
1
Deberías echarle un vistazo Assume. Acabo de enterarme de eso hoy.
Wayne Werner
1

Si el código de configuración para target1es diferente del código de configuración para target2, este tipo de corte de esquina tiende a conducir a un código de inicialización de prueba demasiado largo. Esto a su vez es un desastre o termina siendo refactorizado y reutilizado. Si sus pruebas son lo suficientemente complejas como para justificar su refactorización, su prueba probablemente esté probando más de una cosa.

Si el código de configuración para cada objetivo es esencialmente el mismo, probablemente sea excesivo dividir su prueba en múltiples pruebas individuales.

Si target1y target2son diferentes implementaciones de la misma interfaz, en su lugar debe ser la adición de una unidad de prueba a la interfaz (y permitiendo que su marco de pruebas para generar una prueba para cada aplicación de esa interfaz).

Brian
fuente