2010-12-13 16 views
12

Ho alcuni casi in cui non mi interessa quale eccezione viene lanciata (finché viene lanciata qualche eccezione). Purtroppo,Ignorare le eccezioni in xUnit.net

Assert.Throws<Exception>(someDelegate); 

non passa se non esattamente un esempio di Exception (quindi non un'istanza di una classe derivata) viene generata. So che posso ottenere il comportamento che voglio con

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

ma non legge bene. Mi manca qualcosa in xUnit che ha il comportamento che voglio? Qui ci sono due test che indicano quello che voglio dire:

[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(); } 
    ); 
} 

risposta

6

Per la documentazione qui:

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

È necessario specificare il tipo di eccezione che si desidera essere gettato. In generale, questa è una buona pratica. Dovresti essere in grado di prevedere quali scenari un test genererebbe quale tipo di eccezione. Dovresti essere in grado di progettare sia il tuo metodo che il tuo test in un modo che ti consenta di prevederlo.

Ci sono dei modi per aggirare questo problema, come provare a riprenderti, ma dovresti cercare di cambiare un po 'il tuo design.

+0

completamente d'accordo con il testo. Volevo solo aggiungere che [la risposta di @Jon Hanna] (http://stackoverflow.com/a/32468935/11635) dettagli l'ormai incorporato 'ThrowsAny' che implementa il comportamento desiderato dell'OP –

+0

link è rotto. xUnit è trasferito a GitHub – mortb

2

xUnit non sta in piedi nel vostro senso, se si vuole fare la propria Custom Assertion, qualcosa di simile:

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; 
} 

Oppure:

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

Nota: Devi effettuare Shure che xUnits interne Assert-eccezioni non sono filtrati con l'aggiunta di un fermo extra per questo che genera nuovamente l'interno eccezione – k3b

+0

Grazie k3b. Inoltre, usa questo attentamente perché le cose si complicheranno se l'azione che stai invocando ha effetti collaterali altrove. Non so se xUnit usi un metodo simile, ma immagino che potresti controllare abbastanza facilmente. – Nobody

2

Come avete identificato se Assert.Throws<T> non lo fa Adatta il conto, l'unica cosa OOTB in xUnit che ti rimane è usare Record.Exception.

Come avete identificato, il modo principale di fare un 'asserzione tiri anything` è quello di fare

Assert.NotNull(Record.Exception(lambda)) 

Guardate - non abbastanza. Questo è probabile per progettazione; ci sono pochissime cose in xUnit.net che sono per caso (al contrario di un design fortemente ponderato).

Record.Exception restituisce un risultato per un motivo (e se si stesse utilizzando F #, è necessario |> ignore per escludere il valore). Dovresti sempre essere in grado di Assert qualcosa sulla natura dell'eccezione che sta accadendo in modo che un vero problema nel tuo codice non venga ignorato per caso mentre modifichi il tuo codice nel tempo, che è la ragione di tutto questo materiale di prova in il primo posto. Forse che potrebbe assumere la forma di

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

Guardando questo, è più sicuro che un Assert.NotNull(), ma ancora non si sente bene. È giunto il momento di, come discusso in GOOS, ascoltare i tuoi test (e nel caso di un quadro di prova opinato, il tuo framework di test).


Il problema più grande nella tua domanda è, tuttavia, che in un vero e proprio esempio da un vero e proprio test, c'è sempre un modo per rendere l'interfaccia più chiara o esprimere la vostra aspettativa in un altro modo, quindi la vera risposta è Mu.

1

Stavo guardando nel xUnit.net source e qui è il colpevole:

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; 
} 

Quale sarebbe risolvere il problema è se questo cambiamento sono stati applicati:

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

a:

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

Si potrebbe offrire di presentare una patch?

+0

Come accennato nella mia risposta, qui non c'è "colpevole". Non vi è alcuna possibilità che ciò sia stato scritto in questo modo per coincidenza: l'idea è che i test dovrebbero essere specifici su quali eccezioni vengono lanciate in quali situazioni, in quanto le eccezioni fanno parte dell'interfaccia. @ indirizzi risposta di rmx come si potrebbe scrivere qualcosa che fa che il PO aspetta e http://stackoverflow.com/a/32468935/11635 descrive l'ormai built-in-'ThrowsAny' –

4

Non esisteva al momento di questa domanda, ma ora si può usare Assert.ThrowsAny<Exception> per verificare eccezioni derivata da Exception (e quindi alcuna eccezione affatto), insieme con varianti come Assert.ThrowsAny<ArgumentException> che testare per qualsiasi eccezione derivata da ArgumentException e così via.

+0

Ciò risponde alla domanda * ma * la risposta da [poindexter] (http://stackoverflow.com/a/4451224/2874896) vale la pena prendere in considerazione prima di scrivere effettivamente i test. –

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