Tengo un par de patrones diferentes que utilizo. Utilizo el ExpectedException
atributo la mayor parte del tiempo cuando se espera una excepción. Esto es suficiente para la mayoría de los casos, sin embargo, hay algunos casos en los que esto no es suficiente. Es posible que la excepción no se pueda detectar, ya que es lanzada por un método que se invoca por reflexión, o tal vez solo quiero verificar que se cumplan otras condiciones, digamos que una transacción se revierte o que aún se ha establecido algún valor. En estos casos, lo envuelvo en un try/catch
bloque que espera la excepción exacta, hace un Assert.Fail
si el código tiene éxito y también detecta excepciones genéricas para asegurarme de que no se lanza una excepción diferente.
Primer caso:
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void MethodTest()
{
var obj = new ClassRequiringNonNullParameter( null );
}
Segundo caso:
[TestMethod]
public void MethodTest()
{
try
{
var obj = new ClassRequiringNonNullParameter( null );
Assert.Fail("An exception should have been thrown");
}
catch (ArgumentNullException ae)
{
Assert.AreEqual( "Parameter cannot be null or empty.", ae.Message );
}
catch (Exception e)
{
Assert.Fail(
string.Format( "Unexpected exception of type {0} caught: {1}",
e.GetType(), e.Message )
);
}
}
Assert.Throws
método fuertemente tipado que cubre ambos casos.Ahora, 2017, puede hacerlo más fácil con el nuevo marco MSTest V2 :
fuente
System.Exception
se lanza un. Cualquier otro, como unSystem.ArgumentException
, fallará la prueba.Assert.ThrowsException<MyException>
se probará únicamente con el tipo de excepción proporcionado, y no con ninguno de sus tipos de excepción derivados. En mi ejemplo, si la pruebaSub
fue aThrow
unMyInheritedException
(tipo derivado de la clase baseMyException
), la prueba fallaría .Try { SubToTest(); Assert.Fail("...") } Catch (AssertFailedException e) {throw;} Catch (MyException e) {...}
. Tenga en cuenta la mayor importancia deCatch (AssertFailedException e) {throw;}
(cf. comentario de allgeek)Soy nuevo aquí y no tengo la reputación de comentar o votar en contra, pero quería señalar una falla en el ejemplo en la respuesta de Andy White :
En todos los marcos de pruebas unitarias con los que estoy familiarizado,
Assert.Fail
funciona lanzando una excepción, por lo que la captura genérica enmascarará la falla de la prueba. SiSomethingThatCausesAnException()
no lanza, loAssert.Fail
hará, pero eso nunca saldrá a la luz al corredor de prueba para indicar una falla.Si necesita capturar la excepción esperada (es decir, afirmar ciertos detalles, como el mensaje / propiedades de la excepción), es importante capturar el tipo esperado específico, y no la clase de excepción base. Eso permitiría que surgiera la
Assert.Fail
excepción (asumiendo que no está lanzando el mismo tipo de excepción que hace su marco de prueba unitaria), pero aún así permitiría la validación de la excepción lanzada por suSomethingThatCausesAnException()
método.fuente
A partir de la versión 2.5, NUnit tiene los siguientes niveles de método
Assert
para probar excepciones:Assert.Throws , que probará un tipo de excepción exacto:
Y
Assert.Catch
, que probará una excepción de un tipo dado, o un tipo de excepción derivado de este tipo:Además, al depurar pruebas unitarias que arrojan excepciones, es posible que desee evitar que VS se rompa en la excepción .
Editar
Solo para dar un ejemplo del comentario de Matthew a continuación, el retorno del genérico
Assert.Throws
yAssert.Catch
es la excepción con el tipo de excepción, que luego puede examinar para una inspección más detallada:fuente
Assert.Throws
, además, devuelve la excepción para que pueda escribir más afirmaciones sobre la propia excepción.Desafortunadamente, MSTest TODAVÍA solo tiene el atributo ExpectedException (solo muestra cuánto se preocupa MS por MSTest), lo que IMO es bastante terrible porque rompe el patrón Arrange / Act / Assert y no le permite especificar exactamente qué línea de código espera la excepción que ocurra en.
Cuando estoy usando (/ forzado por un cliente) para usar MSTest, siempre uso esta clase auxiliar:
Ejemplo de uso:
fuente
Como alternativa al uso de
ExpectedException
atributos, a veces defino dos métodos útiles para mis clases de prueba:AssertThrowsException()
toma un delegado y afirma que lanza la excepción esperada con el mensaje esperado.AssertDoesNotThrowException()
toma el mismo delegado y afirma que no lanza una excepción.Este emparejamiento puede resultar muy útil cuando desee probar que se lanza una excepción en un caso, pero no en el otro.
Al usarlos, mi código de prueba unitaria podría verse así:
Agradable y ordenado, ¿eh?
Mis métodos
AssertThrowsException()
yAssertDoesNotThrowException()
se definen en una clase base común de la siguiente manera:fuente
Marque la prueba con ExpectedExceptionAttribute (este es el término en NUnit o MSTest; los usuarios de otros marcos de prueba unitarios pueden necesitar traducir).
fuente
Con la mayoría de los marcos de prueba unitarios .net, puede poner un atributo [ExpectedException] en el método de prueba. Sin embargo, esto no puede decirle que la excepción ocurrió en el punto que esperaba. Ahí es donde xunit.net puede ayudar.
Con xunit tienes Assert.Throws, por lo que puedes hacer cosas como esta:
[Hecho] es el equivalente xunit de [TestMethod]
fuente
Sugiera usar la sintaxis de delegado limpia de NUnit .
Ejemplo de prueba
ArgumentNullExeption
:fuente