当我运行以下代码时:
[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));
}
如果我在“await
”之前添加“_commands.Received().UpdateAsync
”,则会抛出空引用异常。我怎样才能阻止这种情况发生,或者await
没有必要?
答案 0 :(得分:16)
我找到了答案here。
Received.InOrder(async () =>
{
await _Commands.UpdateAsync(Arg.Is<Lobby>(l => l.Status == Status.Updated));
});
答案 1 :(得分:6)
当NSubstitute看到异步调用时,它会自动创建一个已完成的任务,因此await的工作方式与您在代码中的预期相同(而不是抛出NullReferenceException)。在这种情况下,这将是您正在测试的方法中从_commands.UpdateAsync(Status.Updated))
返回的任务。
另一方面,.Received()
调用验证是否调用了异步方法,这是完全同步的,因此无需等待。
要记住的关键是异步方法返回Task
。调用异步方法并返回任务是完全同步的,然后等待Task
知道任务所代表的异步操作何时完成。
答案 2 :(得分:5)
根据Stack Overflow上的this answer,从NSubstitute版本1.8.3开始,您可以使用await
,它将按预期工作,而不是抛出NullReferenceException。
我刚试过它,因为我在版本1.5.0上并且正如你所描述的那样得到NullReferenceException,但是现在我处于最新版本(1.10.0),它运行良好。
答案 3 :(得分:2)
Jake Ginnivan answer正确指出不需要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
答案 4 :(得分:1)
显然您可以简单地await
Received
方法:
[Test]
public async Task Can_Test_Update()
{
var response = await _controller.UpdateAsync(Guid.NewGuid());
response.Valid.Should().BeTrue();
await _commands.Received().UpdateAsync(
Arg.Is<Something>(
l => l.Status == Status.Updated));
}
答案 5 :(得分:0)
当我在“_commands.Received()。UpdateAsync”之前添加“await”时, 它出现错误空引用
那是因为当你没有await
时,方法(Can_Test_Update
)可能会在它实际检查你传递给方法的空值之前结束,这意味着测试结束。你有竞争条件。在await
上UpdateAsync
时,该方法实际上异步等待操作完成,UpdateAsync
有机会访问您传递给它的空值。
要解决您的错误,只需在UpdateAsync
中放置一个断点,然后查看哪个值作为null传递给该方法。我怀疑Arg.Is<Something>
是你的问题。
答案 6 :(得分:0)
如果UpdateAsync是一个存根方法,则需要返回一个空Task,而不是null。您无法等待null任务。
示例:
receivedObject.Stub(s => s.Update(...)).Return(Task.FromResult(0));
修改强>
问题出在这一行:
var mockService = Substitute.For<ICalculationServiceAsync>();
或更准确地说,当你称之为方法时:
await _service.Calculate();
您创建了一个模拟服务,但您不会将该方法存根。我不确定如何在Nunit中执行此操作(我们主要使用Rhino,我需要检查),但是您需要将您的Calculate方法存根以返回一个空任务(Task.FromResult(0)) 。默认情况下,存根方法返回默认返回类型,默认(任务)为空。
关于your gist:DoSomethingAsync不应该是异步无效的。我想你会想要等待它的执行。