NSubstitute – 收到异步 – “等待电话”警告

我试图validation使用正确的参数调用异步方法。 但是,我收到了警告:

“因为没有等待这个调用,所以当前方法的执行在调用完成之前继续。考虑将’await’运算符应用于调用的结果”。 此警告显示在//Assert注释(下方)下方的代码行上。

我使用NSubstitute进行的测试如下:

 [Test] public async Task SimpleTests() { //Arrange var request = CreateUpdateItemRequest(); databaseHelperSub.ExecuteProcAsync(Arg.Any()).Returns(Task.FromResult((object)null)); //Act await underTest.ExecuteAsync(request); //Assert databaseHelperSub.Received().ExecuteProcAsync(Arg.Is( 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并执行await:

 var ds = await DatabaseHelper.ExecuteProcAsync(dbParams); 

由于使用NSubstitute,在执行被测单元后需要Received()。 而在RhinoMocks中,您可以预期在执行测试单元之前进行调用。 RhinoMocks可以返回Task.FromResult()而NSubstitute不能。

RhinoMocks等效的工作原理如下:

 [Test] public async Task SimpleTest() { // Arrange var request = new UpdateItemRequest(); databaseHelperMock.Expect(m => m.ExecuteProcAsync(Arg.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(null)); // Act await underTest.ExecuteAsync(request); } 

我已经看到有一种解决方法,您可以添加扩展方法来删除问题:

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

这意味着我的NSubstitute测试行可以按如下方式执行,警告就会消失:

 databaseHelperSub.Received().ExecuteProcAsync(Arg.Is( 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(); } 

但是,我认为必须有更好的解决方案吗?

只要更新到1.9.0或更高版本,就可以await不接收NullReferenceException情况下使用await

每当Received()谓词变得过于复杂或者与NSubstitute不匹配时,您总是可以通过When().Do().AndDoes()使用回调来捕获指定的args。 对于你的用例,这将是这样的

 DatabaseParams receivedParms = null; databaseHelperSub.ExecuteProcAsync(Arg.Any()) .Returns(Task.FromResult((object)null)) .AndDoes(x => receivedParms = x.Arg); //Act await underTest.ExecuteAsync(request); //Assert receivedParms.Should().NotBeNull(); // assert your parms... 

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()); #pragma warning restore 4014