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

本文关键字:单元测试 问题 等待 异步 | 更新日期: 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方法完成。这是一种危险的做法,不建议用于实际的应用程序代码,但对于单元测试来说很好(换句话说,只在入口点这样做)。