[Edit (May 2020)] - This issue has been reportedly addressed in newer releases of NUnit. Please see Nunit.ThrowsAsync. (Ref this answer, thanks @James-Ross)
This blog talks about problems similar to mine.
I followed the recommendation proposed there, and have a test like this -
[Test]
public void ShouldThrow404WhenNotFound()
{
var mockUserRepository = new Mock();
mockUserRepository.Setup(x => x.GetByUserName(It.IsAny())).Returns(default(User));
var userController = new UserController(mockUserRepository.Object) { Request = new HttpRequestMessage() };
var aggregateException = Assert.Throws(() => userController.Get("foo").Wait());
var httpResponseException = aggregateException.InnerExceptions
.FirstOrDefault(x => x.GetType() == typeof(HttpResponseException)) as HttpResponseException;
Assert.That(httpResponseException, Is.Not.Null);
Assert.That(httpResponseException.Response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
I am not too pleased with it, but this works.
EDIT 1
Inspired by @StephenCleary, I added a static helper class that does the asserts that I am looking for. It looks like this -
public static class AssertEx
{
public static async Task ThrowsAsync(Func func) where TException : class
{
await ThrowsAsync(func, exception => { });
}
public static async Task ThrowsAsync(Func func, Action action) where TException : class
{
var exception = default(TException);
var expected = typeof(TException);
Type actual = null;
try
{
await func();
}
catch (Exception e)
{
exception = e as TException;
actual = e.GetType();
}
Assert.AreEqual(expected, actual);
action(exception);
}
}
I can now have a test like -
[Test]
public async void ShouldThrow404WhenNotFound()
{
var mockUserRepository = new Mock();
mockUserRepository.Setup(x => x.GetByUserName(It.IsAny())).Returns(default(User));
var userController = new UserController(mockUserRepository.Object) { Request = new HttpRequestMessage() };
Action asserts = exception => Assert.That(exception.Response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
await AssertEx.ThrowsAsync(() => userController.Get("foo"), asserts);
}