2010-12-13 43 views
12

Tengo algunos casos en los que no me importa qué excepción se produce (siempre que se produzca alguna excepción). Por desgracia,Ignorar excepciones en xUnit.net

Assert.Throws<Exception>(someDelegate); 

no pasa a menos que exactamente se inicia una instancia de Exception (por lo que no es una instancia de una clase derivada). Sé que puedo obtener el comportamiento que quiero con

Exception exception = Record.Exception(someDelegate); 
Assert.NotNull(exception); 

pero no se lee correctamente. ¿Me estoy perdiendo algo en xUnit que tiene el comportamiento que quiero? Aquí hay dos pruebas que indican lo que quiero decir:

[Fact] 
public void Throws_exception_and_passes() { 
    Exception exception = Record.Exception(
     () => { throw new InvalidOperationException(); } 
    ); 
    Assert.NotNull(exception); 
} 

[Fact] 
public void Throws_exception_and_fails() { 
    Assert.Throws<Exception>(
     () => { throw new InvalidOperationException(); } 
    ); 
} 

Respuesta

6

por la documentación aquí:

http://xunit.codeplex.com/wikipage?title=HowToUse&referringTitle=Home

Se tiene que especificar el tipo de excepción que desea ser lanzado. En general, esta es una buena práctica. Debería poder predecir en qué escenarios arrojaría una prueba qué tipo de excepción. Debería poder diseñar tanto su método como su prueba de una manera que le permita predecir esto.

Existen varias formas de evitar esto, como hacer un intento de atraparlo, pero debe considerar cambiar un poco su diseño.

+0

De acuerdo completamente con el texto. Solo quería agregar que [@Jon Hanna 'respuesta] (http://stackoverflow.com/a/32468935/11635) detalla el ahora integrado' ThrowsAny 'que implementa el comportamiento deseado del OP –

+0

El enlace está roto. xUnit se ha movido a github – mortb

2

xUnit no se interpondrá en su camino si quiere hacer su propia Custom Assertion, algo así como:

public static bool Throws<T>(this Action action, bool discardExceptions = false) 
    where T : Exception 
{ 
    try 
    { 
     action.Invoke(); 
    } 
    catch (T) 
    { 
     return true; 
    } 
    catch (Exception) 
    { 
     if (discardExceptions) 
     { 
      return false; 
     } 
     throw; 
    } 
    return false; 
} 

O:

public static bool Throws(this Action action) 
{ 
    try 
    { 
     action.Invoke(); 
    } 
    catch (Exception) 
    { 
     return true; 
    } 
    return false; 
} 
+0

Nota: Debe asegurarse de que las excepciones de aserción internas de xUnits no se filtren agregando una captura adicional para aquellas que vuelvan a generar la excepción interna – k3b

+0

Gracias k3b. Además, use esto con cuidado porque las cosas se desordenarán si la acción que invoca tiene efectos secundarios en otros lugares. No sé si xUnit usa un método similar, pero supongo que podría verificarlo con bastante facilidad. – Nobody

2

Como usted ha identificado si no lo hace Assert.Throws<T> ajuste la cuenta, la única cosa de OOTB en xUnit que le queda es usar Record.Exception.

Como usted ha identificado, la principal forma de hacer un 'Assert tiros anything` es hacer

Assert.NotNull(Record.Exception(lambda)) 

mire - no es bonito. Esto es probable por diseño; hay muy pocas cosas en xUnit.net que son por accidente (a diferencia de un diseño considerado cuidadosamente).

Record.Exception devuelve un resultado por un motivo (y si usaba F #, tendría que |> ignore para descartar el valor). Siempre debe poder Assert algo sobre la naturaleza de la excepción que está ocurriendo para que un problema real en su código no sea ignorado por casualidad, ya que cambia su código a lo largo del tiempo, que es la razón de todas estas pruebas en el primer lugar. Tal vez eso podría tomar la forma de

var exception = Record.Exception(sut.Something); 
Assert.True(typeof(SomeException).IsAssignableFrom(exception)); 

En cuanto a eso, es más seguro que un Assert.NotNull(), pero aún no se siente bien. Es hora de, como se discutió en GOOS, escuchar sus pruebas (y en el caso de un marco de prueba obstinado, su marco de prueba).Sin embargo


El mayor problema en su pregunta es que en un ejemplo real de una prueba real, siempre hay una manera de hacer que su interfaz más clara o expresar sus expectativas de otra manera, por lo que la verdadera respuesta es Mu.

1

que solo estaba buscando en el xUnit.net source y aquí es el culpable:

private static Exception Throws(Type exceptionType, Exception exception) 
{ 
    Guard.ArgumentNotNull("exceptionType", exceptionType); 

    if (exception == null) 
     throw new ThrowsException(exceptionType); 

    if (!exceptionType.Equals(exception.GetType())) 
     throw new ThrowsException(exceptionType, exception); 

    return exception; 
} 

Lo que resolver su problema es si este cambio se aplica:

if(!exceptionType.Equals(exception.GetType())) 

a:

if(!exception.GetType().IsAssignableTo(exceptionType)) 

¿Podría ofrecer enviar un parche?

+0

Como se alude en mi respuesta, no hay 'culpable' aquí. No hay ninguna posibilidad de que esto se haya escrito de esta manera por coincidencia: la idea es que las pruebas sean específicas sobre qué excepciones se lanzan en qué situaciones, ya que las excepciones finales son parte de la interfaz. La respuesta de @ rmx aborda cómo se podría escribir algo que hace que el OP espera y http://stackoverflow.com/a/32468935/11635 describe el ahora integrado en 'ThrowsAny' –

4

No existía en el momento de esta pregunta, pero ahora uno puede utilizar Assert.ThrowsAny<Exception> para la prueba de cualquier excepción derivada de Exception (y por lo tanto ninguna excepción en absoluto), junto con variantes como Assert.ThrowsAny<ArgumentException> que prueba para cualquier excepción derivada de ArgumentException y así sucesivamente.

+0

Esto responde la pregunta * pero * la respuesta desde [poindexter] (http://stackoverflow.com/a/4451224/2874896) vale la pena tenerlo en cuenta antes de escribir sus pruebas. –

0
public static void SuppressException<TSut>(this TSut value, Action<TSut> action) where TSut : class 
    { 
     try 
     { 
      action.Invoke(value); 
     } 
     catch (Exception) 
     { 
      //do nothing 
     } 
    }