Reputation: 557
I am writing some unit tests using Visual Studio's integrated framework. I need to write some test cases which pass when a proper exception is thrown. The problem is that the exceptions i need to test for are inner exceptions nested in a more general one. Is there some easy solution or do I need to extend the whole functionality. I am currently using the [ExpectedException] attribute, but it wont do much good in such a situation.
I am also curious what happens when we use [ExpectedException] while we also have some Assert logic in the test itself. Are both the conditions evaluated(exception was thrown and the Assert statement turned out to be valid) or the test passes immediately after the correct exception is thrown?
Upvotes: 26
Views: 15590
Reputation: 966
I prefer to use Assert.Catch()
in that case:
var exception = Assert.Catch(() => It.Throws()).InnerException;
Assert.That(exception, Is.TypeOf<CustomException>());
Upvotes: 0
Reputation: 176
FluentAssertions is really helpful.
and I achieved my solution using it as given below. This is checking my custom exception ProcessFailureException
from AggregateException
Func<Task> func = async () => await item.ProcessAsync(context, message);
func.Should().Throw<AggregateException>().WithInnerException<ProcessFailureException>();
Upvotes: 2
Reputation: 6973
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?
Upvotes: 27
Reputation: 5669
Just use GetAwaiter()
and GetResult()
to check for inner exception:
Assert.Throws<InnerException>(() => thing.GetAwaiter().GetResult());
e.g.
Assert.Throws<CommunicationException>(() => thing.GetAwaiter().GetResult());
Upvotes: -3
Reputation: 8718
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")
Upvotes: 2
Reputation: 1438
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.
Upvotes: 6
Reputation: 31464
If your framework doesn't support custom throwing, you usually have two choices:
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.
Upvotes: 19