4

我想对包含如下注册的视图模型进行单元测试:

 public SampleViewModel(IUnityContainer container)
    {
...
    Observable.FromEventPattern<PropertyChangedEventArgs>(gridViewModel, "PropertyChanged")
                    .**ObserveOnDispatcher()**
                    .Subscribe(_ => this.Update());
...
}

当我运行单元测试时,它告诉我“当前线程没有与之关联的调度程序。 ”到达此代码时。

一种解决方案是使用调度程序,但我不想修改 Viewmodel。

有没有办法让单元测试通过这个语句而不报错?

4

4 回答 4

8

我建议您提供自己的IScheduler实现ObserveOn(IScheduler)而不是使用ObserveOnDispatcher()运算符。我已经使用了加载 aDispatcherFrame或 a的技术,Dispatcher但问题是您仍在使用 Dispatcher。最终我发现你只是“从悬崖上掉下来”,尤其是当你涉及到长时间运行的后台线程时。遵循“单元测试中没有线程”的指导方针,只是不要让调度程序靠近您的 ViewModel!您的单元测试将运行得更快。

处理此问题的一种更好的方法是注入一个接口,该接口可以访问您的 Dispatcher Scheduler(通过该IScheduler接口)。这允许您替换公开TestScheduler. 您现在可以在单元测试中控制时间。您可以控制和验证将哪些操作编组到每个调度程序。

这是一篇关于 2009 年初使用 Dispatcher 调用的“单元”测试 WPF 的非常古老的(Rx 之前)帖子。当时这似乎是个好主意。

https://leecampbell.com/2009/02/17/responsive-wpf-user-interfaces-part-5/

有关使用 Rx 进行测试的更多信息,请参阅TestScheduler我在 Rx 上的其他站点

http://introtorx.com/Content/v1.0.10621.0/16_TestingRx.html

于 2013-09-25T22:05:32.550 回答
2

这对我有用。在设置单元测试时,我创建了一个应用程序来模拟我的 VM 的环境:

static Application App;

static void BeforeTestRun()
{
  var waitForApplicationRun = new ManualResetEventSlim();
  Task.Run(() =>
  {
    App = new Application();
    App.Startup += (s, e) => { waitForApplicationRun.Set(); };
    App.Run();
  });

  waitForApplicationRun.Wait();      
}

这就是我使用它来实例化视图模型的方式。

App.Dispatcher.Invoke(() => { this.viewModel = new ViewModel(); }); 
于 2015-02-04T10:45:46.903 回答
1

要正确地对您的视图模型进行单元测试,您确实需要能够提供其所有依赖项。在这种情况下,您的视图模型依赖于调度程序。使您的视图模型具有IScheduler依赖关系是理想的方法。但是,如果您真的不想这样做,请尝试查看这个重复的问题:Unit test IObservable<T> with ObserveOnDispatcher

于 2013-09-20T13:31:09.187 回答
0

我找到了避免错误的解决方案,只需从单元测试代码中使用调度程序实例化 ViewModel,例如:

SampleViewModel sampleViewModel;
var dispatcher = Application.Current != null ? Application.Current.Dispatcher : Dispatcher.CurrentDispatcher;

 dispatcher.Invoke((Action)(() => sampleViewModel = new SampleViewModel(this.container);

仅此而已,似乎无需修改当前代码即可工作,也许还有更好的解决方案。

于 2013-09-23T05:57:44.070 回答