unit-testing - resueltos - teoria de errores fisica laboratorio
En MSTest, ¿cómo puedo verificar el mensaje de error exacto utilizando (10)
Actualización: Ups ... mira que quieres esto en MSTest. Lo siento. Velocidad leída y engañada por su título.
Pruebe este proyecto de extensión de Callum Hibbert y vea si funciona.
Vieja respuesta:
Puedes hacer esto con NUnit 2.4 y superior. Ver documentation de ExpectedException aquí
[ExpectedException( typeof( ArgumentException), ExpectedMessage="unspecified", MatchType=MessageMatch.Contains )]
public void TestMethod()
{
...
MatchType puede ser Exact (predeterminado), Contains o Regex ... que maneja prácticamente el 80% de los casos de uso. También existe un método avanzado de manejo de excepciones si la verificación se vuelve demasiado compleja ... nunca la usé personalmente ... aún no la necesitaba.
Usando MSTest, ¿cómo puedo verificar el mensaje de error exacto proveniente de un método de prueba? Sé que [ExpectedException(typeof(ApplicationException), error msg)]
no compara el mensaje de error proveniente de mi método de prueba, aunque en otro marco de prueba de unidad lo está haciendo.
Una forma de resolver este problema es escribir mi prueba unitaria usando algún bloque try catch, pero de nuevo necesito escribir 4 líneas más.
¿Hay alguna forma más inteligente de verificar el mensaje de error?
Saludos, Pritam
Con MSTest, no puedes hacer esto.
Ya conoce la solución a este problema: afirme el mensaje de una excepción en un bloque catch.
En MSTest no hay una forma integrada de hacerlo. Esto es tan ''elegante'' como se pone:
[TestMethod]
public void Test8()
{
var t = new Thrower();
try
{
t.DoStuffThatThrows();
Assert.Fail("Exception expected.");
}
catch (InvalidOperationException e)
{
Assert.AreEqual("Boo hiss!", e.Message);
}
}
Sin embargo, podría considerar transferir la API Assert.Throws de xUnit.NET a una biblioteca personalizada; eso es lo que hicimos.
También puede ir a Microsoft Connect y votar esta sugerencia .
Estaba buscando una forma de verificar la presencia y el tipo de excepción interna con mstest y encontré esta pregunta. Sabía que era un tema de hace dos años, pero como mi solución no está aquí, déjame compartirla.
Para mí, la manera más elegante de resolver el problema es crear un atributo derivado, aquí está el mío (lo siento, pero los comentarios y las cadenas son en francés, mi lenguaje natural, pero debería ser obvio):
#region Références
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Text.RegularExpressions;
#endregion
namespace MsTestEx
{
/// <summary>
/// Extention de l''attribut ExpectedException permettant de vérifier plus d''éléments (Message, InnerException, ...)
/// </summary>
public class ExpectedExceptionEx
: ExpectedExceptionBaseAttribute
{
#region Variables locales
private Type _ExpectedException = null;
private string _ExpectedMessage = null;
private Type _ExpectedInnerException = null;
private string _ExpectedInnerExceptionMessage = null;
private bool _IsExpectedMessageRegex = false;
private bool _IsExpectedInnerMessageRegex = false;
private bool _AllowDerivedType = false;
private bool _AllowInnerExceptionDerivedType = false;
private bool _CheckExpectedMessage = false;
private bool _CheckInnerExceptionType = false;
private bool _CheckInnerExceptionMessage = false;
#endregion
#region Propriétés
/// <summary>
/// Vérifie que le message de l''exception correspond à celui-ci.
/// </summary>
public string ExpectedMessage
{
get { return _ExpectedMessage; }
set { _ExpectedMessage = value; _CheckExpectedMessage = true; }
}
/// <summary>
/// Vérifie que le message de l''inner-exception correspond à celui-ci.
/// </summary>
public string ExpectedInnerExceptionMessage
{
get { return _ExpectedInnerExceptionMessage; }
set { _ExpectedInnerExceptionMessage = value; _CheckInnerExceptionMessage = true; }
}
/// <summary>
/// Vérifie que l''exception possède bien une inner-exception du type spécifié.
/// Spécifier "null" pour vérifier l''absence d''inner-exception.
/// </summary>
public Type ExpectedInnerException
{
get { return _ExpectedInnerException; }
set { _ExpectedInnerException = value; _CheckInnerExceptionType = true; }
}
/// <summary>
/// Indique si le message attendu est exprimé via une expression rationnelle.
/// </summary>
public bool IsExpectedMessageRegex
{
get { return _IsExpectedMessageRegex; }
set { _IsExpectedMessageRegex = value; }
}
/// <summary>
/// Indique si le message attendu de l''inner-exception est exprimé via une expression rationnelle.
/// </summary>
public bool IsExpectedInnerMessageRegex
{
get { return _IsExpectedInnerMessageRegex; }
set { _IsExpectedInnerMessageRegex = value; }
}
/// <summary>
/// Indique si les exceptions dérivées sont acceptées.
/// </summary>
public bool AllowDerivedType
{
get { return _AllowDerivedType; }
set { _AllowDerivedType = value; }
}
/// <summary>
/// Indique si les inner-exceptions dérivées sont acceptées.
/// </summary>
public bool AllowInnerExceptionDerivedType
{
get { return _AllowInnerExceptionDerivedType; }
set { _AllowInnerExceptionDerivedType = value; }
}
#endregion
#region Constructeurs
/// <summary>
/// Indique le type d''exception attendu par le test.
/// </summary>
/// <param name="expectedException">Type de l''exception attendu.</param>
public ExpectedExceptionEx(Type expectedException)
{
_ExpectedException = expectedException;
}
#endregion
#region Méthodes
/// <summary>
/// Effectue la vérification.
/// </summary>
/// <param name="exception">Exception levée.</param>
protected override void Verify(Exception exception)
{
Assert.IsNotNull(exception); // Pas eu d''exception, ce n''est pas normal
// Vérification du type de l''exception
Type actualType = exception.GetType();
if (_AllowDerivedType) Assert.IsTrue(_ExpectedException.IsAssignableFrom(actualType), "L''exception reçue n''est pas du type spécifié ni d''un type dérivé.");
else Assert.AreEqual(_ExpectedException, actualType, "L''exception reçue n''est pas du type spécifié.");
// Vérification du message de l''exception
if (_CheckExpectedMessage)
{
if (_IsExpectedMessageRegex)
Assert.IsTrue(Regex.IsMatch(exception.Message, _ExpectedMessage), "Le message de l''exception ne correspond pas à l''expression rationnelle");
else
{
string s1, s2;
if (exception.Message.Length > _ExpectedMessage.Length)
{
s1 = exception.Message;
s2 = _ExpectedMessage;
}
else
{
s1 = _ExpectedMessage;
s2 = exception.Message;
}
Assert.IsTrue(s1.Contains(s2), "Le message de l''exception ne contient pas et n''est pas contenu par le message attendu.");
}
}
if (_CheckInnerExceptionType)
{
if (_ExpectedInnerException == null) Assert.IsNotNull(exception.InnerException);
else
{
// Vérification du type de l''exception
actualType = exception.InnerException.GetType();
if (_AllowInnerExceptionDerivedType) Assert.IsTrue(_ExpectedInnerException.IsAssignableFrom(actualType), "L''inner-exception reçue n''est pas du type spécifié ni d''un type dérivé.");
else Assert.AreEqual(_ExpectedInnerException, actualType, "L''inner-exception reçue n''est pas du type spécifié.");
}
}
if (_CheckInnerExceptionMessage)
{
Assert.IsNotNull(exception.InnerException);
if (_IsExpectedInnerMessageRegex)
Assert.IsTrue(Regex.IsMatch(exception.InnerException.Message, _ExpectedInnerExceptionMessage), "Le message de l''exception ne correspond pas à l''expression rationnelle");
else
{
string s1, s2;
if (exception.InnerException.Message.Length > _ExpectedInnerExceptionMessage.Length)
{
s1 = exception.InnerException.Message;
s2 = _ExpectedInnerExceptionMessage;
}
else
{
s1 = _ExpectedInnerExceptionMessage;
s2 = exception.InnerException.Message;
}
Assert.IsTrue(s1.Contains(s2), "Le message de l''inner-exception ne contient pas et n''est pas contenu par le message attendu.");
}
}
}
#endregion
}
}
Ahora, use este atributo con parámetros nombrados en lugar de "ExpectedException". Con mi atributo puede verificar si hay una excepción interna, un mensaje de la excepción y una excepción interna, usar una expresión regular para unir mensajes, etc. Puede adaptarse como lo desee.
La molestia con las anotaciones y los bloques try / catch es que no tiene una separación clara entre las fases ACT y ASSERT de la prueba. Una aplicación más simple es "capturar" la excepción como parte de la fase ACT utilizando una rutina de utilidad tal como:
public static class Catch
{
public static Exception Exception(Action action)
{
Exception exception = null;
try
{
action();
}
catch (Exception ex)
{
exception = ex;
}
return exception;
}
}
Esto le permite hacer:
// ACT
var actualException = Catch.Exception(() => DoSomething())
// ASSERT
Assert.IsNotNull(actualException, "No exception thrown");
Assert.IsInstanceOfType(actualException, expectedType);
Assert.AreEqual(expectedExceptionMessage, actualException.Message);
MSTest v2 admite Assert.Throws y Assert.ThrowsAsync, que devuelve la excepción capturada.
Aquí hay un artículo sobre cómo actualizar a MSTest v2: https://blogs.msdn.microsoft.com/devops/2017/09/01/upgrade-to-mstest-v2/
Aquí hay un ejemplo de uso:
var myObject = new MyObject();
var ex = Assert.Throws<ArgumentNullException>(() => myObject.Do(null));
StringAssert.Contains(ex.Message, "Parameter name: myArg");
MbUnit también puede hacer esto:
[Test]
[Row(ExpectedExceptionMessage="my message")]
void TestBlah(...
Puede crear su propio atributo ExpectedException donde puede Assert
el mensaje de la Exception
que se lanzó.
Código
namespace TestProject
{
public sealed class MyExpectedException : ExpectedExceptionBaseAttribute
{
private Type _expectedExceptionType;
private string _expectedExceptionMessage;
public MyExpectedException(Type expectedExceptionType)
{
_expectedExceptionType = expectedExceptionType;
_expectedExceptionMessage = string.Empty;
}
public MyExpectedException(Type expectedExceptionType, string expectedExceptionMessage)
{
_expectedExceptionType = expectedExceptionType;
_expectedExceptionMessage = expectedExceptionMessage;
}
protected override void Verify(Exception exception)
{
Assert.IsNotNull(exception);
Assert.IsInstanceOfType(exception, _expectedExceptionType, "Wrong type of exception was thrown.");
if(!_expectedExceptionMessage.Length.Equals(0))
{
Assert.AreEqual(_expectedExceptionMessage, exception.Message, "Wrong exception message was returned.");
}
}
}
}
Uso
[TestMethod]
[MyExpectedException(typeof(Exception), "Error")]
public void TestMethod()
{
throw new Exception("Error");
}
Usa esta pequeña clase de ayudante:
public static class ExceptionAssert
{
public static void Throws<TException>(Action action, string message)
where TException : Exception
{
try
{
action();
Assert.Fail("Exception of type {0} expected; got none exception", typeof(TException).Name);
}
catch (TException ex)
{
Assert.AreEqual(message, ex.Message);
}
catch (Exception ex)
{
Assert.Fail("Exception of type {0} expected; got exception of type {1}", typeof(TException).Name, ex.GetType().Name);
}
}
}
Uso:
Foo foo = new Foo();
foo.Property = 42;
ExceptionAssert.Throws<InvalidOperationException>(() => foo.DoSomethingCritical(), "You cannot do anything when Property is 42.");
La ventaja de las excepciones de captura explícitas es que la prueba no tiene éxito cuando otro miembro (por ejemplo, durante la inicialización) lanza la excepción.
NuGet Assertions ( NuGet ) tiene una sintaxis muy "natural del lenguaje" para definir las expectativas en pruebas unitarias:
objectundertest.Invoking(o => o.MethodUnderTest()).ShouldThrow<ExpectedException>()
.WithMessage("the expected error message");
Existen múltiples variaciones para verificar el mensaje de error con cualquier algoritmo ( Where(e => ...
), así como para verificar excepciones internas y sus mensajes.