Frage

Wie verwende ich Assert (oder eine andere Test-Klasse?) Zu überprüfen, ob eine Ausnahme ausgelöst wurde?

War es hilfreich?

Lösung

"Visual Studio Team Test" es scheint, dass Sie das ExpectedException Attribut, um die Test-Methode anzuwenden.

Beispiel aus der Dokumentation hier: A Unit Testing Exemplarische Vorgehensweise mit Visual Studio Team Test

[TestMethod]
[ExpectedException(typeof(ArgumentException),
    "A userId of null was inappropriately allowed.")]
public void NullUserIdInConstructor()
{
   LogonInfo logonInfo = new LogonInfo(null, "P@ss0word");
}

Andere Tipps

In der Regel Ihres Test-Framework für diese Antwort. Aber wenn es nicht flexibel genug ist, kann man immer tun:

try {
    somethingThatShouldThrowAnException();
    Assert.Fail(); // If it gets to this line, no exception was thrown
} catch (GoodException) { }

Wie @Jonas weist darauf hin, das nicht funktioniert, eine Basis Ausnahme für den Fang:

try {
    somethingThatShouldThrowAnException();
    Assert.Fail(); // raises AssertionException
} catch (Exception) {
    // Catches the assertion exception, and the test passes
}

Wenn Sie unbedingt Exception fangen müssen, müssen Sie die Assert.Fail erneut auslösen (). Aber wirklich, ist dies ein Zeichen Sie nicht von Hand schreibe dies sein sollte; Überprüfen Sie die Testframework für Optionen, oder ob Sie eine sinnvolle Ausnahme auslösen, um zu testen, für.

catch (AssertionException) { throw; }

Es soll möglich sein, diesen Ansatz anzupassen, was auch immer Sie wollen - einschließlich Angabe, welche Arten von Ausnahmen zu fangen. Wenn Sie nur bestimmte Arten erwarten, beenden die catch abblockt mit:

} catch (GoodException) {
} catch (Exception) {
    // not the right kind of exception
    Assert.Fail();
}

Meine bevorzugte Methode, um diese für die Umsetzung ist ein Verfahren zu schreiben Wirft genannt, und verwenden Sie es wie jede andere Methode Assert. Leider unterstützt .NET nicht zulassen, dass Sie eine statische Erweiterungsmethode schreiben, so dass Sie diese Methode nicht, als ob es tatsächlich gehört zu der Build in Assert-Klasse verwenden können; machen nur einen anderen namens MyAssert oder etwas ähnliches. Die Klasse sieht wie folgt aus:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace YourProject.Tests
{
    public static class MyAssert
    {
        public static void Throws<T>( Action func ) where T : Exception
        {
            var exceptionThrown = false;
            try
            {
                func.Invoke();
            }
            catch ( T )
            {
                exceptionThrown = true;
            }

            if ( !exceptionThrown )
            {
                throw new AssertFailedException(
                    String.Format("An exception of type {0} was expected, but not thrown", typeof(T))
                    );
            }
        }
    }
}

Das bedeutet, dass Ihr Gerät zu testen wie folgt aussieht:

[TestMethod()]
public void ExceptionTest()
{
    String testStr = null;
    MyAssert.Throws<NullReferenceException>(() => testStr.ToUpper());
}

Welche wie der Rest des Unit-Test-Syntaxen und verhält sich viel mehr sieht.

Wenn Sie mit MSTest, die ursprünglich keine ExpectedException Attribut hatte, könnten Sie dies tun:

try 
{
    SomeExceptionThrowingMethod()
    Assert.Fail("no exception thrown");
}
catch (Exception ex)
{
    Assert.IsTrue(ex is SpecificExceptionType);
}

Wenn Sie NUnit verwenden, können Sie etwas tun:

Assert.Throws<ExpectedException>(() => methodToTest());


Es ist auch möglich, die ausgelöste Ausnahme zu speichern, um sie zu validieren weiter:

ExpectedException ex = Assert.Throws<ExpectedException>(() => methodToTest());
Assert.AreEqual( "Expected message text.", ex.Message );
Assert.AreEqual( 5, ex.SomeNumber);

Siehe auch: http://nunit.org/docs/2.5/exceptionAsserts.html

Seien Sie vorsichtig ExpectedException zu verwenden, da es zu mehreren Gefahren führen kann, wie hier gezeigt:

http: // geekswithblogs. net / sdorman / Archiv / 2009/01/17 / Unit-Testing-and-erwartet-exceptions.aspx

Und hier:

http://xunit.github.io/docs/comparisons.html

