使用异步方法的模拟依赖永远不会将控制权返回给调用者

问题描述 投票:0回答:1

使用 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));
它仍然卡在循环中。我怀疑任务调度程序在返回调用者之前决定等待是否要保留线程?

不确定我是否误解了异步方法是如何被嘲笑的。

谢谢!

c# asynchronous nsubstitute
1个回答
0
投票

异步状态机仅在有异步工作要做时才注册回调,并在可能的情况下同步完成。

通过返回

Task.Completed Task
,您的代码可以同步完成,因此不会返回控制流。另一方面,
Task.Delay
安排回调,从而返回控制流。

很好的发现!

© www.soinside.com 2019 - 2024. All rights reserved.