web-dev-qa-db-ja.com

NSubstitute-非同期で受信-「呼び出しが待機されていない」警告

非同期メソッドが正しいパラメーターで呼び出されたことを確認しようとしています。ただし、次の警告が表示されます。

「この呼び出しは待機されないため、現在のメソッドの実行は、呼び出しが完了する前に続行されます。呼び出しの結果に「待機」演算子を適用することを検討してください。」この警告は、_//Assert_コメント(下記)の下のコード行に表示されます。

NSubstituteを使用したテストは次のとおりです。

_[Test]
public async Task SimpleTests()
{
  //Arrange
  var request = CreateUpdateItemRequest();

  databaseHelperSub.ExecuteProcAsync(Arg.Any<DatabaseParams>()).Returns(Task.FromResult((object)null));

  //Act      
  await underTest.ExecuteAsync(request);

  //Assert
  databaseHelperSub.Received().ExecuteProcAsync(Arg.Is<DatabaseParams>(
    p => p.StoredProcName == StoredProcedureName
         && p.Parameters[0].ParameterName == "Param1"
         && p.Parameters[0].Value.ToString() == "Value1"
         && p.Parameters[1].ParameterName == "Param2"
         && p.Parameters[1].Value.ToString() == "Value2"));
}
_

テスト対象のユニットunderTest.ExecuteAsync(request)ExecuteProcedureAsyncを呼び出し、待機を実行します。

_var ds = await DatabaseHelper.ExecuteProcAsync(dbParams);
_

NSubstituteを使用すると、テスト対象のユニットの実行後にReceived()が必要になるためです。 RhinoMocksでは、expectを呼び出して、テスト中のユニットが実行される前に呼び出すことができます。 RhinoMocksはTask.FromResult()を返すことができますが、NSubstituteは返すことができません。

機能するRhinoMocksの同等の機能は次のとおりです。

_[Test]
        public async Task SimpleTest()
        {
            // Arrange
            var request = new UpdateItemRequest();

            databaseHelperMock.Expect(m => m.ExecuteProcAsync(Arg<DatabaseParams>.Matches(
                p =>   p.StoredProcName == StoredProcedureName
                    && p.Parameters[0].ParameterName == "Param1"
                    && p.Parameters[0].Value.ToString() == "Value1"
                    && p.Parameters[1].ParameterName == "Param2"
                    && p.Parameters[1].Value.ToString() == "Value2
                ))).Return(Task.FromResult<object>(null));

            // Act
            await underTest.ExecuteAsync(request);

        }
_

問題を削除する拡張メソッドを追加できる回避策があることを確認しました。

_  public static class TestHelper
  {
    public static void IgnoreAwait(this Task task)
    {

    }
  }
_

NSubstituteのテスト行は次のように実行でき、警告は消えます。

_databaseHelperSub.Received().ExecuteProcAsync(Arg.Is<DatabaseParams>(
        p => p.StoredProcName == StoredProcedureName
             && p.Parameters[0].ParameterName == "Param1"
             && p.Parameters[0].Value.ToString() == "Value1"
             && p.Parameters[1].ParameterName == "Param2"
             && p.Parameters[1].Value.ToString() == "Value2")).IgnoreAwait();
    }
_

しかし、私はこれについてもっと良い解決策があるはずだと思いましたか?

23
JBond

バージョン1.9.0以降に更新するとすぐに、awaitを受け取らずにNullReferenceExceptionを使用できるようになります。

21
Marcio Rinaldi

Received()述語が複雑すぎる場合やNSubstituteと一致しない場合は、常に callbacks を使用してWhen().Do()または.AndDoes()。このようなものになるあなたのユースケースのために

DatabaseParams receivedParms = null;
databaseHelperSub.ExecuteProcAsync(Arg.Any<DatabaseParams>())
  .Returns(Task.FromResult((object)null))
  .AndDoes(x => receivedParms = x.Arg<DatabaseParams>);

//Act      
await underTest.ExecuteAsync(request);

//Assert
receivedParms.Should().NotBeNull();
// assert your parms...
7
mkoertgen

Jake Ginnivanの回答 は、Received awaitは必要ないことを説明していますが、コンパイラはそれを理解していません。

安全に警告を抑制できます

 #pragma warning disable 4014 //for .Received await is not required, so suppress warning “Consider applying the 'await' operator”
   _service.Received(totalNumber).MyMethod(Arg.Any<ParamType>());
 #pragma warning restore 4014