Aserciones de MSTest

Use las clases Assert del espacio de nombres Microsoft.VisualStudio.TestTools.UnitTesting para comprobar la funcionalidad específica. Un método de prueba ejecuta el código de la aplicación, pero notifica la corrección solo cuando se incluyen instrucciones Assert .

Información general

MSTest proporciona tres clases de aserción:

Class Propósito
Assert Aserciones de uso general para valores, tipos y excepciones.
StringAssert Aserciones específicas de cadenas para patrones, subcadenas y comparaciones.
CollectionAssert Aserciones de colección para comparar y validar colecciones.

Importante

Para el nuevo código, use siempre la Assert clase . Es probable que las StringAssert clases y CollectionAssert estén en desuso en una versión futura. Se mantienen principalmente por compatibilidad con versiones anteriores, pero no se recomiendan porque la división de aserciones entre tres tipos daña la detectabilidad.

Todos los métodos de aserción aceptan un parámetro de mensaje opcional que se muestra cuando se produce un error en la aserción, lo que le ayuda a identificar la causa:

Assert.AreEqual(expected, actual, "Values should match after processing");

La clase Assert.

Use la clase Assert para comprobar que el código sometido a prueba se comporta según lo previsto.

Nota:

A partir de MSTest 4.0, todas las Assert API capturan la expresión de argumento e incluyenla en mensajes de error. Este soporte proporciona diagnósticos más completos sin un parámetro message manual.

Métodos de aserción comunes

[TestMethod]
public async Task AssertExamples()
{
    // Equality
    Assert.AreEqual(5, calculator.Add(2, 3));
    Assert.AreNotEqual(0, result);

    // Reference equality
    Assert.AreSame(expected, actual);
    Assert.AreNotSame(obj1, obj2);

    // Boolean conditions
    Assert.IsTrue(result > 0);
    Assert.IsFalse(string.IsNullOrEmpty(name));

    // Null checks
    Assert.IsNull(optionalValue);
    Assert.IsNotNull(requiredValue);

    // Type checks
    Assert.IsInstanceOfType<IDisposable>(obj);
    Assert.IsNotInstanceOfType<string>(obj);

    // Exception testing (MSTest v3.8+)
    Assert.ThrowsExactly<ArgumentNullException>(() => service.Process(null!));
    await Assert.ThrowsExactlyAsync<InvalidOperationException>(
        async () => await service.ProcessAsync());
}

El método Assert.That

A partir de MSTest 4.0, Assert.That evalúa cualquier expresión booleana y genera un mensaje de error claro. Para obtener diagnósticos más enriquecidos, Assert.That usa [CallerArgumentExpression] para capturar automáticamente el texto de la expresión.

Assert.That(order.Total > 0);

API disponibles

Nota:

A partir de MSTest 3.8, las aserciones de colección incluyen Assert.Contains, Assert.DoesNotContain, Assert.HasCount, Assert.IsEmpty, Assert.IsNotEmptyy Assert.ContainsSingle.

A partir de MSTest 3.10, las aserciones de comparación incluyen Assert.IsInRange, Assert.IsGreaterThan, Assert.IsGreaterThanOrEqualTo, Assert.IsLessThanAssert.IsLessThanOrEqualTo, , y Assert.IsPositiveAssert.IsNegative.

A partir de MSTest 3.10, las aserciones de coincidencia de cadenas incluyen Assert.StartsWith, Assert.EndsWith, Assert.MatchesRegex, Assert.DoesNotStartWith, Assert.DoesNotEndWithy Assert.DoesNotMatchRegex.

A partir de MSTest 4.1 Assert.IsExactInstanceOfType y Assert.IsNotExactInstanceOfType requieren una coincidencia exacta de tipo. A diferencia de Assert.IsInstanceOfType, estos métodos no coinciden con los tipos derivados.

Nuevas aserciones de colección y equivalencia en MSTest 4.3

Nota:

