21

xUnitテストにasyncおよびawaitキーワードを適用する方法を見つけようとしています。xUnit1.9とAsyncCTP1.3を使用しています。これが私のテストケースです

1つの非同期メソッド呼び出しを指定するインターフェイスがあります

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

インターフェイスを使用してasyncメソッドを呼び出すクラスがあります

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

このテストでは、asyncandawaitキーワードを使用しています。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で期待される動作ですか?


アップデート

スティーブンのコメントに感謝します。2つの変更を加えることで最初のテストを修正することができました。テストはvoidではなくタスクを返すようになり、モックもタスクを返します。

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

2 に答える 2

15

Taskユニットテストメソッドを、の代わりに戻るように変更するvoidと、機能するはずです。async voidユニットテストのサポートは、将来のリリースで検討されています

非同期単体テストがデフォルトで機能しない理由をブログで詳しく説明します。(私のブログの例ではMSTestを使用していますが、xUnit1.9より前を含む他のすべてのテストランナーにも同じ問題がありました)。

于 2012-06-27T17:59:59.813 に答える
3

'Update'のコードを使おうとしましたが、モックしていたasyncメソッドで停止していました。

    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; } );
于 2014-01-23T00:37:03.883 に答える