Wenn Sie Ausnahmen zu testen, gibt es weniger verpönt Wege. Sie können die try {act / fail} catch {assert} Methode, die für Frameworks nützlich sein kann, die keine direkte Unterstützung für die Ausnahme andere Prüfungen als ExpectedException verfügen.

Eine bessere Alternative ist xUnit.NET zu verwenden, die ein sehr modernes, zukunftsweisende und erweiterbare Unit-Test-Framework, das sich von allen anderen Fehler und verbessert gelernt hat. Eine solche Verbesserung ist Assert.Throws, die für die Geltendmachung Ausnahmen eine viel bessere Syntax zur Verfügung stellt.

Sie können xUnit.NET bei Github finden: http://xunit.github.io/

In einem Projekt arbeite ich an haben wir eine andere Lösung dies zu tun.

Zuerst dont Ich mag die ExpectedExceptionAttribute becuase es in Betracht zieht, welche Methodenaufruf, der die Ausnahme verursacht hat.

Ich tue dies mit einem helpermethod statt.

Test

[TestMethod]
public void AccountRepository_ThrowsExceptionIfFileisCorrupt()
{
     var file = File.Create("Accounts.bin");
     file.WriteByte(1);
     file.Close();

     IAccountRepository repo = new FileAccountRepository();
     TestHelpers.AssertThrows<SerializationException>(()=>repo.GetAll());            
}

HelperMethod

public static TException AssertThrows<TException>(Action action) where TException : Exception
    {
        try
        {
            action();
        }
        catch (TException ex)
        {
            return ex;
        }
        Assert.Fail("Expected exception was not thrown");

        return null;
    }

Ordentlich, nicht wahr;)

MSTest (v2) hat jetzt eine Assert.ThrowsException Funktion, die wie folgt verwendet werden kann:

Assert.ThrowsException<System.FormatException>(() =>
            {
                Story actual = PersonalSite.Services.Content.ExtractHeader(String.Empty);
            }); 

Sie können es mit nuget installieren: Install-Package MSTest.TestFramework

Es ist ein Attribut auf dem Testverfahren ... Sie nicht Assert verwenden. Sieht wie folgt aus:

[ExpectedException(typeof(ExceptionType))]
public void YourMethod_should_throw_exception()

Sie können ein Paket von Nuget herunterladen mit: PM> Install-Package MSTestExtensions fügt hinzu, dass Assert.Throws () Syntax im Stil von nUnit / xUnit zu MSTest.

High Level Anweisungen:. Laden Sie die Montage und erben von BaseTest und Sie können die Assert.Throws verwenden () Syntax

Die wichtigste Methode für die Überwürfe Implementierung sieht wie folgt aus:

public static void Throws<T>(Action task, string expectedMessage, ExceptionMessageCompareOptions options) where T : Exception
{
    try
    {
        task();
    }
    catch (Exception ex)
    {
        AssertExceptionType<T>(ex);
        AssertExceptionMessage(ex, expectedMessage, options);
        return;
    }

    if (typeof(T).Equals(new Exception().GetType()))
    {
        Assert.Fail("Expected exception but no exception was thrown.");
    }
    else
    {
        Assert.Fail(string.Format("Expected exception of type {0} but no exception was thrown.", typeof(T)));
    }
}

Disclosure: Ich habe zusammen, um dieses Paket

.

Weitere Informationen: http: // www .bradoncode.com / blog / 2012/01 / Geltendmachung-Ausnahmen-in-mstest-with.html

Sie können dies erreichen mit einem einfachen einzeiligen.

Wenn Ihr Betrieb foo.bar() ist async:

await Assert.ThrowsExceptionAsync<Exception>(() => foo.bar());

Wenn foo.bar() nicht async ist

Assert.ThrowsException<Exception>(() => foo.bar());

Ich empfehle, nicht das ExpectedException Attribut (da es auch ist beschränke und fehleranfällig) oder einen try / catch-Block in jedem Test zu schreiben (da es zu kompliziert und fehleranfällig). Verwenden Sie eine gut gestaltete Assertion-Methode - entweder von Ihrem Test-Framework zur Verfügung gestellt oder schreiben Sie Ihre eigene. Hier ist, was ich geschrieben habe und zu verwenden.

public static class ExceptionAssert
{
    private static T GetException<T>(Action action, string message="") where T : Exception
    {
        try
        {
            action();
        }
        catch (T exception)
        {
            return exception;
        }
        throw new AssertFailedException("Expected exception " + typeof(T).FullName + ", but none was propagated.  " + message);
    }

