Can't Assert exception in async method with Xunit
Asked Answered
I

1

11

Some mistake in a code test rise this question, due the extension of the code, here is a complete project that replicates exactly the problem we have (to save you analyzing tons of lines).

The issue is when trying to catch an exception from an asynchronous method, here the AsyncTest.cs file:

using System;
using Xunit;

namespace AsyncTest
{
    public class AsyncTest
    {
        [Fact]
        public void ProbeTest()
        {
            // Arrange
            var probe = new Probe();

            // Act
            Action action = async () =>
                await probe.GetJob();

            // Assert
            var ex = Assert.Throws<InvalidOperationException>(action);
            Assert.Contains("Trouble with Project.", ex.Message);
        }
    }
}

Now, the Probe.cs class to be tested (Note the delay and the exception throwing in GetById method called by the GetJob method):

using System;
using System.Threading.Tasks;

namespace AsyncTest
{
    class Probe
    {
        public async Task<MyResult<Guid>> GetJob()
        {
            var etlJob = await GetById("id");
            return new MyResult<Guid>(etlJob);
        }

        public async Task<Guid> GetById(string id)
        {
            await Task.Delay(200);

            throw new InvalidOperationException("Trouble with Project.");
        }
    }
}

Last, the MyResult.cs class used by Probe.cs.

namespace AsyncTest
{
    public class MyResult<T>
    {
        private T _value;

        public MyResult(T Value)
        {
            _value = Value;
        }

        public string Message { get; set; }
        public T Data { get; set; }
    }
}

Apparently, the test ends before the exception is thrown even if the await Task.Delay(200); line is removed. In some cases using multiple breakpoints and placing the call in a loop, an exception is throw but not detected by the test.

It looks like a synchronous and asynchronous mix-up but can't figure out exactly what.

Thanks in advance.

Idiomatic answered 26/5, 2020 at 23:46 Comment(0)
S
16

Make your test method asynchronous and await the assertion:

[Fact]
public async Task ProbeTest()
{
    // Arrange
    var probe = new Probe();

    // Act
    Func<Task> action = async () => await probe.GetJob();

    // Assert
    var ex = await Assert.ThrowsAsync<InvalidOperationException>(action);
    Assert.Contains("Trouble with Project.", ex.Message);
}
Sideline answered 26/5, 2020 at 23:53 Comment(2)
Great !!!, Thanks. Is well know that async exceptions are registered into the task but did not figure out how to handle it.Idiomatic
This can also be a test for you based on this solution changing the Assert statement >> Assert.IsType<InvalidOperationException>(ex);Lobate

© 2022 - 2024 — McMap. All rights reserved.