-1

I have a unit test, something like:

[Test]
public void ThingController__Put__when_thing_is_invalid__then__throws()
{
    var controller = this.CreateThingController();

    try
    {
        var r = controller.Put("thing1", this.CreateInvalidThing());
    }
    catch(HttpResponseException hrex) when (hrex.Response.StatusCode == HttpStatusCode.BadRequest)
    {
        return; // implicit pass.
    }
    catch(Exception ex)
    {
        Assert.Fail($"Wrong exception {ex.GetType().Name}");
    }

    Assert.Fail("No exception thrown!");
}

But it always hits the last Fail, i.e. no exception is thrown. I have turned on first chance exceptions and can see it being thrown and is rethrown all the way up. It definitely is bubbling all the way up.

Note: SO flagged this as a possible duplicate of

Unit testing async method for specific exception

That question is a how-to but this one is a problem-solution, specifically for why a catch is not being hit, i.e. you know how, but made a common mistake forgetting that the action is async - because they normally don't have Async suffix - and needs unwrapping.

Community
  • 1
  • 1
Luke Puplett
  • 42,091
  • 47
  • 181
  • 266
  • 1
    Possible duplicate of [Unit testing async method for specific exception](http://stackoverflow.com/questions/12837128/unit-testing-async-method-for-specific-exception) – Gilad Green Aug 02 '16 at 09:26

2 Answers2

3

If your Put method is an async Task method, which I suspect it is based on the issue you're describing you can modify your test method to appropriately handle async/await by making the signature async Task. If your Put method is async task, it is executing as a hot task but since it is not being awaited currently your unit test thread continues on before your exception is actually raised. Essentially the original code is creating a fire and forget scenario.

[Test]
public async Task ThingController__Put__when_thing_is_invalid__then__throws()
{
    var controller = this.CreateThingController();

    try
    {
        var r = await controller.Put("thing1", this.CreateInvalidThing());
    }
    catch(HttpResponseException hrex) when (hrex.Response.StatusCode == HttpStatusCode.BadRequest)
    {
        return; // implicit pass.
    }
    catch(Exception ex)
    {
        Assert.Fail($"Wrong exception {ex.GetType().Name}");
    }

    Assert.Fail("No exception thrown!");
}
davidallyoung
  • 1,302
  • 11
  • 15
  • Note: recent testing frameworks support this but if working on an old project you may still need to check your version. – Luke Puplett Aug 14 '16 at 07:50
0

Is the Put action method asynchronous?

If so, then you are not accessing the result of the action and the exception is not being 'unwrapped'.

You should either be calling r.ExecuteAsync(...) if its an IHttpActionResult, or adding r.Wait(); under the call to Put(...).

You may also need to alter your catch block to catch AggregateException and inspect it.

Luke Puplett
  • 42,091
  • 47
  • 181
  • 266
  • 1
    Instead of `r.Wait()`, you should make the unit test `async` and use `await r`. Then you won't have to deal with `AggregateException`. – svick Aug 02 '16 at 12:54
  • Can't disagree with that. See also http://stackoverflow.com/questions/12191831/how-do-i-test-an-async-method-with-nunit-eventually-with-another-framework – Luke Puplett Aug 03 '16 at 11:21