Pruebas unitarias: aserciones diferidas con Linq

18

¿Está bien agregar aserciones diferidas como esta?

var actualKittens = actualKittens.Select(kitten => {
    Assert.IsСute(kitten);
    return kitten
});

¿Por qué? Entonces puedo iterar solo una vez, incluso con declaraciones que esperan una colección materializada, por ejemplo:

CollectionAssert.AreEquivalent(expectedKittens, actualKittens.ToList());

Y también podría ser no solo Select, sino un método con iterador definido y con muchas comprobaciones y lógica (por ejemplo, algunos contadores y filtros).

La semilla de la duda es la complejidad de leer y depurar dicho código en caso de que falle la prueba.

SerG
fuente
1
No confiaría en esto para las pruebas, pero a veces está bien hacerlo en el código de producción si no hay una solución mejor. Puedes convertirte en una función auxiliar sequence.WithSideEffect(item => Assert.IsCute(item))para hacerlo más limpio.
Usr
@usr Parece que captó la falla clave de esa manera: efecto secundario de un iterador.
SerG
¿Todavía no tiene que repetir dos veces, una para generar la lista y otra para compararla expectedKittens? Acabas de ocultar las iteraciones detrás de las llamadas a métodos.
IllusiveBrian
@IllusiveBrian En este sentido, en el ejemplo, sí. Todavía es menos que con adicional .All().
SerG

Respuestas:

37

¿Está bien agregar afirmaciones diferidas como esta [..]

No lo es. ¿Por qué? Porque si por alguna razón elimina la segunda afirmación, la prueba aún se volvería verde y pensaría que todavía funciona, pero no funciona, ya que la colección no se enumerará. Si tiene dos o más afirmaciones independientes, seguirán haciendo su trabajo incluso si deshabilita una de ellas.

Considera esta combinación:

Assert.IsTrue(actualKittens.All(x => x.IsCute());
CollectionAssert.AreEquivalent(expectedKittens, actualKittens.ToList());

Ahora, incluso si deshabilita o elimina una de las afirmaciones, la otra seguirá haciendo su trabajo. Además, si olvida materializar la colección, puede llevar más tiempo ejecutarla, pero seguirá funcionando. Las pruebas independientes son más robustas y confiables.

También hay un segundo no . No estoy seguro de cómo otros marcos lo manejan, pero si está utilizando la plataforma MS Test, entonces no sabría qué prueba falló. Si hace doble clic en la prueba fallida, le mostrará la CollectionAssertfalla, pero en realidad fue la anidada la Assertque salió mal y será extremadamente difícil de depurar. Aquí hay un ejemplo:

    [TestMethod]
    public void TestMethod()
    {
        var numbers = new[] { 1, 2, 3 }.Select(x =>
        {
            Assert.Fail("Wrong number.");
            return x;
        });

        // This will fail and you won't be sure why.
        CollectionAssert.AreEqual(new[] { 1, 2, 3 }, numbers.ToList()); 

    }

Esto significa que la primera prueba es realmente inútil porque no ayuda a encontrar un error. No sabe si falló porque un número no era válido o porque ambas colecciones eran diferentes.


¿Por qué? Entonces puedo iterar solo una vez, incluso con declaraciones que esperan una colección materializada

Me pregunto por qué te importa. Estas son pruebas unitarias. No tiene que optimizar cada uno de ellos y, por lo general, las pruebas no requieren millones de elementos, por lo que el rendimiento no debería ser una preocupación.

Tendrá que mantener tales pruebas, ¿por qué debería hacerlas más complejas de lo necesario? Escribe afirmaciones simples que funcionen.

t3chb0t
fuente
Si por alguna razón una aserción necesita ser enterrada en el flujo de control, una forma de asegurarse de que se ejecutó es mantener un contador / indicador que se incremente / establezca en verdadero antes de la aserción anidada. Más tarde, podemos afirmar que el flujo de control esperado se ha tomado al verificar este contador. No es perfecto, pero aborda en gran medida su primera crítica.
amon
1
Además, usted u otra persona volverían a la afirmación diferida dentro de 6 meses y tendrían que perder el tiempo resolviéndola.
DavidTheWin
Hay algo mal con tu ejemplo. Llamar ToListiterará lo enumerable, ¿no?
RubberDuck
1
@RubberDuck sí, fallará y también fallará, sin embargo, no en el Assert.Failsino en el CollectionAsserty no podrá decir qué afirmación realmente salió mal. Quiero decir que VS no se enfocará en Assert.Failel otro ... ahora puedes depurar.
t3chb0t