124 votes

Le meilleur moyen de tester les exceptions à faire Valoir pour s'assurer qu'ils seront jetés

Pensez-vous que c'est un bon moyen pour tester les exceptions? Toutes les suggestions?

Exception exception = null;
        try
        {
            //I m sure that an exeption will happen here
        }
        catch (Exception ex)
        {
            exception = ex;
        }

        Assert.IsNotNull(exception);

Je suis à l'aide de MS Test.

161voto

tvanfosson Points 268301

J'ai un couple de modèles différents que j'utilise. J'utilise le ExpectedException attribut la plupart du temps lorsqu'une exception est prévue. Cela suffit pour la plupart des cas, cependant, il existe des cas où cela n'est pas suffisant. L'exception ne peut pas être catchable -- puisqu'il est lancé par une méthode qui est appelée par la réflexion, ou peut-être que je veux juste vérifier que d'autres conditions sont vérifiées, dire une transaction est annulée ou une valeur a encore été fixée. Dans ces cas, j'ai l'envelopper dans un bloc try/catch qui s'attend à l'exception exacte, fait une Assertion.Échouer si le code fonctionne et attire aussi des exceptions génériques pour s'assurer qu'une autre exception n'est levée.

Premier cas:

[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void MethodTest()
{
     var obj = new ClassRequiringNonNullParameter( null );
}

Deuxième cas:

[TestMethod]
public void MethodTest()
{
    try
    {
        var obj = new ClassRequiringNonNullParameter( null );
        Assert.Fail("An exception should have been thrown");
    }
    catch (ArgumentNullException ae)
    {
        Assert.AreEqual( "Parameter cannot be null or empty.", ae.Message );
    }
    catch (Exception e)
    {
        Assert.Fail(
             string.Format( "Unexpected exception of type {0} caught: {1}",
                            e.GetType(), e.Message )
        );
    }
}

26voto

StuartLC Points 35534

Comme de v 2.5, NUnit a la suite de la méthode de niveau Asserts pour le test des exceptions:

Affirmer.Jette, qui mettra à l'épreuve exact d'un type d'exception:

Assert.Throws<NullReferenceException>(() => someNullObject.ToString());

Et Assert.Catch, ce qui permettra de tester une exception d'un type donné, ou une exception de type dérivés de ce type:

Assert.Catch<Exception>(() => someNullObject.ToString());

En aparté, lors du débogage de l'unité de tests permettant de lancer des exceptions, vous pouvez empêcher VS de rupture sur l'exception.

18voto

Andy White Points 36586

Un moyen pour tester des exceptions est de mettre un "faire Valoir.Fail()" après le code qui doit ont lancé une exception. Si votre code atteint l'Affirmer.L'échec, cela signifie qu'une exception n'a pas été levée et le test échoue.

try
{
    SomethingThatCausesAnException();
    Assert.Fail("Should have exceptioned above!");
}
catch (InvalidOperationException ex) // must catch specific type of Exception you're testing, not just Exception as allgeek points out
{
    // whatever logging code
}

17voto

allgeek Points 161

Je suis nouveau ici et n'ont pas la réputation de commentaire ou d'downvote, mais je voulais souligner une faille dans l'exemple Andy White répondre:

try
{
    SomethingThatCausesAnException();
    Assert.Fail("Should have exceptioned above!");
}
catch (Exception ex)
{
    // whatever logging code
}

Dans tous les tests unitaires cadres que je suis familier avec, Assert.Fail travaux par la levée d'une exception, de sorte que le générique de la catch en fait le masque de l'échec du test. Si SomethingThatCausesAnException() ne les jetez pas, l' Assert.Fail volonté, mais qui ne sera jamais à bulle pour le test runner pour indiquer l'échec.

Si vous avez besoin d'attraper l'exception prévue (c'est à dire, à faire valoir certains détails, comme le message / propriétés sur l'exception), il est important de captures spécifiques de type attendu, et non pas la base de l'Exception de la classe. Qui permettrait à l' Assert.Fail exception à bulle (en supposant que vous n'êtes pas lancer le même type d'exception que votre framework de test unitaire), mais encore de permettre la validation de l'exception qui a été levée par votre SomethingThatCausesAnException() méthode.

11voto

GrahamS Points 3315

Comme une alternative à l'utilisation d' ExpectedException d'attribut, il m'arrive de définir deux méthodes utiles pour mes classes de test:

AssertThrowsException() prend un délégué et affirme qu'il lève l'exception prévue avec le message attendu.

AssertDoesNotThrowException() prend le même délégué et affirme qu'il ne jette pas une exception.

Ce couplage peut être très utile lorsque vous voulez tester qu'une exception est levée dans un cas, mais pas dans l'autre.

Utiliser mon code de test unitaire pourrait ressembler à ceci:

ExceptionThrower callStartOp = delegate(){ testObj.StartOperation(); };

// Check exception is thrown correctly...
AssertThrowsException(callStartOp, typeof(InvalidOperationException), "StartOperation() called when not ready.");

testObj.Ready = true;

// Check exception is now not thrown...
AssertDoesNotThrowException(callStartOp);

Agréable et soigné, hein?

Mon AssertThrowsException() et AssertDoesNotThrowException() méthodes sont définies sur une classe de base commune comme suit:

protected delegate void ExceptionThrower();

/// <summary>
/// Asserts that calling a method results in an exception of the stated type with the stated message.
/// </summary>
/// <param name="exceptionThrowingFunc">Delegate that calls the method to be tested.</param>
/// <param name="expectedExceptionType">The expected type of the exception, e.g. typeof(FormatException).</param>
/// <param name="expectedExceptionMessage">The expected exception message (or fragment of the whole message)</param>
protected void AssertThrowsException(ExceptionThrower exceptionThrowingFunc, Type expectedExceptionType, string expectedExceptionMessage)
{
    try
    {
        exceptionThrowingFunc();
        Assert.Fail("Call did not raise any exception, but one was expected.");
    }
    catch (NUnit.Framework.AssertionException)
    {
        // Ignore and rethrow NUnit exception
        throw;
    }
    catch (Exception ex)
    {
        Assert.IsInstanceOfType(expectedExceptionType, ex, "Exception raised was not the expected type.");
        Assert.IsTrue(ex.Message.Contains(expectedExceptionMessage), "Exception raised did not contain expected message. Expected=\"" + expectedExceptionMessage + "\", got \"" + ex.Message + "\"");
    }
}

/// <summary>
/// Asserts that calling a method does not throw an exception.
/// </summary>
/// <remarks>
/// This is typically only used in conjunction with <see cref="AssertThrowsException"/>. (e.g. once you have tested that an ExceptionThrower
/// method throws an exception then your test may fix the cause of the exception and then call this to make sure it is now fixed).
/// </remarks>
/// <param name="exceptionThrowingFunc">Delegate that calls the method to be tested.</param>
protected void AssertDoesNotThrowException(ExceptionThrower exceptionThrowingFunc)
{
    try
    {
        exceptionThrowingFunc();
    }
    catch (NUnit.Framework.AssertionException)
    {
        // Ignore and rethrow any NUnit exception
        throw;
    }
    catch (Exception ex)
    {
        Assert.Fail("Call raised an unexpected exception: " + ex.Message);
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X