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
我正在尝试验证是否使用正确的参数调用了异步方法。但是,我收到警告:
"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
。
您可以安全地取消警告
#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