Unit testing for inner exceptions
this is an old question but i want to share my own implementation of ExpectedInnerExceptionAttribute
with you guys. maybe useful for someone
public class ExpectedInnerExceptionAttribute : ExpectedExceptionBaseAttribute
{
public ExpectedInnerExceptionAttribute(Type exceptionType)
{
this.ExceptionType = exceptionType;
}
public Type ExceptionType { get; private set; }
protected override void Verify(Exception ex)
{
if (ex != null && ex.InnerException != null
&& ex.InnerException.GetType() == this.ExceptionType)
{
return;
}
throw ex;
}
}
You could also extend it to check exception message etc. you just need to add Your own logic in Verify method.
Not a total solution, but in NUnit, you can do this sort of thing:
var ex = Assert.Throws<Exception>(() => thing.ThatThrows());
Assert.That(ex.InnerException, Is.TypeOf<BadException>() );
Maybe you can in your test framework?
For unit testing i currently use FluentAssertions. Since i learned it i never wanted to assert stuff in any other way.
For asserting exceptions look at this bit of the documentation
In particular this part
Action act = () => subject.Foo2("Hello");
act.ShouldThrow<InvalidOperationException>()
.WithInnerException<ArgumentException>()
.WithInnerMessage("whatever")
If your framework doesn't support custom throwing, you usually have two choices:
- Implement it yourself
- Change (or extend) framework
I'll start with second solution. Consider using FluentAssertions library. It allows you to do something like this:
Action deleteUser = () => usersRepository.Delete(new User { Id = null });
deleteUser
.ShouldThrow<UserNotFoundException>()
.WithInnerException<ArgumentNullException>()
.WithInnerMessage("User Id must have value");
You will still use Visual Studio testing framework, just that you'll have one extra library for, well - fluent assertions.
First choice on the other hand is a bit more work as it is usually the case with hand-rolled solutions:
try
{
usersRepository.Delete(new User { Id = null });
Assert.Fail("Deleting user with null id should throw");
}
catch (UserNotFoundException ue)
{
Assert.AreEqual(ue.InnerException.Message, "User Id must have value");
}
You replace ExpectedException
attribute with custom code asserting actual exception instance. Like I said, it is more work but does the trick.