demoncodemonkey
demoncodemonkey

Reputation: 11957

How to use Assert.Catch with an async method

I just upgraded to NUnit 3, and I'm having some trouble getting my unit tests to pass.

[Test]
public void GetSomethingAsync_CallsConverter()
{
    int id = 123;

    Assert.Catch<NullReferenceException>(
        async () => await _repository.GetSomethingAsync(id));

    _fooMock.Verify(f => f.Bar(id), Times.Once);
}

NUnit gives me this error:

System.ArgumentException : 'async void' methods are not supported, please use 'async Task' instead

I managed to get my Assert.Throws to pass by changing it like this:

    Assert.Throws<NullReferenceException>(
        async () => await _repository.GetSomethingAsync(id));
//to
    Assert.That(
        async () => await _repository.GetSomethingAsync(id),
        Throws.InstanceOf<NullReferenceException>());

But there's no similar equivalent thing to Assert.Catch.
So how are we supposed to use Assert.Catch on async methods?

Upvotes: 3

Views: 3237

Answers (2)

Craig Selbert
Craig Selbert

Reputation: 777

I had a similar issue and I replaced the void return with Task so

Try replacing

[Test]
public void GetSomethingAsync_CallsConverter()

with

[Test]
public async Task GetSomethingAsync_CallsConverter()

So here is a example of how we are testing async calls

[Test]
public async System.Threading.Tasks.Task Integration_Get_Invalid_ReturnsUnauthorized()
{
    // ARRANGE
    const string url = "/api/v2/authenticate/999/wrongName/wrongPassword";

    // ACT
    var result = await Get(url);

    // ASSERT
    Assert.IsFalse(result.HttpResponseMessage.IsSuccessStatusCode); 
}

If you want to test that an exception is being raised use the following

Assert.Throws<ValidationException>(() =>
{
    var user = await _service.Get(2);
 });

Upvotes: 4

Stephen Cleary
Stephen Cleary

Reputation: 457197

I use my own AssertEx.ThrowsAsync method, since various unit testing frameworks / assertion libraries have varying amounts of support for async:

[Test]
public async Task GetSomethingAsync_CallsConverter()
{
  int id = 123;

  await AssertEx.ThrowsAsync<NullReferenceException>(
      async () => await _repository.GetSomethingAsync(id));

  _fooMock.Verify(f => f.Bar(id), Times.Once);
}

A fix is coming for NUnit. Unfortunately, they've chosen to implement it with a sync-over-async pattern, which I believe is a mistake that will come back to bite them later.

Upvotes: 2

Related Questions