2008-11-02 12 views
5

Soy completamente nuevo en C# y NUnit.¿Es la ExpectedExceptionAttribute de NUnit la única forma de probar si algo genera una excepción?

En Boost.Test hay una familia de BOOST_*_THROW macros. En el módulo de prueba de Python, está el método TestCase.assertRaises.

Por lo que yo entiendo, en C# con NUnit (2.4.8) el único método para hacer una prueba de excepción es usar ExpectedExceptionAttribute.

¿Por qué debería preferir ExpectedExceptionAttribute más, digamos, el enfoque de Boost.Test? ¿Qué razonamiento puede respaldar esta decisión de diseño? ¿Por qué es mejor en caso de C# y NUnit?

Por último, si decido usar ExpectedExceptionAttribute, ¿cómo puedo hacer algunas pruebas adicionales después de que la excepción fue elevada y atrapada? Digamos que quiero probar el requisito diciendo que el objeto tiene que ser válido después de que un setter haya elevado System.IndexOutOfRangeException. ¿Cómo arreglarías el siguiente código para compilar y trabajar como se esperaba?

[Test] 
public void TestSetterException() 
{ 
    Sth.SomeClass obj = new SomeClass(); 

    // Following statement won't compile. 
    Assert.Raises("System.IndexOutOfRangeException", 
        obj.SetValueAt(-1, "foo")); 

    Assert.IsTrue(obj.IsValid()); 
} 

Edit: Gracias por sus respuestas. Hoy, he encontrado un Es las Pruebasblog entry donde se mencionan los tres métodos descritos por usted (y una variación menor). Es lástima que no pude encontrarlo antes :-(

Respuesta

13

me sorprende que no he visto aún este patrón mencionado. David Arno es muy similar, pero yo prefiero la sencillez de este:

try 
{ 
    obj.SetValueAt(-1, "foo"); 
    Assert.Fail("Expected exception"); 
} 
catch (IndexOutOfRangeException) 
{ 
    // Expected 
} 
Assert.IsTrue(obj.IsValid()); 
+0

No se confirmará.Fallo ("...") lo expulsará de la prueba con una AssertionFailedException? –

+1

Sí. Sin embargo, si la llamada a SetValueAt arroja una excepción (que queremos que suceda), el control se mueve inmediatamente al catch-block y evita Assert.Fail, pasando así la prueba. Si SetValueAt no arroja una excepción, entonces el comportamiento no es tan excepcional y la prueba debería fallar. – yfeldblum

+0

Eso es más ordenado que mi manera de hacerlo. Usaré tu enfoque en el futuro :) –

10

Si puede utilizar NUnit 2.5 hay un poco de buen helpers no

Assert.That(delegate { ... }, Throws.Exception<ArgumentException>()) 
+1

+1. Prefiero usar este estilo ya que se requiere menos ceremonia para escribir la prueba, especialmente si necesita mantener una referencia para revisar mensajes, etc. También puede usar var exception = Assert.Throws (() => myInstance.DoSomethingInvalid ()); –

2

Siempre he adoptado el siguiente enfoque:..

bool success = true; 
try { 
    obj.SetValueAt(-1, "foo"); 
} catch() { 
    success = false; 
} 

assert.IsFalse(success); 

... 
sintaxis
+0

Personalmente vería una excepción específica, pero funcionará ;-p –

+0

@Marc, punto válido: debe detectar la excepción específica bajo prueba y dejar que otros pasen para que aparezcan como errores en lugar de fallas de prueba. –

4

El MbUnit es

Assert.Throws<IndexOutOfRangeException>(delegate { 
    int[] nums = new int[] { 0, 1, 2 }; 
    nums[3] = 3; 
}); 
2

Su sintaxis preferida:

Assert.Raises("System.IndexOutOfRangeException", 
       obj.SetValueAt(-1, "foo")); 

trabajo woiuldn't con C# de todos modos - la obj.SetValueAt sería evaluado y el resultado pasó a Assert.Raises. Si SetValue arroja una excepción, entonces nunca entrarías en Assert.Raises.

Se puede escribir un método de ayuda para hacerlo:

void Raises<T>(Action action) where T:Exception { 
    try { 
     action(); 
     throw new ExpectedException(typeof(T)); 
    catch (Exception ex) { 
     if (ex.GetType() != typeof(T)) { 
     throw; 
     } 
    } 
} 

que permite que la sintaxis similar de:

Assert.Raises<System.IndexOutOfRangeException>(() => 
    obj.SetValueAt(-1, "foo") 
; 
Cuestiones relacionadas