28

On VS 2013, I can't get this async test to fail.

I have xUnit 1.8.0.1539 (installed from nuget), with the xUnit Test Runner VS extension (0.99.5). All current, AFAIK.

I happen to also have Moq, AutoFixture, and FluentAssertions reference in the unit test, but I don't think that matters (but I'm admitting it in case it does).

I have done async unit tests in other areas of my solution, and they work.

I'm missing something with this newly created tests, and I can't tell what I'm missing or doing wrong.

NOTE The SUT code is not meant to be complete. I'm just trying to get the red light first, before I write the code to make the test go green.

Here's the test code:

using System.Threading.Tasks;
using FluentAssertions;
using Xunit;

namespace MobileApp.Proxy.Test
{
public class WhenRetrievingPriceDataFromClient
{
    [Fact]
    public async Task GroupReportIsReturnedWithSomeData()
    {
        // arrange
        var sut = new Client();

        // act
        var actual = await sut.GetReportGroupAsync();

        // assert

        // Xunit test
        Assert.Null(actual);
        Assert.NotNull(actual);
        // FluentAssertions
        actual.Should().BeNull();
        actual.Should().NotBeNull();
    }
}
}

And here is the SUT code:

using System;
using System.Diagnostics;
using System.Net.Http;
using System.Threading.Tasks;
using MobileApp.Proxy.Properties;

namespace MobileApp.Proxy
{
    public class Client
    {
        public async Task<ReportGroup> GetReportGroupAsync()
        {
            return await Task.FromResult(new ReportGroup());
        }
    }
}

Obviously, this test should fail! The Asserts for Null and NotNull can't both succeed, so my conclusion is that the test is exiting before it finishes getting the response from the SUT.

What did I miss?

OR, is there a better way I should have started an async test to make sure it fails before writing the SUT code?

Josh Gallagher
  • 5,211
  • 2
  • 33
  • 60
Alan McBee
  • 4,202
  • 3
  • 33
  • 38

2 Answers2

33

You need xUnit 1.9 for async unit tests to work correctly.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Doh! I realize now what I did that led to this. Rather than installing each package from Nuget that I wanted, I relied on Nuget's automatic package dependency resolver, and installed the "AutoFixture with xUnit.net data theories" package, expecting that it would retrieve the latest package, when it actually retrieved the exact package version that it depended on. – Alan McBee Apr 08 '14 at 18:52
15

Async tests are supported in xUnit v1.9 or later. If you're stuck with an earlier version, you'll need to do something like this:

[Fact]
public void GroupReportIsReturnedWithSomeData()
{
     GroupReportIsReturnedWithSomeDataAsync().Wait();
}

private async Task GroupReportIsReturnedWithSomeDataAsync()
{
    // arrange
    var sut = new Client();

    // act
    var actual = await sut.GetReportGroupAsync();

    // assert

    // Xunit test
    Assert.Null(actual);
    Assert.NotNull(actual);
    // FluentAssertions
    actual.Should().BeNull();
    actual.Should().NotBeNull();
}

Basically, the test method blocks until the async test method completes, whether it'd due to successful completion or fault (e.g., a failed assertion). In the case of a fault, the exceptions will propagate to the main test thread through Wait().

You may want to pass a timeout to Wait() so your test will fail if it hasn't completed after a certain amount of time. As written, the test could block indefinitely if the async method never completes.

Mike Strobel
  • 25,075
  • 57
  • 69
  • Doesn't the 'await' keyword do the same thing as calling the 'Wait()' method? But I'll try your suggestion and report back. UPDATE - Never mind that - I realize you just wrote a wrapper. I'll try that. – Alan McBee Apr 08 '14 at 18:33
  • 1
    No. The `Wait()` method blocks until the task completes. The `await` keyword basically tells the compiler "resume running the following code after this task completes". When that code continues, and on what thread, is determined by the kind of object you are awaiting (in this case, a `Task`). If you use `await` from the main thread, you may end up exiting before the task completes. – Mike Strobel Apr 08 '14 at 18:35
  • Right. And I'm going to try this. But I was led to believe the Xunit supports async tests. (and yes, I know you said you don't use it). – Alan McBee Apr 08 '14 at 18:38
  • Based on the link in Stephen's answer, it seems async test support was added in xUnit v1.9. The link also says that my approach is the way to go for earlier versions. – Mike Strobel Apr 08 '14 at 18:43
  • 1
    This approach will likely cause deadlocks if there is a synchronization context set when calling these methods. – Servy Apr 08 '14 at 18:45
  • @Servy Why it will cause a deadlock? There is no call to '.result' – Mandeep Janjua Feb 23 '19 at 06:46
  • @MandeepJanjua just google "async deadlock" for an explanation of the most common reason why this code will deadlock. There are lots of explanations out there. – Servy Feb 23 '19 at 21:29
  • @Servy Sorry, I missed this call - GroupReportIsReturnedWithSomeDataAsync().Wait() . Yes, it will cause deadlock. Regarding your comment - there are a lot of ways, we can cause a deadlock. Just googling with generic "async deadlock", will not lead to an answer that can address the given crisis situation. – Mandeep Janjua Feb 25 '19 at 01:57
  • @MandeepJanjua Yes, there are lots of ways to cause a deadlock, but there is one way that's particularly common when using the `async` keyword, and that's what's going to fill up the majority of the top search results when searching for "async deadlock", hence why I felt confident saying it would describe the problem and what to do to fix it, and it seems it *did* allow you learn said information, so it appears the assumption was valid. – Servy Feb 25 '19 at 14:29