NSubstitute - 收到异步 - “未等待呼叫”警告

NSubstitute - Received for async - “call is not awaited”warning

我正在尝试验证是否使用正确的参数调用了异步方法。但是,我收到警告:

"Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call"。此警告出现在 //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 中,您可以 期望 在执行被测单元之前发生调用。 RhinoMocks 可以 return 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();
    }

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

每当 Received() 谓词变得过于复杂或与 NSubstitute 不匹配时,您始终可以通过 When().Do().AndDoes() 使用 callbacks 捕获指定的参数。对于你的用例,会是这样的

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...

只要更新到 1.9.0 或更高版本,您就可以使用 await 而无需收到 NullReferenceException

解释说对于 Received 等待不是必需的,但是编译器不理解它。

您可以安全地取消警告

 #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