如何测试async Task方法执行前的同步代码并验证LoadingState为Busy
解决方案
你可以通过TaskCompletionSource手动控制LoadData()返回的Task的完成时机,在await挂起的节点断言加载状态:
[Fact] public async Task Refresh_WhenExecuting_ExpectLoadingStateBusy() { // 创建手动控制完成状态的Task var tcs = new TaskCompletionSource<bool>(); var mockDataService = Substitute.For<IDataService>(); // 让mock的LoadData返回我们控制的未完成Task mockDataService.LoadData().Returns(tcs.Task); var dataRepository = new DataRepository(mockDataService); // 启动Refresh方法但不等待它完成 var refreshTask = dataRepository.Refresh(); // 此时Refresh已经执行完await之前的同步代码,状态已设置为Busy dataRepository.LoadingState.Should().Be(LoadingState.Busy); // 手动完成Task,让Refresh执行后续逻辑,避免测试残留未完成任务 tcs.SetResult(true); await refreshTask; }
实现原理
Refresh方法中await dataService.LoadData()之前的代码都是同步执行的,当你调用dataRepository.Refresh()时,会立刻执行到await LoadData()这一行才会把控制权交还给调用方- 我们通过
TaskCompletionSource返回一个不会主动完成的Task,此时Refresh方法会停在await节点,不会执行后续修改LoadingState为Done/Error的代码 - 这时候我们就可以安全断言
LoadingState为Busy,断言完成后手动结束Task即可
额外优化建议
建议把你之前的测试方法的返回值从async void改成async Task,这是XUnit推荐的异步测试写法,async void的测试在出错时可能会导致进程崩溃,也不便于异常追踪。
内容的提问来源于stack exchange,提问作者Ryan Payne
相关产品推荐
相关产品推荐

