2009-10-22 30 views
168

¿Cómo uso Assert.Throws para afirmar el tipo de excepción y la redacción actual del mensaje?¿Cómo uso Assert.Throws para afirmar el tipo de la excepción?

Algo como esto:

Assert.Throws<Exception>(
    ()=>user.MakeUserActive()).WithMessage("Actual exception message") 

El método que estoy probando lanza varios mensajes del mismo tipo, con diferentes mensajes, y necesito una manera de probar que el mensaje correcto es lanzada en función del contexto.

Respuesta

295

Assert.Throws devuelve la excepción que se produce que le permite hacer valer la excepción.

var ex = Assert.Throws<Exception>(() => user.MakeUserActive()); 
Assert.That(ex.Message, Is.EqualTo("Actual exception message")); 

Así que si se lanza una excepción, o una excepción del tipo incorrecto es lanzada, la primera afirmación Assert.Throws fallará. Sin embargo, si se lanza una excepción del tipo correcto, ahora puede afirmar en la excepción real que ha guardado en la variable.

Al usar este patrón, puede afirmar en otras cosas que no sea el mensaje de excepción, p. en el caso de ArgumentException y derivados, se puede afirmar que el nombre del parámetro es correcta:

var ex = Assert.Throws<ArgumentNullException>(() => foo.Bar(null)); 
Assert.That(ex.ParamName, Is.EqualTo("bar")); 

También puede utilizar la API de fluidez para hacer esto afirma:

Assert.That(() => foo.Bar(null), 
Throws.Exception 
    .TypeOf<ArgumentNullException>() 
    .With.Property("ParamName") 
    .EqualTo("bar")); 

Un pequeño consejo al hacer valer el Los mensajes de excepción son para decorar el método de prueba con el SetCultureAttribute para asegurarse de que el mensaje arrojado utiliza la cultura esperada. Esto entra en juego si almacena sus mensajes de excepción como recursos para permitir la localización.

+0

Esto fue realmente útil para mí, quería una forma de mostrar el error, ni siquiera leí si el método Assert.Throws arrojaba un valor. Gracias – Haroon

+4

+1 Gracias por mostrar la API de Fluent, por alguna razón tenía problemas para entender cómo usarla solo con los documentos de NUnit. – aolszowka

21

Ahora puede usar los atributos ExpectedException, p. Ej.

[Test] 
[ExpectedException(typeof(InvalidOperationException), 
ExpectedMessage="You can't do that!"] 
public void MethodA_WithNull_ThrowsInvalidOperationException() 
{ 
    MethodA(null); 
} 
+0

Esto me molestó un poco cuando se lo vio por primera vez, porque la prueba del aparente no tenía afirmación, lo cual era un olor para mí. Esta es una buena característica, pero se debe debatir en el equipo si este atributo se debe utilizar en Assert.Throws – Marcel

+12

+1 también es una buena forma de probar excepciones. Lo único que hay que tener en cuenta es que, en teoría, cualquier línea de código que arroje una InvalidOperationException con ese mensaje pasará la prueba, incluido el código de la prueba que prepara los datos/objetos de prueba o cualquier otro método que pueda necesitar antes de la prueba. uno que está interesado en probar, posiblemente dando como resultado un falso positivo. Por supuesto, eso depende de cuán específico es el mensaje y el tipo de excepción que está probando. Con 'Assert.Throw' puede orientar la línea exacta que le interesa. – Nope

+7

El atributo ExpectedException está en desuso en NUnit 3: https://github.com/nunit/docs/wiki/Breaking-Changes –

2

Es un largo tiempo ya que esta cuestión se planteó, me di cuenta, pero recientemente me encontré con lo mismo, y sugieren esta función para MSTest:

public bool AssertThrows(Action action) where T : Exception 
{ 
try {action();} 
catch(Exception exception) 
{ 
    if (exception.GetType() == typeof(T)) return true; 
} 
return false; 
} 

uso:

Assert.IsTrue(AssertThrows<FormatException>(delegate{ newMyMethod(MyParameter); })); 

Más aquí: http://phejndorf.wordpress.com/2011/02/21/assert-that-a-particular-exception-has-occured/

3

Para ampliar la respuesta del persistente, y para proporcionar más de la funcionalidad de NUnit, usted puede hacer esto:

public bool AssertThrows<TException>(
    Action action, 
    Func<TException, bool> exceptionCondition = null) 
    where TException : Exception 
{ 
    try 
    { 
     action(); 
    } 
    catch (TException ex) 
    { 
     if (exceptionCondition != null) 
     { 
      return exceptionCondition(ex); 
     } 

     return true; 
    } 
    catch 
    { 
     return false; 
    } 

    return false; 
} 

Ejemplos:

// No exception thrown - test fails. 
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
     () => {})); 

// Wrong exception thrown - test fails. 
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
     () => { throw new ApplicationException(); })); 

// Correct exception thrown - test passes. 
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
     () => { throw new InvalidOperationException(); })); 

// Correct exception thrown, but wrong message - test fails. 
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
     () => { throw new InvalidOperationException("ABCD"); }, 
     ex => ex.Message == "1234")); 

// Correct exception thrown, with correct message - test passes. 
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
     () => { throw new InvalidOperationException("1234"); }, 
     ex => ex.Message == "1234")); 
7
Assert.That(myTestDelegate, Throws.ArgumentException 
    .With.Property("Message").EqualTo("your argument is invalid.")); 
0

Desde que estoy preocupado por el nivel de detalle de algunos de los nuevos patrones de NUnit, utilizo algo como esto para crear código que es más limpio para mí personalmente:

public void AssertBusinessRuleException(TestDelegate code, string expectedMessage) 
{ 
    var ex = Assert.Throws<BusinessRuleException>(code); 
    Assert.AreEqual(ex.Message, expectedMessage); 
} 

public void AssertException<T>(TestDelegate code, string expectedMessage) where T:Exception 
{ 
    var ex = Assert.Throws<T>(code); 
    Assert.AreEqual(ex.Message, expectedMessage); 
} 

El uso es entonces:

AssertBusinessRuleException(() => service.Create(content), "Name already exists"); 
Cuestiones relacionadas