Los siguientes métodos de aserción se introdujeron en MSTest 4.3.0.

  • Assert.AreSequenceEqual / Assert.AreNotSequenceEqual : comparación de secuencia de elementos. Pase SequenceOrder.InAnyOrder para omitir el orden de los elementos.
  • Assert.AreEquivalent / Assert.AreNotEquivalent — comparación estructural profunda de dos objetos o colecciones.
  • Assert.ContainsAll / Assert.DoesNotContainAll : aserte que una colección contiene (o no contiene) todos los elementos esperados.
  • Assert.AreAllNotNull — afirma que todos los elementos de una colección no son null.
  • Assert.AreAllDistinct — aserte que todos los elementos de una colección son distintos.
  • Assert.AreAllOfType : aserte que cada elemento de una colección es de un tipo esperado.

Al comparar colecciones, prefiere estos métodos sobre Assert.AreEqual, que compara las referencias en lugar de los elementos.

MSTest 4.3 también agrega:

  • La API experimental Assert.AddValueFormatter para personalizar cómo se representan los valores en los mensajes de error de aserción.
  • Span<T> y Memory<T>, sobrecargas de Assert.HasCount.
  • Mensajes de error de aserción estructurados para Assert.IsTrue, Assert.IsFalse, Assert.IsNully Assert.IsNotNull que incluyen la expresión evaluada.
  • Sobrecargas para mensajes de cadenas interpoladas en los métodos asincrónicos Assert.ThrowsAsync/Assert.ThrowsExactlyAsync, y rechazo de delegados que devuelven ValueTask<TResult> y que, de otro modo, no se esperaría su finalización.
  • Complete los detalles de la excepción, incluidos los seguimientos de pila y las excepciones internas, en Assert.Throws* los mensajes de error.
  • Pilas de errores de aserción que ocultan marcos de implementación de MSTest y representan valores numéricos integrados con precisión completa.

Assert.AddValueFormatter devuelve un IDisposable registro. Elimine el registro para quitar el formateador. El formateador solo se aplica al contexto asincrónico actual, por lo que las pruebas paralelas pueden usar diferentes formateadores sin cambiar la salida de los demás. Dado que la API es experimental en MSTest 4.3, confirme o suprima el MSTESTEXP diagnóstico antes de usarlo.

Aserciones no excluyentes con Assert.Scope()

Importante

