xUnit and Moq do not support async - await keywords

送分小仙女□ 提交于 2019-12-22 01:27:07

问题


I am trying to discover how to apply the async and await keywords to my xUnit tests. I am using xUnit 1.9 and Async CTP 1.3. Here is my test case

I have an interface which specifies one asynchronous method call

public interface IDoStuffAsync
{
    Task AnAsyncMethod(string value);
}

I have a class which consumes the interface and calls the async method

public class UseAnAsyncThing
{
    private readonly IDoStuffAsync _doStuffAsync;

    public UseAnAsyncThing(IDoStuffAsync doStuffAsync)
    {
        _doStuffAsync = doStuffAsync;
    }

    public async Task DoThatAsyncOperation(string theValue)
    {
        await _doStuffAsync.AnAsyncMethod(theValue);
    }
}

In my tests I wish to check that the method DoThatAsyncOperation is calling the method with the correct value so I mock the interface and use the Moq to verify the call

    [Fact]
    public async void The_test_will_pass_even_though_it_should_fail()
    {
        var mock = new Mock<IDoStuffAsync>();
        var sut = new UseAnAsyncThing(mock.Object);

        mock.Setup(x => x.AnAsyncMethod(It.IsAny<string>()));

        await sut.DoThatAsyncOperation("test");

        // This won't throw a Moq.MockExcpetion so the test appears to pass
        // However it does not run
        mock.Verify(x => x.AnAsyncMethod("fail"));
    }

This test is using the async and await keywords. When it runs it erroneously passes as Moq should assert that the verify fails. Any code after the call to sut.DoThatAsyncOperation("test"); does not run

    [Fact]
    public void This_will_work_and_assert_the_reslt()
    {
        var mock = new Mock<IDoStuffAsync>();
        var sut = new UseAnAsyncThing(mock.Object);

        mock.Setup(x => x.AnAsyncMethod(It.IsAny<string>()));

        sut.DoThatAsyncOperation("test").ContinueWith(y => { });

        // This won't throw a Moq.MockExcpetion so the test appears to pass
        // However it does not run
        mock.Verify(x => x.AnAsyncMethod("fail"));
    }

This test is setup without the await and async keywords and passes fine.

Is this expected behavior for xUnit and Moq?


Update

Thanks for Stephen's comment I managed to fix the first test by making two changes. The test now returns a Task instead of void and the Mock also returns a Task.

    [Fact]
    public async Task The_test_will_pass_even_though_it_should_fail()
    {
        var mock = new Mock<IDoStuffAsync>();
        var sut = new UseAnAsyncThing(mock.Object);

        mock.Setup(x => x.AnAsyncMethod(It.IsAny<string>())).ReturnAsync(true);

        await sut.DoThatAsyncOperation("test");

        // This now fails as it should
        mock.Verify(x => x.AnAsyncMethod("fail"));
    }

回答1:


Change your unit test method to return Task instead of void, and it should work. Support for async void unit tests is being considered for a future release.

I describe in detail why async unit tests don't work by default on my blog. (My blog examples use MSTest, but the same problems existed in every other test runner, including xUnit pre-1.9).




回答2:


I tried to use the code from your 'Update', but it was stopping at the async method that I was mocking.

    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(default(T));


    mock.Setup(x => x.AnAsyncMethod(It.IsAny<T>())).Returns(tcs.Task);

So to fix that I had to change the 'Return' method:

    mock.Setup(x => x.AnAsyncMethod(It.IsAny<T>())).Returns(()=> { return tcs.Task; } );


来源:https://stackoverflow.com/questions/11230567/xunit-and-moq-do-not-support-async-await-keywords

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!