异步和等待——单元测试问题
本文关键字:单元测试 问题 等待 异步 | 更新日期: 2023-09-27 18:17:48
我有一个异步函数说DoWork(),它做一些工作,并将结果存储在一个文件中。所以返回类型是void。我需要为这个函数写一个单元测试,我的问题来了。
internal sealed class MainClass: InheritedClass
{
public override async void Start()
{
base.Start();
var result = await TaskEx.Run(() => DoSomeWork());
Store(result);
}
}
在单元测试类中,如果我有下面这样的代码,它不会等待,它移动到下一行执行,测试失败。那么,我怎样才能使它WAIT直到基本操作完成呢?
public async Task StoreDataTest()
{
var t = Task.Factory.StartNew(MainClass.Start);
t.Wait();
var data = UtilityClass.GetStoredData();
Assert.IsNotNull(data, "No data found");
}
重写Start()时不能更改返回类型。在我的例子中,基类在许多地方被继承,并且不能更改基类中虚方法的返回类型。那么我应该开始使用后台工作者和事件处理程序吗?我应该使用这种方法吗?
我们不能使用。net 4.5,因为我们仍然支持XP:(所以,我在。net 4.0上使用BCL库来获得异步和等待功能。最近,我看到一些博客建议不要使用backgroundworker,因为它在以后的。net版本中已经过时了。
List<EntityClass> result = null;
var worker = new BackgroundWorker();
worker.DoWork += (sender, e) =>
{
result = GetData();
};
worker.RunWorkerCompleted += (sender, eventArgs) =>
{
if (result == null)
{
return;
}
Store(result);
// Event used for Unit testing purpose
if (DataStoredEvent != null)
{
DataStoredEvent(this, new EventArgs());
}
};
worker.RunWorkerAsync();
谢谢
正如其他人所指出的,最好的解决方案是将方法更改为返回Task
,这是不带返回值的异步方法的自然返回类型:
internal sealed class MainClass: InheritedClass
{
public override async Task StartAsync()
{
base.Start();
var result = await TaskEx.Run(() => DoSomeWork());
Store(result);
}
}
附带说明,我建议您不要在业务逻辑类中使用TaskEx.Run
;这个方法最好只从UI层调用。
一旦你的方法正确返回Task
,单元测试是直接的:
public async Task StoreDataTest()
{
await MainClass.StartAsync();
var data = UtilityClass.GetStoredData();
Assert.IsNotNull(data, "No data found");
}
基于注释更新:
更改基类是最好的解决方案。虽然这是一个困难的解决方案,但这并不能改变它是最佳解决方案的事实。
也就是说,如果你不想实现最好的解决方案,它是可能的单元测试async void
方法使用AsyncContext
类型从我的AsyncEx库:
public void StoreDataTest()
{
AsyncContext.Run(() => MainClass.Start());
var data = UtilityClass.GetStoredData();
Assert.IsNotNull(data, "No data found");
}
注意,单元测试方法实际上是同步的,因为它阻塞了单元测试线程,直到async void
方法完成。这是一种危险的做法,不建议用于实际的应用程序代码,但对于单元测试来说很好(换句话说,只在入口点这样做)。