Do you think that this is a good way for testing exceptions? Any suggestions?
Exception exception = null;
try{
//I m sure that an exeption will happen here
}
catch (Exception ex){
exception = ex;
}
Assert.IsNotNull(exception);
I'm using MS Test.
This question is related to
c#
.net
unit-testing
Now, 2017, you can do it easier with the new MSTest V2 Framework:
Assert.ThrowsException<Exception>(() => myClass.MyMethodWithError());
//async version
await Assert.ThrowsExceptionAsync<SomeException>(
() => myObject.SomeMethodAsync()
);
As an alternative to using ExpectedException
attribute, I sometimes define two helpful methods for my test classes:
AssertThrowsException()
takes a delegate and asserts that it throws the expected exception with the expected message.
AssertDoesNotThrowException()
takes the same delegate and asserts that it does not throw an exception.
This pairing can be very useful when you want to test that an exception is thrown in one case, but not the other.
Using them my unit test code might look like this:
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);
Nice and neat huh?
My AssertThrowsException()
and AssertDoesNotThrowException()
methods are defined on a common base class as follows:
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);
}
}
I'm new here and don't have the reputation to comment or downvote, but wanted to point out a flaw in the example in Andy White's reply:
try
{
SomethingThatCausesAnException();
Assert.Fail("Should have exceptioned above!");
}
catch (Exception ex)
{
// whatever logging code
}
In all unit testing frameworks I am familiar with, Assert.Fail
works by throwing an exception, so the generic catch will actually mask the failure of the test. If SomethingThatCausesAnException()
does not throw, the Assert.Fail
will, but that will never bubble out to the test runner to indicate failure.
If you need to catch the expected exception (i.e., to assert certain details, like the message / properties on the exception), it's important to catch the specific expected type, and not the base Exception class. That would allow the Assert.Fail
exception to bubble out (assuming you aren't throwing the same type of exception that your unit testing framework does), but still allow validation on the exception that was thrown by your SomethingThatCausesAnException()
method.
Suggest using NUnit's clean delegate syntax.
Example for testing ArgumentNullExeption
:
[Test]
[TestCase(null)]
public void FooCalculation_InvalidInput_ShouldThrowArgumentNullExeption(string text)
{
var foo = new Foo();
Assert.That(() => foo.Calculate(text), Throws.ArgumentNullExeption);
//Or:
Assert.That(() => foo.Calculate(text), Throws.Exception.TypeOf<ArgumentNullExeption>);
}
With most .net unit testing frameworks you can put an [ExpectedException] attribute on the test method. However this can't tell you that the exception happened at the point you expected it to. That's where xunit.net can help.
With xunit you have Assert.Throws, so you can do things like this:
[Fact]
public void CantDecrementBasketLineQuantityBelowZero()
{
var o = new Basket();
var p = new Product {Id = 1, NetPrice = 23.45m};
o.AddProduct(p, 1);
Assert.Throws<BusinessException>(() => o.SetProductQuantity(p, -3));
}
[Fact] is the xunit equivalent of [TestMethod]
As of v 2.5, NUnit has the following method-level Assert
s for testing exceptions:
Assert.Throws, which will test for an exact exception type:
Assert.Throws<NullReferenceException>(() => someNullObject.ToString());
And Assert.Catch
, which will test for an exception of a given type, or an exception type derived from this type:
Assert.Catch<Exception>(() => someNullObject.ToString());
As an aside, when debugging unit tests which throw exceptions, you may want to prevent VS from breaking on the exception.
Edit
Just to give an example of Matthew's comment below, the return of the generic Assert.Throws
and Assert.Catch
is the exception with the type of the exception, which you can then examine for further inspection:
// The type of ex is that of the generic type parameter (SqlException)
var ex = Assert.Throws<SqlException>(() => MethodWhichDeadlocks());
Assert.AreEqual(1205, ex.Number);
Unfortunately MSTest STILL only really has the ExpectedException attribute (just shows how much MS cares about MSTest) which IMO is pretty awful because it breaks the Arrange/Act/Assert pattern and it doesnt allow you to specify exactly which line of code you expect the exception to occur on.
When I'm using (/forced by a client) to use MSTest I always use this helper class:
public static class AssertException
{
public static void Throws<TException>(Action action) where TException : Exception
{
try
{
action();
}
catch (Exception ex)
{
Assert.IsTrue(ex.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + ex.GetType() + " was thrown instead.");
return;
}
Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");
}
public static void Throws<TException>(Action action, string expectedMessage) where TException : Exception
{
try
{
action();
}
catch (Exception ex)
{
Assert.IsTrue(ex.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + ex.GetType() + " was thrown instead.");
Assert.AreEqual(expectedMessage, ex.Message, "Expected exception with a message of '" + expectedMessage + "' but exception with message of '" + ex.Message + "' was thrown instead.");
return;
}
Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");
}
}
Example of usage:
AssertException.Throws<ArgumentNullException>(() => classUnderTest.GetCustomer(null));
Mark the test with the ExpectedExceptionAttribute (this is the term in NUnit or MSTest; users of other unit testing frameworks may need to translate).
Source: Stackoverflow.com