How do I use Assert
(or other Test class) to verify that an exception has been thrown?
22 Answers
For "Visual Studio Team Test" it appears you apply the ExpectedException attribute to the test's method.
Sample from the documentation here: A Unit Testing Walkthrough with 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");
}
Usually your testing framework will have an answer for this. But if it's not flexible enough, you can always do this:
try {
somethingThatShouldThrowAnException();
Assert.Fail(); // If it gets to this line, no exception was thrown
} catch (GoodException) { }
As @Jonas points out, this DOES NOT work for catching a base Exception:
try {
somethingThatShouldThrowAnException();
Assert.Fail(); // raises AssertionException
} catch (Exception) {
// Catches the assertion exception, and the test passes
}
If you absolutely must catch Exception, you need to rethrow the Assert.Fail(). But really, this is a sign you shouldn't be hand-writing this; check your test framework for options, or see if you can throw a more meaningful exception to test for.
catch (AssertionException) { throw; }
You should be able to adapt this approach to whatever you like -- including specifying what kinds of exceptions to catch. If you only expect certain types, finish the catch
blocks off with:
} catch (GoodException) {
} catch (Exception) {
// not the right kind of exception
Assert.Fail();
}
My preferred method for implementing this is to write a method called Throws, and use it just like any other Assert method. Unfortunately, .NET doesn't allow you to write a static extension method, so you can't use this method as if it actually belongs to the build in Assert class; just make another called MyAssert or something similar. The class looks like this:
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))
);
}
}
}
}
That means that your unit test looks like this:
[TestMethod()]
public void ExceptionTest()
{
String testStr = null;
MyAssert.Throws<NullReferenceException>(() => testStr.ToUpper());
}
Which looks and behaves much more like the rest of your unit test syntaxes.
if you use NUNIT, you can do something like this:
Assert.Throws<ExpectedException>(() => methodToTest());
It is also possible to store the thrown exception in order to validate it further:
ExpectedException ex = Assert.Throws<ExpectedException>(() => methodToTest());
Assert.AreEqual( "Expected message text.", ex.Message );
Assert.AreEqual( 5, ex.SomeNumber);
Be wary of using ExpectedException, as it can lead to several pitfalls as demonstrated here:
http://geekswithblogs.net/sdorman/archive/2009/01/17/unit-testing-and-expected-exceptions.aspx
And here:
http://xunit.github.io/docs/comparisons.html
If you need to test for exceptions, there are less frowned upon ways. You can use the try{act/fail}catch{assert}
method, which can be useful for frameworks that don't have direct support for exception tests other than ExpectedException
.
A better alternative is to use xUnit.NET, which is a very modern, forward looking, and extensible unit testing framework that has learned from all the others mistakes, and improved. One such improvement is Assert.Throws
, which provides a much better syntax for asserting exceptions.
You can find xUnit.NET at github: http://xunit.github.io/
In a project i´m working on we have another solution doing this.
First I don´t like the ExpectedExceptionAttribute becuase it does take in consideration which method call that caused the Exception.
I do this with a helpermethod instead.
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;
}
Neat, isn´t it;)
You can download a package from Nuget using: PM> Install-Package MSTestExtensions that adds Assert.Throws() syntax in the style of nUnit/xUnit to MsTest.
High level instructions: download the assembly and inherit from BaseTest and you can use the Assert.Throws() syntax.
The main method for the Throws implementation looks as follows:
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: I put together this package.
More Info: http://www.bradoncode.com/blog/2012/01/asserting-exceptions-in-mstest-with.html
I do not recommend using the ExpectedException attribute (since it's too constraining and error-prone) or to write a try/catch block in each test (since it's too complicated and error-prone). Use a well-designed assert method -- either provided by your test framework or write your own. Here's what I wrote and use.
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));
}
}
Example uses:
[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
Returning the exception instead of supporting a validation callback is a reasonable idea except that doing so makes the calling syntax of this assert very different than other asserts I use.
Unlike others, I use 'propagates' instead of 'throws' since we can only test whether an exception propagates from a call. We can't test directly that an exception is thrown. But I suppose you could image throws to mean: thrown and not caught.
FINAL THOUGHT
Before switching to this sort of approach I considered using the ExpectedException attribute when a test only verified the exception type and using a try/catch block if more validation was required. But, not only would I have to think about which technique to use for each test, but changing the code from one technique to the other as needs changed was not trivial effort. Using one consistent approach saves mental effort.
So in summary, this approach sports: ease-of-use, flexibility and robustness (hard to do it wrong).
Well i'll pretty much sum up what everyone else here said before...Anyways, here's the code i built according to the good answers :) All is left to do is copy and use...
/// <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.");
}
The helper provided by @Richiban above works great except it doesn't handle the situation where an exception is thrown, but not the type expected. The following addresses that:
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))
);
}
}
}
}
Since you mention using other test classes, a better option than the ExpectedException
attribute is to use Shoudly's Should.Throw.
Should.Throw<DivideByZeroException>(() => { MyDivideMethod(1, 0); });
Let's say we have a requirement that the customer must have an address to create an order. If not, the CreateOrderForCustomer
method should result in an ArgumentException
. Then we could write:
[TestMethod]
public void NullUserIdInConstructor()
{
var customer = new Customer(name := "Justin", address := null};
Should.Throw<ArgumentException>(() => {
var order = CreateOrderForCustomer(customer) });
}
This is better than using an ExpectedException
attribute because we are being specific about what should throw the error. This makes requirements in our tests clearer and also makes diagnosis easier when the test fails.
Note there is also a Should.ThrowAsync
for asynchronous method testing.
There is an awesome library called NFluent which speeds up and eases the way you write your assertions.
It is pretty straightforward to write an assertion for throwing an exception:
[Test]
public void given_when_then()
{
Check.ThatCode(() => MethodToTest())
.Throws<Exception>()
.WithMessage("Process has been failed");
}
Even though this is an old question, I would like to add a new thought to the discussion. I have extended the Arrange, Act, Assert pattern to be Expected, Arrange, Act, Assert. You can make an expected exception pointer, then assert it was assigned to. This feels cleaner than doing your Asserts in a catch block, leaving your Act section mostly just for the one line of code to call the method under test. You also don't have to Assert.Fail();
or return
from multiple points in the code. Any other exception thrown will cause the test to fail, because it won't be caught, and if an exception of your expected type is thrown, but the it wasn't the one you were expecting, Asserting against the message or other properties of the exception help make sure your test won't pass inadvertently.
[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);
}