Assert.Scope() es una API experimental. Su uso genera el diagnóstico MSTESTEXP, que debes suprimir (por ejemplo, con #pragma warning disable MSTESTEXP o en el archivo .editorconfig de tu proyecto) para reconocer que la estructura y el comportamiento de la API pueden cambiar en futuras versiones.

De forma predeterminada, cada aserción genera una excepción AssertFailedException en cuanto falla, lo que termina la prueba inmediatamente. Assert.Scope() introduce aserciones suaves: mientras un ámbito está activo, los errores de aserción se recopilan en lugar de generarse, por lo que la ejecución continúa y puede ver todos los errores del ámbito a la vez. Cuando se elimina el ámbito, los errores recopilados se notifican juntos:

[TestMethod]
public void ValidatePerson()
{
    using (Assert.Scope())
    {
        Assert.AreEqual("Jane", person.FirstName); // failure collected, execution continues
        Assert.AreEqual("Doe", person.LastName);   // failure collected, execution continues
        Assert.IsTrue(person.IsActive);            // failure collected, execution continues
    }
    // On Dispose, all collected failures are reported together.
}

Cuando se elimina el ámbito:

  • Si se recopiló exactamente un error, se genera el AssertFailedException original.
  • Si se produjeron varios errores, se lanza un único AssertFailedException que los engloba a todos en un AggregateException.

Las condiciones posteriores no se aplican dentro de un ámbito

Como una aserción con errores ya no genera una excepción dentro de un ámbito, el código que se ejecuta después no puede confiar en que la aserción se haya superado. Esto se aplica a cada condición posterior, incluida la nulabilidad y el restricción de tipos:

using (Assert.Scope())
{
    Assert.IsNotNull(item);
    // 'item' might still be null here: the failure was collected, not thrown.
    Assert.AreEqual("expected", item.Value);
    // 'item.Value' might not equal "expected" either.
}

Si una aserción con error provocaría NullReferenceException (o cualquier otra excepción) en una línea posterior dentro del ámbito, esa excepción secundaria es un síntoma del error ya recopilado, no un error independiente. El error de aserción original se sigue notificando cuando se elimina el ámbito.

Las aserciones de devolución de valores devuelven null/default en caso de error dentro de un ámbito

Algunas aserciones devuelven un valor en caso de éxito; por ejemplo, Throws y ThrowsExactly devuelven la excepción capturada, y ContainsSingle devuelve el elemento coincidente. Cuando se produce un error en una de estas aserciones dentro de un ámbito, se recopila el error y el método devuelve null/default en lugar de generar:

using (Assert.Scope())
{
    // No exception is thrown by the lambda, so the assertion fails. The failure is
    // collected and 'ex' is null. Accessing 'ex' below throws NullReferenceException.
    InvalidOperationException ex = Assert.Throws<InvalidOperationException>(() => { });
    _ = ex.Message; // NullReferenceException—don't use the return value in a scope
}

No se base en el valor devuelto por una aserción suave dentro de un ámbito. Si necesita el valor devuelto (como la excepción detectada), llame a la aserción fuera del ámbito o reestructure la prueba para que nada dependa del valor devuelto hasta que se elimine el ámbito.

Assert.Fail y Assert.Inconclusive siempre generan

Fail y Inconclusive nunca son suaves. Siempre se genera inmediatamente, incluso dentro de un ámbito, porque expresan un resultado de prueba incondicional. Use uno de ellos cuando una condición es crítica y el resto de la prueba no puede continuar significativamente sin ella.

No se admiten ámbitos anidados

No se pueden anidar llamadas Assert.Scope(). Solo puede haber un ámbito de aserción activo a la vez.

La clase StringAssert.

Use la clase StringAssert para comparar y examinar cadenas.

Advertencia

Es probable que la StringAssert clase esté en desuso en una versión futura. Solo se mantiene para la compatibilidad con versiones anteriores y no se recomienda para el nuevo código. Todos los StringAssert métodos tienen equivalentes en la Assert clase , lo que ofrece una mejor detectabilidad. Para migrar los usos existentes, consulte el analizador MSTEST0046.

Las API disponibles son:

La clase CollectionAssert.

Utilice la clase CollectionAssert para comparar colecciones de objetos o comprobar el estado de una colección.

Advertencia

Es probable que la CollectionAssert clase esté en desuso en una versión futura. Se mantiene principalmente por motivos de compatibilidad con versiones anteriores y no se recomienda para el nuevo código. Cuando existe un método equivalente en Assert (como Assert.Contains, Assert.DoesNotContaino Assert.HasCount), use Assert para mejorar la detectabilidad.

Las API disponibles son:

Creación de aserciones personalizadas con Assert.That

Los métodos de aserción integrados no cubren todos los escenarios. Para ampliar la infraestructura de aserción con sus propias comprobaciones, MSTest expone la Assert.That propiedad singleton como un enlace de extensibilidad. Las aserciones personalizadas se agregan como métodos de extensión de C# en el Assert tipo de instancia y los autores de llamadas los invocan con la sintaxis conocida Assert.That.MyAssertion(...) .

Para mejorar la detectabilidad, organice las aserciones en todo el proyecto en una clase estática dedicada. Las aserciones personalizadas accesibles mediante Assert.That aparecen junto a los métodos integrados en IntelliSense, por lo que los usuarios no tienen que recordar un tipo auxiliar independiente.

Creación de una aserción personalizada

Agregue un método de extensión que tenga como destino el Assert tipo e inicie AssertFailedException cuando se produce un error en la condición:

using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

public static class CustomAssertExtensions
{
    public static void IsPrime(this Assert assert, int value)
    {
        if (value < 2 || Enumerable.Range(2, (int)Math.Sqrt(value) - 1).Any(i => value % i == 0))
        {
            throw new AssertFailedException($"Assert.That.IsPrime failed. Value <{value}> is not a prime number.");
        }
    }
}

Uso de una aserción personalizada

Después de importar el espacio de nombres que contiene sus métodos de extensión, invoque su aserción personalizada mediante Assert.That:

[TestMethod]
public void Compute_ReturnsPrime()
{
    int result = _calculator.NextPrime(10);
    Assert.That.IsPrime(result);
}

Enlaces de extensión en StringAssert y CollectionAssert

Las StringAssert.That propiedades y CollectionAssert.That exponen el mismo patrón singleton para la compatibilidad con versiones anteriores. Para las nuevas aserciones personalizadas, siempre tenga como destino Assert.That. De lo contrario, los asistentes heredan los mismos problemas de detectabilidad que las clases heredadas y necesitarán la migración si StringAssert y CollectionAssert están en desuso.

Assert.That propiedad frente a Assert.That(...) método

Nota:

No confunda la Assert.Thatpropiedad única (utilizada como punto de extensión) con el Assert.That(() => condition)método añadido en MSTest 3.8. Este último acepta una expresión booleana y genera mensajes de error detallados mediante el análisis del árbol de expresiones (por ejemplo, Assert.That(() => order.Total > 0)). Las dos API comparten un nombre, pero sirven para fines diferentes.

procedimientos recomendados

  • Usar aserciones específicas: se prefiere AreEqual por IsTrue(a == b) mejores mensajes de error.

  • Incluir mensajes descriptivos: ayude a identificar los errores rápidamente con mensajes de aserción claros.

  • Probar una cosa a la vez: cada método de prueba debe comprobar un solo comportamiento.

  • Uso Throws/ThrowsExactly para excepciones: en MSTest v3.8+, prefiere Assert.Throws, Assert.ThrowsExactlyy sus homólogos asincrónicos (ThrowsAsync, ThrowsExactlyAsync) sobre el ExpectedException atributo .

  • Prefiera Assert en lugar de StringAssert/CollectionAssert: para mejorar la capacidad de detección y la coherencia, use la clase Assert. Es probable que las StringAssert clases y CollectionAssert estén en desuso en una versión futura.

  • Extensión Assert.That de aserciones personalizadas: para lograr una detectabilidad coherente, agregue aserciones personalizadas como métodos de extensión en Assert e invoquelas a través de Assert.That. No haga referencia a StringAssert.That ni a CollectionAssert.That en código nuevo.

Los analizadores siguientes ayudan a garantizar el uso adecuado de las aserciones:

  • MSTEST0006 : evite ExpectedException el atributo , use Assert.Throws métodos en su lugar.
  • MSTEST0017 : los argumentos de aserción deben pasarse en el orden correcto.
  • MSTEST0023: No niegue las afirmaciones booleanas.
  • MSTEST0025 - Se prefiere Assert.Fail en lugar de condiciones siempre falsas.
  • MSTEST0026 : los argumentos de aserción deben evitar el acceso condicional.
  • MSTEST0032 - Revisar las condiciones de aserción que siempre son verdaderas.
  • MSTEST0037 : use los métodos de aserción adecuados.
  • MSTEST0038 - Evite el uso de Assert.AreSame con tipos de valor.
  • MSTEST0039 : use métodos más recientes Assert.Throws .
  • MSTEST0040: evite el uso de aserciones en contexto de void asincrónico.
  • MSTEST0046: use Assert en lugar de StringAssert.
  • - Assert.Throws MSTEST0051 debe contener una sola instrucción.
  • MSTEST0053 : evite Assert los parámetros de formato.
  • MSTEST0058: evite aserciones en bloques catch.

Consulte también