次のコードを実行すると:
_[Test]
public async Task Can_Test_Update()
{
var response = await _controller.UpdateAsync(Guid.NewGuid());
response.Valid.Should().BeTrue();
_commands.Received().UpdateAsync(
Arg.Is<Something>(
l => l.Status == Status.Updated));
}
_
「_commands.Received().UpdateAsync
」の前に「await
」を追加すると、null参照例外がスローされます。どうすればこれを止めることができますか、またはawait
は必要ありませんか?
私は答えを見つけました ここ 。
Received.InOrder(async () =>
{
await _Commands.UpdateAsync(Arg.Is<Lobby>(l => l.Status == Status.Updated));
});
NSubstituteが非同期呼び出しを検出すると、完了したタスクが自動的に作成されるため、コードで期待どおりに待機が機能します(NullReferenceExceptionはスローされません)。この場合、それはテストしているメソッド内の_commands.UpdateAsync(Status.Updated))
から返されるタスクになります。
一方、.Received()
呼び出しは、asyncメソッドが呼び出されたこと、つまり完全に同期していることを確認しているため、待機する必要はありません。
覚えておくべき重要なことは、非同期メソッドはTask
を返すということです。 asyncメソッドを呼び出してタスクを返すのは完全に同期しているので、タスクが表す非同期操作がいつ完了するかを知るためにTask
を待ちます。
スタックオーバーフローの この回答 によると、NSubstituteバージョン1.8.3以降、await
を使用でき、NullReferenceExceptionをスローするのではなく、期待どおりに機能します。
バージョン1.5.0で試してみたところ、説明どおりにNullReferenceExceptionが発生しましたが、現在は最新(1.10.0)を使用しており、正常に機能しています。
Jake Ginnivanの回答 は、Received awaitは不要であることを正しく示していますが、コンパイラはそれを理解せず、次のように表示します。
警告CS4014:この呼び出しは待機されていないため、呼び出しが完了する前に現在のメソッドの実行が続行されます。呼び出しの結果に「await」演算子を適用することを検討してください。
最も簡単な回避策は、警告を抑制することです
#pragma warning disable 4014 //for .Received await is not required, so suppress warning “Consider applying the 'await' operator”
_publisher.Received(totalNumber).MyMethod(Arg.Any<ParamType>());
#pragma warning restore 4014
UpdateAsyncがスタブメソッドである場合は、nullではなく空のタスクを返す必要があります。 nullタスクを待つことはできません。
例:
receivedObject.Stub(s => s.Update(...)).Return(Task.FromResult(0));
編集
問題はこの行にあります:
var mockService = Substitute.For<ICalculationServiceAsync>();
もっと正確に言えば、それをメソッドと呼ぶとき:
await _service.Calculate();
モックサービスを作成しますが、メソッドをスタブ化しません。 Nunitでそれを行う方法はわかりませんが(主にRhinoを使用しているので、確認する必要があります)、空のタスク(Task.FromResult(0))を返すにはCalculateメソッドをスタブ化する必要があります。デフォルトでは、スタブメソッドはデフォルトの戻り値の型を返し、default(Task)はnullです。
について あなたの要点 :DoSomethingAsyncはasyncvoidであってはなりません。私はあなたがそれの実行を待ちたいと思うだろうと思います。
「_commands.Received()。UpdateAsync」の前に「await」を追加すると、エラーnull参照が発生します
これは、await
を実行しない場合、メソッド(Can_Test_Update
)メソッドに渡したnull値を実際にチェックする前に終了する場合があります。つまり、テストが終了します。競合状態があります。 await
でUpdateAsync
を実行すると、メソッドは実際には操作が完了するのを非同期的に待機し、UpdateAsync
は渡されたnullにアクセスする機会を得ます。
エラーを解決するには、UpdateAsync
内にブレークポイントを設定し、どの値がnullとしてメソッドに渡されるかを確認します。 Arg.Is<Something>
はあなたの問題です。