Question

I use xUnit and FluentAssertions to write my unit tests and I am stuck at the following problem. As I have not implemented the catch (in GetCountriesAsync) of the WebException yet, I throw a new NotImplementedException in this place.

This code is the only way I made the test actually work as expected. I added the native xUnit implementation either, due to FluentAssertions is just syntactic sugar.

[Fact]
public async Task GetCountriesAsyncThrowsExceptionWithoutInternetConnection()
{
    // Arrange
    Helpers.Disconnect(); // simulates network disconnect
    var provider = new CountryProvider();

    try
    {
        // Act
        var countries = await provider.GetCountriesAsync();
    }
    catch (Exception e)
    {
        // Assert FluentAssertions
        e.Should().BeOfType<NotImplementedException>();

        // Assert XUnit
        Assert.IsType<NotImplementedException>(e);
    }
}

Though I found this implementation a lot nicer, it just doesn't work.

[Fact]
public async Task GetCountriesAsyncThrowsExceptionWithoutInternetConnection3()
{
    // Arrange
    Helpers.Disconnect(); // simulates network disconnect
    var provider = new CountryProvider();

    // Act / Assert FluentAssertions
    provider.Invoking(async p => await p.GetCountriesAsync())
            .ShouldThrow<NotImplementedException>();

    // Act / Assert XUnit
    Assert.Throws<NotImplementedException>(async () => await provider.GetCountriesAsync());
}

As VS2012/ReSharper already suggests to remove the redundant async keyword of the test method, I replaced async Task with void and the test still behaves the same, so I suspect the async Actions cannot be awaited, they're rather fired and forgotten.

Is there a way to implement this properly with xUnit/FluentAssertions? I think I have to go with my first implementation as I can't see any functionality like InvokingAsync().

Was it helpful?

Solution

Actually, FA 2.0 has specific support for handling asynchronous exceptions. Just look at the unit tests in AsyncFunctionExceptionAssertionSpecs. for various examples.

OTHER TIPS

Regarding FluentAssertions, I've added the following to my code:

using System;
using System.Threading.Tasks;

namespace FluentAssertions
{
    public static class FluentInvocationAssertionExtensions
    {
        public static Func<Task> Awaiting<T>(this T subject, Func<T, Task> action)
        {
            return () => action(subject);
        }
    }
}

and now you can do:

_testee.Awaiting(async x => await x.Wait<Foo>(TimeSpan.Zero))
        .ShouldThrow<BarException>();

whereas _teste.Wait<T> returns a Task<T>. Also the naming of the method Awaiting make sense, because pure invocation of the method will not result in the exception being caught by the caller, you do need to use await to do so.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top