首页 文章

xUnit和Moq不支持异步 - 等待关键字

提问于
浏览
19

我试图发现如何将async和await关键字应用于我的xUnit测试 . 我使用的是xUnit 1.9和Async CTP 1.3 . 这是我的测试用例

我有一个接口,它指定一个异步方法调用

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

我有一个使用接口并调用异步方法的类

public class UseAnAsyncThing
{
    private readonly IDoStuffAsync _doStuffAsync;

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

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

在我的测试中,我希望检查方法 DoThatAsyncOperation 是否正在使用正确的值调用方法,因此我模拟了接口并使用Moq来验证调用

[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"));
    }

此测试使用 asyncawait 关键字 . 当它运行时,它错误地通过,因为Moq应断言验证失败 . 调用 sut.DoThatAsyncOperation("test"); 后的任何代码都不会运行

[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"));
    }

此测试是在没有await和async关键字的情况下设置的,并且传递正常 .

这是xUnit和Moq的预期行为吗?


Update

感谢Stephen的评论,我设法通过进行两次更改来修复第一个测试 . 测试现在返回Task而不是void,Mock也返回一个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"));
    }

2 回答

  • 15

    更改单元测试方法以返回 Task 而不是 void ,它应该可以工作 . 支持 async void 单元测试is being considered for a future release .

    我在博客上详细描述了why async unit tests don't work by default . (我的博客示例使用MSTest,但每个其他测试运行器都存在相同的问题,包括xUnit pre-1.9) .

  • 3

    我尝试使用“更新”中的代码,但它停止在我正在嘲笑的异步方法中 .

    var tcs = new TaskCompletionSource<T>();
        tcs.SetResult(default(T));
    
    
        mock.Setup(x => x.AnAsyncMethod(It.IsAny<T>())).Returns(tcs.Task);
    

    所以要解决这个问题,我必须改变'Return'方法:

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

相关问题