Uso de Assert.Concluyente


Me pregunto cómo alguien debería usar Assert.Concluyente().

Lo estoy usando si mi prueba unitaria estaría a punto de fallar por una razón que no sea para lo que es la prueba.

Por ejemplo, tengo un método en una clase que calcula la suma de una matriz de ints. En la misma clase, también hay un método para calcular el promedio del elemento. Se implementa llamando a sum y dividiéndola por la longitud del array.

Escribir una prueba unitaria para Sum() es simple. Obstante, cuando escribo una prueba para Average (), y Sum () falla, entonces Average () es probable que falle también.

El fallo de Average no es explícito sobre la razón por la que falló; falló por una razón distinta a la que debería probar. Es por eso que verificaría si Sum() devuelve el resultado correcto, de lo contrario lo Afirmo.Concluyente().

¿Debe considerarse esto una buena práctica? Lo que es Afirmar.¿No concluyente para qué? O debería más bien resolver el ejemplo anterior por medio de un aislamiento Marco?

Author: Johannes Rudolph, 2009-08-02

4 answers

Cuando uso VS para generar las pruebas unitarias, obtuve Assert.Inclusivo para los métodos de prueba generados y por lo general cambio la afirmación por lo que algo más cuando los trabajo. Uso los signos de interrogación de Assert.No concluyente en el resultado de la prueba como marcadores para decirme rápidamente qué pruebas aún no he completado.

Bueno, es solo la forma en que lo uso. De su nombre "Inconcluso", supongo que se puede utilizar para indicar su estado indeterminista, siempre y cuando documente lo que medio.

Sin embargo, a partir de la descripción de su método Average(), creo que tal vez su prueba unitaria no es lo suficientemente atómica como para cubrir solo una "unidad", un escenario específico. A veces, escribo 2 o 3 métodos de prueba unitarios para un solo método. O puede dividir su método Average() en métodos más pequeños que cubren responsabilidades individuales. De esa manera, puede probar unitariamente esos métodos más pequeños antes de probarle unitariamente Average() uno.


[14] Johannes, [15]]}

Así es como implementaría la Sum() y Average() métodos.

public static class MyMath
{
    private static void ValidateInput(ICollection<int> numbers)
    {
        if (numbers == null)
            throw new ArgumentNullException("numbers", "Null input.  Nothing to compute!");
        if (numbers.Count == 0)
            throw new ArgumentException("Input is empty.  Nothing to compute!");
    }

    public static int Sum(int[] numbers)
    {
        ValidateInput(numbers);

        var total = 0;
        foreach (var number in numbers)
            total += number;

        return total;
    }

    public static double Average(int[] numbers)
    {
        ValidateInput(numbers);
        return Sum(numbers) / numbers.Length;
    }
}

Para simplificar, solo arrojo ArgumentException excepciones del método ValidateInput(ICollection<int>). También puede comprobar la posibilidad de desbordar y lanzar OverflowException en el método ValidateInput(ICollection<int>).

Dicho esto, así es como probaría la función Average(int[]).

[TestMethod]
public void AverageTest_GoodInput()
{
    int[] numbers = {1, 2, 3};
    const double expected = 2.0;
    var actual = MyMath.Average(numbers);
    Assert.AreEqual(expected, actual);
}

[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void AverageTest_NullInput()
{
    int[] numbers = null;
    MyMath.Average(numbers);
}

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void AverageTest_EmptyInput()
{
    var numbers = new int[0];
    MyMath.Average(numbers);
}

Con esta configuración de pruebas, puedo estar seguro de que cuando todas las pruebas pasan, mi función es correcta. Bueno, excepto por el caso de desbordamiento. Ahora puedo volver al método ValidateInput(ICollection<int>) para agregar lógica para verificar desbordamiento, luego agregue una prueba más para esperar que se lance OverflowException para el tipo de entradas que causan desbordamiento. O hacerlo en el orden opuesto si te gusta acercarte usando TDD.

Espero que esto ayude a aclarar la idea.

 14
Author: tranmq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-03 19:53:45

La prueba inconclusa es una prueba para la que no se puede determinar el resultado. Por ejemplo, qué pasaría si tuviera una prueba que usa algún tipo de recurso externo (conexión a Internet, por ejemplo). Si la conexión no está disponible actualmente, esto no significa realmente que la prueba sea un error. Por otro lado, no debes simplemente marcarlo como exitoso sin realmente ejecutarlo. Así que lo marca como inconcluso y esto se puede ver en el informe de la prueba.

NOTA: En general, usted no debe usar tales recursos externos en sus pruebas, ya que esto puede hacer que las pruebas sean frágiles.

Para las pruebas que aún no se han terminado, utilizo el atributo Explicit de MbUnit.

 24
Author: Igor Brejc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-02 18:10:23

Solo afirmo.No concluyente en las pruebas unitarias que aún no he escrito. A veces cuando escribo algo me doy cuenta de algún caso de esquina que no quiero perder. Así que salto rápidamente por encima, escribir el método de prueba con un nombre descriptivo y añadir una sola línea de Afirmación.Concluyente.

La razón para hacer esto es que proporciona documentación sobre cosas que necesito probar sin interrumpir demasiado mi flujo de trabajo. También hace posible filtrar los fallos de prueba rápidamente en el lista de resultados. Tener un fracaso inconcluso significa que no he roto nada, solo más pruebas para escribir.

 9
Author: JaredPar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-02 17:06:35

Afirmar.Inconcluso indica que:

Todavía no he escrito la prueba; solo he creado el método de prueba

-o-

Mi prueba tiene una dependencia y esa dependencia no está disponible. Por ejemplo

List<Customer> custs = o.GetAllCustomers();
if (custs.Count == 0)
{
  Assert.Inconclusive("No customers to test");
  return;
}
 7
Author: DavidGiard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-04 19:45:02