2010-12-13 26 views
12

J'ai quelques cas où je me fiche de l'exception qui est levée (tant qu'une exception est levée). Malheureusement,Ignorer les exceptions dans xUnit.net

Assert.Throws<Exception>(someDelegate); 

ne passe pas à moins exactement une instance de Exception (donc pas une instance d'une classe dérivée) est levée. Je sais que je peux obtenir le comportement que je veux avec

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

mais il ne lit pas correctement. Ai-je manqué quelque chose dans xUnit qui a le comportement que je veux? Voici deux tests qui indiquent ce que je veux 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(); } 
    ); 
} 

Répondre

6

par la documentation ici:

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

Vous devez spécifier le type d'exception que vous voulez être jeté. En général, c'est une bonne pratique. Vous devriez être capable de prédire quels scénarios un test devrait lancer quel type d'exception. Vous devriez être capable de concevoir votre méthode et votre test d'une manière qui vous permettra de prédire cela.

Il y a des façons de contourner cela, comme essayer de vous rattraper, mais vous devriez essayer de changer un peu votre conception.

+0

sommes entièrement d'accord avec le texte. Je voulais juste ajouter que [réponse « Hanna @ Jon] (http://stackoverflow.com/a/32468935/11635) détaille le maintenant intégré' ThrowsAny' qui met en œuvre le comportement OP désiré lien –

+0

est cassé. xUnit a déménagé à GitHub – mortb

2

xUnit ne résistera pas à votre façon si vous voulez faire votre propre Custom Assertion, quelque chose comme:

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

Ou:

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

Note: Vous devez faire shure que xUnits Assert-exceptions internes ne sont pas filtrés en ajoutant une prise supplémentaire pour ce qui rethrows l'exception interne – k3b

+0

Merci k3b. En outre, utilisez ceci avec précaution car les choses deviendront désordonnées si l'action que vous invoquez a des effets secondaires ailleurs. Je ne sais pas si xUnit utilise une méthode similaire, mais je suppose que vous pourriez vérifier assez facilement. – Nobody

2

Comme vous l'avez identifié si Assert.Throws<T> ne le fait pas adapter la facture, la seule chose OOTB dans xUnit vous reste avec Record.Exception.

Comme vous l'avez identifié, le principal moyen de faire un « Assertion lancers francs anything` est de faire

Assert.NotNull(Record.Exception(lambda)) 

Regardez - pas assez. C'est probablement par conception; Il y a très peu de choses dans xUnit.net qui sont accidentelles (par opposition à une conception réfléchie soigneusement réfléchie).

Record.Exception renvoie un résultat pour une raison (et si vous utilisiez F #, vous auriez |> ignore pour supprimer la valeur). Vous devriez toujours être capable de Assert quelque chose sur la nature de l'Exception qui se passe afin qu'un problème réel dans votre code ne soit pas ignoré par hasard lorsque vous changez votre code au fil du temps, ce qui est la raison de tous ces tests dans la première place. Peut-être que cela pourrait prendre la forme regardant de

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

que, il est plus sûr qu'un Assert.NotNull(), mais ne se sent toujours pas bien. Il est temps de, comme discuté dans GOOS, d'écouter vos tests (et dans le cas d'un cadre de test opiniâtre, votre cadre de test).


Le plus gros problème dans votre question est que, dans un exemple réel d'un vrai test, il y a toujours un moyen de rendre l'interface plus claire ou d'exprimer vos attentes d'une autre manière, de sorte que la vraie réponse est Mu.

1

Je regardais dans le xUnit.net source et est ici le coupable:

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

Qu'est-ce qui résout votre problème est de savoir si ce changement a été appliqué:

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

à:

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

Vous pourriez offrir à soumettre un patch?

+0

Comme mentionné dans ma réponse, il n'y a pas de 'coupable' ici. Il n'y a aucune chance que cela ait été écrit de cette manière par coïncidence - l'idée est que les tests devraient être spécifiques quant aux exceptions qui sont levées dans quelles situations, en fin de compte, les exceptions font partie de l'interface. @ adresses de réponse de RMX comment on peut écrire quelque chose qui fait que l'OP attend et http://stackoverflow.com/a/32468935/11635 décrit la 'ThrowsAny' –

4

Il n'existait pas au moment de cette question, mais maintenant on peut utiliser Assert.ThrowsAny<Exception> pour tester une exception dérivée de Exception (et donc toute exception du tout), ainsi que des variantes telles que Assert.ThrowsAny<ArgumentException> qui tester tout exception dérivée de ArgumentException et ainsi de suite.

+0

maintenant intégré in- Cela répond à la question *, mais * la réponse de [poindexter] (http://stackoverflow.com/a/4451224/2874896) vaut la peine de prendre en considération avant d'écrire réellement vos tests. –

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