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:

  1. Implement it yourself
  2. 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.