    public static void Propagates<T>(Action action) where T : Exception
    {
        Propagates<T>(action, "");
    }

    public static void Propagates<T>(Action action, string message) where T : Exception
    {
        GetException<T>(action, message);
    }

    public static void Propagates<T>(Action action, Action<T> validation) where T : Exception
    {
        Propagates(action, validation, "");
    }

    public static void Propagates<T>(Action action, Action<T> validation, string message) where T : Exception
    {
        validation(GetException<T>(action, message));
    }
}

Beispiel verwendet:

    [TestMethod]
    public void Run_PropagatesWin32Exception_ForInvalidExeFile()
    {
        (test setup that might propagate Win32Exception)
        ExceptionAssert.Propagates<Win32Exception>(
            () => CommandExecutionUtil.Run(Assembly.GetExecutingAssembly().Location, new string[0]));
        (more asserts or something)
    }

    [TestMethod]
    public void Run_PropagatesFileNotFoundException_ForExecutableNotFound()
    {
        (test setup that might propagate FileNotFoundException)
        ExceptionAssert.Propagates<FileNotFoundException>(
            () => CommandExecutionUtil.Run("NotThere.exe", new string[0]),
            e => StringAssert.Contains(e.Message, "NotThere.exe"));
        (more asserts or something)
    }

NOTES

die Ausnahme Rückkehr stattdessen eine Validierung Rückruf zu unterstützen ist eine vernünftige Idee, außer dass damit die anrufende Syntax dieser assert macht ganz anders als andere behaupten, die ich benutze.

Im Gegensatz zu anderen, verwende ich ‚propagiert‘ anstelle von ‚wirft‘, da wir nur, ob eine Ausnahme von einem Aufruf ausbreitet testen können. Wir können nicht direkt testen, ob eine Ausnahme ausgelöst wird. Aber ich denke, man könnte Bild bedeuten wirft. Geworfen und nicht gefangen

FINAL GEDANKEN

Bevor auf diese Art von Ansatz Schalt ich das ExpectedException Attribut betrachtet zu verwenden, wenn ein Test nur die Art Ausnahme überprüft und mit einem try / catch-Block, wenn mehr Validierung erforderlich war. Aber nicht nur würde ich darüber nachdenken, welche Technik für jeden Test zu verwenden, aber von einer Technik zum anderen eine Änderung des Codes als Bedarf geändert war nicht trivial Aufwand. einen konsequenten Ansatz spart geistige Anstrengung.

Also zusammenfassend, ist dieser Ansatz Sport. Einfachheit der Handhabung, Flexibilität und Robustheit (schwer, es zu tun, falsch)

Der Helfer von @Richiban bereitgestellt oben funktioniert gut, außer es die Situation nicht behandeln, in denen eine Ausnahme ausgelöst wird, aber nicht die Art erwartet. Die folgenden Adressen dass:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace YourProject.Tests
{
    public static class MyAssert
    {
        /// <summary>
        /// Helper for Asserting that a function throws an exception of a particular type.
        /// </summary>
        public static void Throws<T>( Action func ) where T : Exception
        {
            Exception exceptionOther = null;
            var exceptionThrown = false;
            try
            {
                func.Invoke();
            }
            catch ( T )
            {
                exceptionThrown = true;
            }
            catch (Exception e) {
                exceptionOther = e;
            }

            if ( !exceptionThrown )
            {
                if (exceptionOther != null) {
                    throw new AssertFailedException(
                        String.Format("An exception of type {0} was expected, but not thrown. Instead, an exception of type {1} was thrown.", typeof(T), exceptionOther.GetType()),
                        exceptionOther
                        );
                }

                throw new AssertFailedException(
                    String.Format("An exception of type {0} was expected, but no exception was thrown.", typeof(T))
                    );
            }
        }
    }
}

Da Sie andere Testklassen erwähnen verwenden, eine bessere Option als das ExpectedException Attribut Shoudly Should.Throw .

Should.Throw<DivideByZeroException>(() => { MyDivideMethod(1, 0); });

Lassen Sie uns sagen, dass wir eine Anforderung haben, dass die Kunden muss eine Adresse ein zu schaffen . Wenn nicht, sollte die CreateOrderForCustomer Methode in einem ArgumentException führen. Dann könnten wir schreiben:

[TestMethod]
public void NullUserIdInConstructor()
{
  var customer = new Customer(name := "Justin", address := null};

  Should.Throw<ArgumentException>(() => {
    var order = CreateOrderForCustomer(customer) });
}

