等待单元测试的Async Void方法调用
我有一个如下所示的方法:
private async void DoStuff(long idToLookUp)
{
IOrder order = await orderService.LookUpIdAsync(idToLookUp);
// Close the search
IsSearchShowing = false;
}
//Other stuff in case you want to see it
public DelegateCommand<long> DoLookupCommand{ get; set; }
ViewModel()
{
DoLookupCommand= new DelegateCommand<long>(DoStuff);
}
我想单元测试它是这样的:
[TestMethod]
public void TestDoStuff()
{
//+ Arrange
myViewModel.IsSearchShowing = true;
// container is my Unity container and it setup in the init method.
container.Resolve<IOrderService>().Returns(orderService);
orderService = Substitute.For<IOrderService>();
orderService.LookUpIdAsync(Arg.Any<long>())
.Returns(new Task<IOrder>(() => null));
//+ Act
myViewModel.DoLookupCommand.Execute(0);
//+ Assert
myViewModel.IsSearchShowing.Should().BeFalse();
}
在我完成LookUpIdAsync的模拟之前,我的断言被调用。 在我的正常代码中,这正是我想要的。 但是对于我的单元测试,我不想要那个。
我正在使用BackgroundWorker转换为Async / Await。 由于我可以等待BackgroundWorker完成,所以后台工作人员正常工作。
但似乎没有办法等待异步无效的方法......
我怎样才能单元测试这种方法?
一个async void
方法本质上是一个“火再忘”的方法。 没有办法找回完成事件(没有外部事件等)。
如果你需要单元测试这个,我建议把它变成一个async Task
方法。 然后可以对结果调用Wait()
,该方法完成后会通知您。
但是,这种写入的测试方法仍然不起作用,因为您并不是直接测试DoStuff
,而是测试包装它的DelegateCommand
。 您需要直接测试此方法。
你应该避免async void
。 仅对事件处理程序使用async void
。 DelegateCommand
是(逻辑上)一个事件处理程序,所以你可以这样做:
// Use [InternalsVisibleTo] to share internal methods with the unit test project.
internal async Task DoLookupCommandImpl(long idToLookUp)
{
IOrder order = await orderService.LookUpIdAsync(idToLookUp);
// Close the search
IsSearchShowing = false;
}
private async void DoStuff(long idToLookUp)
{
await DoLookupCommandImpl(idToLookup);
}
并单元测试它为:
[TestMethod]
public async Task TestDoStuff()
{
//+ Arrange
myViewModel.IsSearchShowing = true;
// container is my Unity container and it setup in the init method.
container.Resolve<IOrderService>().Returns(orderService);
orderService = Substitute.For<IOrderService>();
orderService.LookUpIdAsync(Arg.Any<long>())
.Returns(new Task<IOrder>(() => null));
//+ Act
await myViewModel.DoLookupCommandImpl(0);
//+ Assert
myViewModel.IsSearchShowing.Should().BeFalse();
}
我的建议答案在上面。 但是如果你真的想测试一个async void
方法,你可以用我的AsyncEx库来完成:
[TestMethod]
public void TestDoStuff()
{
AsyncContext.Run(() =>
{
//+ Arrange
myViewModel.IsSearchShowing = true;
// container is my Unity container and it setup in the init method.
container.Resolve<IOrderService>().Returns(orderService);
orderService = Substitute.For<IOrderService>();
orderService.LookUpIdAsync(Arg.Any<long>())
.Returns(new Task<IOrder>(() => null));
//+ Act
myViewModel.DoLookupCommand.Execute(0);
});
//+ Assert
myViewModel.IsSearchShowing.Should().BeFalse();
}
但是这个解决方案在其生命周期中更改了视图模型的SynchronizationContext
。
我想出了一种做单元测试的方法:
[TestMethod]
public void TestDoStuff()
{
//+ Arrange
myViewModel.IsSearchShowing = true;
// container is my Unity container and it setup in the init method.
container.Resolve<IOrderService>().Returns(orderService);
orderService = Substitute.For<IOrderService>();
var lookupTask = Task<IOrder>.Factory.StartNew(() =>
{
return new Order();
});
orderService.LookUpIdAsync(Arg.Any<long>()).Returns(lookupTask);
//+ Act
myViewModel.DoLookupCommand.Execute(0);
lookupTask.Wait();
//+ Assert
myViewModel.IsSearchShowing.Should().BeFalse();
}
这里的关键是,因为我是单元测试,我可以在任务中替换我想要的异步调用(在我的异步无效中)返回。 然后我才确定任务已完成,然后再继续。
链接地址: http://www.djcxy.com/p/50797.html