我想对包含如下注册的视图模型进行单元测试:
public SampleViewModel(IUnityContainer container)
{
...
Observable.FromEventPattern<PropertyChangedEventArgs>(gridViewModel, "PropertyChanged")
.**ObserveOnDispatcher()**
.Subscribe(_ => this.Update());
...
}
当我运行单元测试时,它会在到达此代码时告诉我“当前线程没有与之关联的Dispatcher。”。
一种解决方案是使用调度程序,但我不想修改Viewmodel。
是否有解决方案使单元测试通过此语句而不会出现错误?
答案 0 :(得分:6)
我建议您向IScheduler
提供自己的ObserveOn(IScheduler)
实施,而不是使用ObserveOnDispatcher()
运算符。我使用了加载DispatcherFrame
或Dispatcher
的技术,但问题是您仍在使用Dispatcher。最终我发现你只是“从悬崖上掉下来”,特别是一旦你有长时间运行的背景线程。按照“单元测试中没有线程”的指导原则,不要让调度员靠近你的ViewModels!你的单元测试运行得更快,更快。
处理此问题的一个更好的方法是注入一个接口,该接口可以访问Dispatcher Scheduler(通过IScheduler
接口)。这允许您在公开TestScheduler
的实现中替换。您现在可以控制单元测试的时间。您可以控制和验证为每个调度程序编组的操作。
这是一个非常古老的(前Rx)帖子“单元”测试WPF与2009年初的Dispatcher调用。当时这似乎是一个好主意。
https://leecampbell.com/2009/02/17/responsive-wpf-user-interfaces-part-5/
有关使用Rx进行测试的更多信息以及我在Rx上的其他网站中找到了TestScheduler
答案 1 :(得分: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(); });
答案 2 :(得分:1)
要正确地对您的viewmodel进行单元测试,您确实需要能够提供其所有依赖项。在这种情况下,您的viewmodel依赖于调度程序。使您的viewmodel采用IScheduler
依赖关系是理想的方法。但如果你真的不想这样做,那么试着看看这个重复的问题:Unit test IObservable<T> with ObserveOnDispatcher
答案 3 :(得分:0)
我找到了一个避免错误的解决方案,只需从Unit Test代码中使用如下调度程序实例化ViewModel:
SampleViewModel sampleViewModel;
var dispatcher = Application.Current != null ? Application.Current.Dispatcher : Dispatcher.CurrentDispatcher;
dispatcher.Invoke((Action)(() => sampleViewModel = new SampleViewModel(this.container);
这一切似乎都可以在不修改当前代码的情况下工作,也许还有更好的解决方案。