c# – 验证正在等待任务
我有以下代码,我想测试:
private Task _keepAliveTask; // get's assigned by object initializer public async Task EndSession() { _cancellationTokenSource.Cancel(); // cancels the _keepAliveTask await _logOutCommand.LogOutIfPossible(); await _keepAliveTask; } 重要的是EndSession Task只在`_keepAliveTask’结束后才结束.但是,我很难找到一种方法来可靠地测试它. 问题:如何对EndSession方法进行单元测试并验证EndSession返回的任务是否等待_keepAliveTask. 出于演示目的,单元测试可能如下所示: public async Task EndSession_MustWaitForKeepAliveTaskToEnd() { var keepAliveTask = new Mock<Task>(); // for simplicity sake i slightly differ from the other examples // by passing the task as method parameter await EndSession(keepAliveTask); keepAliveTask.VerifyAwaited(); // this is what i want to achieve } 进一步的标准: 我已经考虑了几个备选方案,我将在下面记录: 非异步方法 如果没有对_logOutCommand.LogOutIfPossible()的调用,那将非常简单:我只是删除异步并返回_keepAliveTask而不是等待它: public Task EndSession() { _cancellationTokenSource.Cancel(); return _keepAliveTask; } 单元测试看起来(简化): public void EndSession_MustWaitForKeepAliveTaskToEnd() { var keepAliveTask = new Mock<Task>(); // for simplicity sake i slightly differ from the other examples // by passing the task as method parameter Task returnedTask = EndSession(keepAliveTask); returnedTask.Should().be(keepAliveTask); } 但是,有两个论点反对这个: >我有多个需要等待的任务(我正在考虑Task.WhenAll down down) 非异步方法,异步同步 当然,我可以做类似的事情: public Task EndSession() { _cancellationTokenSource.Cancel(); // cancels the _keepAliveTask _logOutCommand.LogOutIfPossible().Wait(); return _keepAliveTask; } 但这是禁止的(同步异步).此外,它仍然存在先前方法的问题. 使用Task.WhenAll(…)的非异步方法 是(有效的)性能改进,但引入了更多的复杂性: 由于性能不是关键,我想避免额外的复杂性.此外,前面提到的问题,它只是将(验证)问题移动到EndSession方法的调用者也适用于此. 观察效果而不是验证电话 现在当然不是“单位”测试方法调用等.我总能观察到效果.这是:只要_keepAliveTask没有结束,EndSession任务也不能结束.但由于我不能无限期地等待,因此我必须暂时停止.测试应该很快,所以5秒的超时是不行的.所以我做的是: [Test] public void EndSession_MustWaitForKeepAliveTaskToEnd() { var keepAlive = new TaskCompletionSource<bool>(); _cancelableLoopingTaskFactory .Setup(x => x.Start(It.IsAny<ICancelableLoopStep>(),It.IsAny<CancellationToken>())) .Returns(keepAlive.Task); _testee.StartSendingKeepAlive(); _testee.EndSession() .Wait(TimeSpan.FromMilliseconds(20)) .Should().BeFalse(); } 但我真的不喜欢这种方法: >难以理解 解决方法
如果你想要的只是验证EndSession正在等待_keepAliveTask(并且你真的可以完全控制_keepAliveTask)那么你可以创建自己的等待类型而不是在等待时对任务进行处理,并检查:
public class MyAwaitable { public bool IsAwaited; public MyAwaiter GetAwaiter() { return new MyAwaiter(this); } } public class MyAwaiter { private readonly MyAwaitable _awaitable; public MyAwaiter(MyAwaitable awaitable) { _awaitable = awaitable; } public bool IsCompleted { get { return false; } } public void GetResult() {} public void OnCompleted(Action continuation) { _awaitable.IsAwaited = true; } } 因为所有你需要等待的东西是有一个GetAwaiter方法返回一些IsCompleted,OnCompleted和GetResult,你可以使用虚拟等待来确保正在等待_keepAliveTask: _keepAliveTask = new MyAwaitable(); EndSession(); _keepAliveTask.IsAwaited.Should().BeTrue(); 如果你使用一些模拟框架,你可以使Task的GetAwaiter返回我们的MyAwaiter. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |