我有一个异步函数说DoWork()可以完成一些工作并将结果存储在一个文件中。所以返回类型是无效的。我需要为这个函数编写一个单元测试,这就是我的问题。
internal sealed class MainClass: InheritedClass
{
public override async void Start()
{
base.Start();
var result = await TaskEx.Run(() => DoSomeWork());
Store(result);
}
}
在单元测试类中,如果我有类似下面的代码,它不会等待,它会移动到下一行执行但未通过测试。那么,如何在基本操作完成之前使其等待。
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();
由于
答案 0 :(得分:3)
正如其他人所说,最好的解决方案是将方法更改为返回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");
}
根据评论进行更新:
更改基类是最佳解决方案。它是 hard 解决方案的事实并没有改变它是最佳解决方案的事实。
也就是说,如果你不想实现最佳解决方案,那么可能使用AsyncContext
type from my AsyncEx library来单元测试async void
方法:
public void StoreDataTest()
{
AsyncContext.Run(() => MainClass.Start());
var data = UtilityClass.GetStoredData();
Assert.IsNotNull(data, "No data found");
}
请注意,单元测试方法实际上是同步的,因为它会阻止单元测试线程,直到async void
方法完成。这是一种危险的做法,不推荐用于实际应用程序代码,但适用于单元测试(换句话说,只能在入口点执行此操作)。