Das ist besser als ein ExpectedException Attribut, weil wir konkret über werden, was den Fehler werfen soll. Dies macht Anforderungen in unseren Tests klarer und auch macht Diagnose einfacher, wenn der Test nicht bestanden.

Hinweis gibt es auch ein Should.ThrowAsync für asynchrones Verfahren Prüfung.

Als Alternative Sie testen Ausnahmen sind in der Tat versuchen können, mit den nächsten zwei Zeilen in Ihrem Test geworfen.

var testDelegate = () => MyService.Method(params);
Assert.Throws<Exception>(testDelegate);

Nun, ich werde ziemlich Summe, was alle anderen schon mal hier gesagt ... Wie auch immer, hier ist der Code, den ich nach den guten Antworten gebaut :) Alles, was übrig ist, zu tun Kopie und Verwendung ...

/// <summary>
/// Checks to make sure that the input delegate throws a exception of type TException.
/// </summary>
/// <typeparam name="TException">The type of exception expected.</typeparam>
/// <param name="methodToExecute">The method to execute to generate the exception.</param>
public static void AssertRaises<TException>(Action methodToExecute) where TException : System.Exception
{
    try
    {
        methodToExecute();
    }
    catch (TException) {
        return;
    }  
    catch (System.Exception ex)
    {
        Assert.Fail("Expected exception of type " + typeof(TException) + " but type of " + ex.GetType() + " was thrown instead.");
    }
    Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");  
}

In VS Einbau-Unit-Tests, wenn Sie wollen einfach nur, um zu überprüfen, dass „jede Ausnahme“ geworfen wird, aber Sie wissen nicht, die Art, können Sie einen Haken verwenden alle:

[TestMethod]
[ExpectedException(typeof(Exception), AllowDerivedTypes = true)]
public void ThrowExceptionTest()
{
    //...
}

Schauen Sie sich nUnit Docs für Beispiele zu :

[ExpectedException( typeof( ArgumentException ) )]

Das wird sich davon abhängen, welche Test-Framework sind Sie mit?

In MbUnit, zum Beispiel, können Sie die erwartete Ausnahme mit einem Attribute angeben können, um sicherzustellen, dass Sie die Ausnahme bekommen Sie wirklich erwartet.

[ExpectedException(typeof(ArgumentException))]

Bei Verwendung von NUnit , versuchen Sie dies:

Assert.That(() =>
        {
            Your_Method_To_Test();
        }, Throws.TypeOf<Your_Specific_Exception>().With.Message.EqualTo("Your_Specific_Message"));

Auch wenn dies eine alte Frage ist, würde Ich mag einen neuen Gedanken in die Diskussion hinzuzufügen. Ich habe das Vereinbaren verlängert, Act, Assert Muster Assert Erwartet, Vereinbaren, Act, werden. Sie können eine erwartete Ausnahme Zeiger machen, dann behaupten sie zugewiesen wurde. Das fühlt sich sauberer als tun, um Ihre Asserts in einem catch-Block, Ihr Act Abschnitt verlassen meist nur für die eine Zeile Code der Methode im Test aufzurufen. Sie müssen auch nicht von mehreren Punkten im Code Assert.Fail(); oder return. Jede andere Ausnahme ausgelöst wird bewirken, dass der Test nicht, weil es nicht gefangen werden, und wenn eine Ausnahme Ihrer erwarteten Typ geworfen, aber das war es nicht die, die Sie erwartet haben, Geltendmachung gegen die Nachricht oder andere Eigenschaften hilft die Ausnahme sicherstellen, dass Ihr Test nicht versehentlich passieren wird.

[TestMethod]
public void Bar_InvalidDependency_ThrowsInvalidOperationException()
{
    // Expectations
    InvalidOperationException expectedException = null;
    string expectedExceptionMessage = "Bar did something invalid.";

    // Arrange
    IDependency dependency = DependencyMocks.Create();
    Foo foo = new Foo(dependency);

    // Act
    try
    {
        foo.Bar();
    }
    catch (InvalidOperationException ex)
    {
        expectedException = ex;
    }

    // Assert
    Assert.IsNotNull(expectedException);
    Assert.AreEqual(expectedExceptionMessage, expectedException.Message);
}

Es ist eine wunderbare Bibliothek namens NFluent die beschleunigt und erleichtert die Art und Weise Sie schreiben Sie Ihre Behauptungen .

Es ist ziemlich einfach, eine Behauptung zu werfen, eine Ausnahme zu schreiben:

    [Test]
    public void given_when_then()
    {
        Check.ThatCode(() => MethodToTest())
            .Throws<Exception>()
            .WithMessage("Process has been failed");
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top