异步和等待 - 单元测试问题

时间:2015-10-15 15:13:09

标签: c# .net unit-testing asynchronous async-await

我有一个异步函数说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();

由于

1 个答案:

答案 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方法完成。这是一种危险的做法,不推荐用于实际应用程序代码,但适用于单元测试(换句话说,只能在入口点执行此操作)。

相关问题