Als Alternative ExpectedException
Attribut zu verwenden, definiere ich manchmal zwei hilfreiche Methoden für meine Testklassen:
AssertThrowsException()
nimmt einen Delegaten und behauptet, dass er die erwartete Ausnahme mit dem erwarteten m auslöst Nachricht.
AssertDoesNotThrowException()
nimmt den gleichen Delegaten und behauptet, dass es keine Ausnahme auslöst.
Diese Paarung kann sehr nützlich sein, wenn Sie testen möchten, ob in einem Fall eine Ausnahme ausgelöst wird, aber nicht in der anderen.
Mit ihnen meine Unit-Test-Code könnte wie folgt aussehen:
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);
Nizza und ordentlich huh?
Meine AssertThrowsException()
und AssertDoesNotThrowException()
Methoden sind auf einer gemeinsamen Basisklasse wie folgt definiert:
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);
}
}
Viele Unit-Test-Frameworks implementieren Assertionsfehler als Ausnahmen. So wird die Assert.Fail() im zweiten Fall vom Catch-Block (Exception) abgefangen, der die Ausnahmebedingungsnachricht ausblendet. Sie müssen einen Catch hinzufügen (NUnit.Framework.AssertionException) {throw;} oder ähnlich - siehe meine Antwort. – GrahamS
@Graham - Ich tippte mir das aus dem Kopf. Normalerweise würde ich die Ausnahmebedingungsnachricht zusätzlich zu ihrem Typ ausdrucken. Der Punkt ist, dass der Test fehlschlagen würde, da der zweite Handler den Assertionsfehler abfangen und mit Informationen über den Fehler "umkehren" würde. – tvanfosson
Obwohl Ihr Code funktional klingt, empfehle ich nicht, das ExpectedException-Attribut zu verwenden (da es zu einschränkend und fehleranfällig ist) oder einen try/catch-Block in jedem Test zu schreiben (da es zu kompliziert und fehleranfällig ist). Verwenden Sie eine gut durchdachte Assert-Methode - entweder von Ihrem Test-Framework zur Verfügung gestellt oder schreiben Sie Ihre eigenen. Sie können einen besseren Code erzielen, und Sie müssen nicht zwischen den verschiedenen Techniken wählen oder von einem zum anderen wechseln, wenn sich der Test ändert. Siehe http://StackOverflow.com/A/25084462/2166177 – steve