c# - try - ¿Cómo hago cumplir el mensaje de excepción con el atributo ExpectedException?
try catch c# ejemplo (7)
Pensé que estas dos pruebas deberían comportarse de manera idéntica, de hecho, escribí la prueba en mi proyecto utilizando MS Test solo para descubrir ahora que no respeta el mensaje esperado de la misma manera que lo hace NUnit.
NUnit ( falla ):
[Test, ExpectedException(typeof(System.FormatException), ExpectedMessage = "blah")]
public void Validate()
{
int.Parse("dfd");
}
Prueba de MS ( pases ):
[TestMethod, ExpectedException(typeof(System.FormatException), "blah")]
public void Validate()
{
int.Parse("dfd");
}
No importa qué mensaje le dé la prueba de ms, pasará.
¿Hay alguna manera de hacer que la prueba de ms falle si el mensaje no es correcto? ¿Puedo incluso crear mi propio atributo de excepción? Preferiría no tener que escribir un bloque try catch para cada prueba en la que esto ocurra.
@rcravens es correcto: el segundo parámetro es un mensaje que se imprime si la prueba falla. Lo que he hecho para solucionar esto es diseñar mis pruebas de manera un poco diferente. Es cierto que no me encanta este enfoque, pero funciona.
[TestMethod]
public void Validate()
{
try
{
int.Parse("dfd");
// Test fails if it makes it this far
Assert.Fail("Expected exception was not thrown.");
}
catch (Exception ex)
{
Assert.AreEqual("blah", ex.Message);
}
}
Escribí esto hace un tiempo, así que tal vez haya una mejor manera en VS2012.
Ese segundo parámetro mstest es un mensaje que se imprime cuando falla la prueba. El mstest tendrá éxito si se lanza una formatexception. Encontré este post que puede ser útil.
Extendí la respuesta de BlackjacketMack para nuestro proyecto agregando soporte para combinaciones con, sin distinción de mayúsculas y ResourceType-ResourceName.
Ejemplo de uso:
public class Foo
{
public void Bar(string mode)
{
if (string.IsNullOrEmpty(mode)) throw new InvalidOperationException(Resources.InvalidModeSpecified);
}
public void Bar(int port)
{
if (port < 0 || port > Int16.MaxValue) throw new ArgumentOutOfRangeException("port");
}
}
[TestClass]
class ExampleClass
{
[TestMethod]
[ExpectedExceptionWithMessage(typeof(InvalidOperationException), typeof(Samples.Resources), "InvalidModeSpecified")]
public void Raise_Exception_With_Message_Resource()
{
new Foo().Bar(null);
}
[TestMethod]
[ExpectedExceptionWithMessage(typeof(ArgumentOutOfRangeException), "port", true)]
public void Raise_Exeception_Containing_String()
{
new Foo().Bar(-123);
}
}
Aquí está la clase actualizada:
public class ExpectedExceptionWithMessageAttribute : ExpectedExceptionBaseAttribute
{
public Type ExceptionType { get; set; }
public Type ResourcesType { get; set; }
public string ResourceName { get; set; }
public string ExpectedMessage { get; set; }
public bool Containing { get; set; }
public bool IgnoreCase { get; set; }
public ExpectedExceptionWithMessageAttribute(Type exceptionType)
: this(exceptionType, null)
{
}
public ExpectedExceptionWithMessageAttribute(Type exceptionType, string expectedMessage)
: this(exceptionType, expectedMessage, false)
{
}
public ExpectedExceptionWithMessageAttribute(Type exceptionType, string expectedMessage, bool containing)
{
this.ExceptionType = exceptionType;
this.ExpectedMessage = expectedMessage;
this.Containing = containing;
}
public ExpectedExceptionWithMessageAttribute(Type exceptionType, Type resourcesType, string resourceName)
: this(exceptionType, resourcesType, resourceName, false)
{
}
public ExpectedExceptionWithMessageAttribute(Type exceptionType, Type resourcesType, string resourceName, bool containing)
{
this.ExceptionType = exceptionType;
this.ExpectedMessage = ExpectedMessage;
this.ResourcesType = resourcesType;
this.ResourceName = resourceName;
this.Containing = containing;
}
protected override void Verify(Exception e)
{
if (e.GetType() != this.ExceptionType)
{
Assert.Fail(String.Format(
"ExpectedExceptionWithMessageAttribute failed. Expected exception type: <{0}>. Actual exception type: <{1}>. Exception message: <{2}>",
this.ExceptionType.FullName,
e.GetType().FullName,
e.Message
)
);
}
var actualMessage = e.Message.Trim();
var expectedMessage = this.ExpectedMessage;
if (expectedMessage == null)
{
if (this.ResourcesType != null && this.ResourceName != null)
{
PropertyInfo resourceProperty = this.ResourcesType.GetProperty(this.ResourceName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
if (resourceProperty != null)
{
string resourceValue = null;
try
{
resourceValue = resourceProperty.GetMethod.Invoke(null, null) as string;
}
finally
{
if (resourceValue != null)
{
expectedMessage = resourceValue;
}
else
{
Assert.Fail("ExpectedExceptionWithMessageAttribute failed. Could not get resource value. ResourceName: <{0}> ResourcesType<{1}>.",
this.ResourceName,
this.ResourcesType.FullName);
}
}
}
else
{
Assert.Fail("ExpectedExceptionWithMessageAttribute failed. Could not find static resource property on resources type. ResourceName: <{0}> ResourcesType<{1}>.",
this.ResourceName,
this.ResourcesType.FullName);
}
}
else
{
Assert.Fail("ExpectedExceptionWithMessageAttribute failed. Both ResourcesType and ResourceName must be specified.");
}
}
if (expectedMessage != null)
{
StringComparison stringComparison = this.IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
if (this.Containing)
{
if (actualMessage == null || actualMessage.IndexOf(expectedMessage, stringComparison) == -1)
{
Assert.Fail(String.Format(
"ExpectedExceptionWithMessageAttribute failed. Expected message: <{0}>. Actual message: <{1}>. Exception type: <{2}>",
expectedMessage,
e.Message,
e.GetType().FullName
)
);
}
}
else
{
if (!string.Equals(expectedMessage, actualMessage, stringComparison))
{
Assert.Fail(String.Format(
"ExpectedExceptionWithMessageAttribute failed. Expected message to contain: <{0}>. Actual message: <{1}>. Exception type: <{2}>",
expectedMessage,
e.Message,
e.GetType().FullName
)
);
}
}
}
}
}
Prueba esto. En este ejemplo, tengo un mensaje de saludo que muestra el mensaje de saludo para un nombre dado. Cuando el parámetro de nombre está vacío o el sistema nulo lanza una excepción con el mensaje. El ExceptionAssert.Throws
verifica ambos en MsTest.
[TestMethod]
public void Does_Application_Display_Correct_Exception_Message_For_Empty_String()
{
// Arrange
var oHelloWorld = new HelloWorld();
// Act
// Asset
ExceptionAssert.Throws<ArgumentException>(() =>
oHelloWorld.GreetingMessge(""),"Invalid Name, Name can''t be empty");
}
[TestMethod]
public void Does_Application_Display_Correct_Exception_Message_For_Null_String()
{
// Arrange
var oHelloWorld = new HelloWorld();
// Act
// Asset
ExceptionAssert.Throws<ArgumentNullException>(() =>
oHelloWorld.GreetingMessge(null), "Invalid Name, Name can''t be null");
}
Puede usar el código de este proyecto que se explica en este artículo para crear un atributo ExpectedExceptionMessage que funcionará con MS Test para obtener el resultado deseado.
prueba de ms ( falla ):
[TestClass]
public class Tests : MsTestExtensionsTestFixture
{
[TestMethod, ExpectedExceptionMessage(typeof(System.FormatException), "blah")]
public void Validate()
{
int.Parse("dfd");
}
}
Usamos este atributo en todo el lugar y claramente entendimos mal el segundo parámetro (avergonzado de nosotros).
Sin embargo, definitivamente lo hemos usado para verificar el mensaje de excepción. Lo siguiente fue lo que usamos con sugerencias de esta página. No maneja la globalización o los tipos de excepción heredados, pero hace lo que necesitamos. Una vez más, el objetivo era simplemente RR ''ExpectedException'' y cambiarlo con esta clase. (Bummer ExpectedException está sellado.)
public class ExpectedExceptionWithMessageAttribute : ExpectedExceptionBaseAttribute
{
public Type ExceptionType { get; set; }
public string ExpectedMessage { get; set; }
public ExpectedExceptionWithMessageAttribute(Type exceptionType)
{
this.ExceptionType = exceptionType;
}
public ExpectedExceptionWithMessageAttribute(Type exceptionType, string expectedMessage)
{
this.ExceptionType = exceptionType;
this.ExpectedMessage = expectedMessage;
}
protected override void Verify(Exception e)
{
if (e.GetType() != this.ExceptionType)
{
Assert.Fail(String.Format(
"ExpectedExceptionWithMessageAttribute failed. Expected exception type: {0}. Actual exception type: {1}. Exception message: {2}",
this.ExceptionType.FullName,
e.GetType().FullName,
e.Message
)
);
}
var actualMessage = e.Message.Trim();
if (this.ExpectedMessage != null)
{
Assert.AreEqual(this.ExpectedMessage, actualMessage);
}
Console.Write("ExpectedExceptionWithMessageAttribute:" + e.Message);
}
}