使用 NSubstitute 时,我遇到了似乎是错误或我不理解 NSubstitute 或 async/await 如何工作的问题。
我正在尝试测试一个具有 while 循环的异步方法,如下所示:
public class ClassUnderTest {
private readonly IDependencyToBeMocked _dependency;
ClassUnderTest(IDependencyToBeMocked dependency) {
_dependency = dependency;
}
public async Task MethodToBeTested(CancellationToken token) {
while (!stoppingToken.IsCancellationRequested)
{
await _dependency.Wait();
}
}
}
public interface IDependencyToBeMocked {
Task Wait();
}
我已经像这样安排了我的测试,使用 xUnit 和 NSubstitute。
public class Tests
{
private readonly IDependencyToBeMocked _dependency;
private readonly ClassUnderTest _classUnderTest;
public Tests()
{
_dependency = Substitute.For<IDependencyToBeMocked>();
_classUnderTest = new ClassUnderTest(_dependency);
}
[Fact]
public async Task Test()
{
// arrange
var source = new CancellationTokenSource();
_dependency.Wait().Returns(Task.CompletedTask);
// act
var task = _classUnderTest.MethodToBeTested(source.Token);
await source.CancelAsync();
await task;
// assert
// do some assertions
}
}
运行测试时出现问题。它永远不会超过线
var task = _classUnderTest.MethodToBeTested(source.Token);
并且取消令牌永远不会被取消。
要测试的方法永远不会返回给调用者,尽管事实上它没有被等待。我希望它第一次点击
await _dependency.Wait()
时控制权返回给调用者(即 Test() 方法),但它仍然永远卡在 while 循环中。
肯定会发生一些奇怪的事情:如果我改变它,那么
_dependency.Wait().Returns(Task.Delay(10));
测试就会按预期进行;但是,如果我使用 _dependency.Wait().Returns(Task.Delay(1));
它仍然卡在循环中。我怀疑任务调度程序在返回调用者之前决定等待是否要保留线程?
不确定我是否误解了异步方法是如何被嘲笑的。
谢谢!
异步状态机仅在有异步工作要做时才注册回调,并在可能的情况下同步完成。
通过返回
Task.Completed Task
,您的代码可以同步完成,因此不会返回控制流。另一方面,Task.Delay
安排回调,从而返回控制流。
很好的发现!