【问题标题】:Async method within constructor affecting unit tests构造函数中的异步方法影响单元测试
【发布时间】:2015-03-17 04:14:20
【问题描述】:

进行单元测试,测试仅在Jobs.Count > 0 时才允许导航。 GetJobsAsync() 在构造过程中被调用,如果不为空则清除 Jobs 列表(每次调用时获取新列表)。在我手动添加新作业作为单元测试通过的条件后,作业列表似乎已清除。如何正确设置此时间,以便在测试运行期间不会清除作业列表?

在 MyClass 构造函数中

this.GetJobsAsync();

GetJobsAsync

private async void GetJobsAsync()
{
    var jobs = await this.dataService.GetJobs();
    if (jobs != null)
    {
        this.Jobs.Clear();

        foreach (var job in jobs)
        {
            this.Jobs.Add(new JobViewModel(job));
        }
    }

    // have the select job command rerun its condition
    this.SelectJobCommand.RaiseCanExecuteChanged();
}

单元测试(必须至少有一个导航作业,作业添加后清空):

var vm = new MyClass();
vm.Jobs.Add(new JobVM(new JobModel()));
vm.SelectJobCommand.Execute(null);            
Assert.AreEqual(
  NavigationKeys.WizardJob,
  this.navigationService.CurrentPageKey);

【问题讨论】:

  • 这就是为什么你没有async void 不是顶级方法的方法。
  • 最好的做法不是设置 DataService 来返回作业吗?这样,测试流程就可以尽可能准确地模拟生产流程。通常我会通过在我的单元测试中使用一个 Mock DataService 对象来做到这一点。
  • 问题是,在真正的应用程序中,你有一个 SynchronizationContext 来保持单线程并为你维护顺序,而在单元测试中你没有一个,所以多个线程是跑步,你有一个比赛条件。
  • @SilasReinagel - 不确定,应该没问题,但问题仍然存在。

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


【解决方案1】:

在我手动添加新作业作为单元测试通过的条件后,作业列表似乎被清除了。

很明显,您了解自己有竞争条件。您不能在 async void 上等待,并且您在构造函数中。

如何正确设置此时间,以便在测试运行期间不会清除作业列表?

两件事。首先,将GetJobAsync 更改为async Task 而不是async void。然后,使用异步初始化模式:

public class MyClass
{
    public Task InitializeAsync()
    {
         return GetJobsAsync();
    }
}

在你的单元测试中:

public async Task TestNavigationAsync()
{
     var vm = new MyClass();
     await vm.InitializeAsync();

     vm.Jobs.Add(new JobVM(new JobModel()));
     vm.SelectJobCommand.Execute(null);       

     Assert.AreEqual(NavigationKeys.WizardJob,
                                  navigationService.CurrentPageKey); 
 }

这样可以保证执行的顺序。

【讨论】:

  • 这个问题是它不能很好地与 WPF 的模型一起工作。在典型的应用程序中,MyClass 将被创建并从您无法等待的属性 getter 初始化。
  • 谁说过 WPF 和属性?无论如何,他可以使用任何LoadedNavigated 事件通过AsyncCommand 触发初始化
  • @YuvalItzchakov - 我认为这对单元测试很有用,因为单元测试在继续之前等待数据,但我正在努力解决在实际代码中调用 InitializeAsync 的位置,因为它目前是在构造函数中...哦,等等,您可能刚刚回答过...
  • 显然它没有明确说明,但对 VM、命令和导航服务的引用强烈暗示了它或类似的 MVVM 框架。
  • @O.O - 没错。异步事件处理程序或异步命令是您所追求的。
猜你喜欢
  • 2020-07-14
  • 1970-01-01
  • 1970-01-01
  • 2022-11-11
  • 1970-01-01
  • 1970-01-01
  • 2011-11-07
  • 2015-06-29
  • 1970-01-01
相关资源
最近更新 更多