多线程 – 在单元可测试的MVVM代码中使用Dispatcher

我有一个MVVM-lite应用程序,我想要单元可测试.该模型使用System.Timers.Timer,因此更新事件最终在后台工作线程上.这个单元测试很好,但是在运行时抛出了System.NotSupportedException“这种类型的CollectionView不支持从与dispatcher线程不同的线程更改其SourceCollection.”我曾希望MVVM-lite类Threading.dispatcherHelper可以解决问题,但调用dispatcherHelper.CheckBeginInvokeOnUI导致我的单元测试失败.这是我在视图模型中最终得到的代码

private void locationChangedHandler(object src,LocationChangedEventArgs e)
{
    if (e.LocationName != this.CurrentPlaceName)
    {
        this.CurrentPlaceName = e.LocationName;
        List<FileInfo> filesTaggedForHere = Tagger.FilesWithTag(this.CurrentPlaceName);

        //This nextline fixes the threading error,but breaks it for unit tests
        //galaSoft.MvvmLight.Threading.dispatcherHelper.CheckBeginInvokeOnUI(delegate { updateFilesIntendedForHere(filesTaggedForHere); });

        if (Application.Current != null)
        {
            this.dispatcher.Invoke(new Action(delegate { updateFilesIntendedForHere(filesTaggedForHere); }));
        }
        else
        {
            updateFilesIntendedForHere(filesTaggedForHere);
        }
    }
}
private void updateFilesIntendedForHere(List<FileInfo> filesTaggedForHereIn)
{
    this.FilesIntendedForHere.Clear();
    foreach (FileInfo file in filesTaggedForHereIn)
    {
        if (!this.FilesIntendedForHere.Contains(file))
        {
            this.FilesIntendedForHere.Add(file);
        }
    }
}

我在http://kentb.blogspot.com/2009/04/mvvm-infrastructure-viewmodel.html中尝试过这个技巧,但在单元测试期间对dispatcher.Currentdispatcher上的Invoke调用无法运行,因此失败了.这就是为什么我在运行测试而不是应用程序时直接调用辅助方法的原因.

这可能不对 – viewmodel不应该关心它的调用位置.任何人都可以看到为什么Kent Boogaart的调度程序方法和MVVM-lite dispatcherHelper.CheckBeginInvokeOnUI都不能在我的单元测试中工作?

解决方法

我是这样做的:

class Myviewmodel() {
    private readonly SynchronizationContext _syncContext;

    public Myviewmodel() {
        _syncContext = SynchronizationContext.Current; // or use DI
    )

    ...

    public void SomeTimerEvent() {
        _syncContext.Post(_ => UpdateUi(),null);
    }
}

认上下文将是测试中的线程池和UI中的调度程序.如果您想要其他一些行为,也可以轻松创建自己的测试上下文.

相关文章

HashMap是Java中最常用的集合类框架,也是Java语言中非常典型...
在EffectiveJava中的第 36条中建议 用 EnumSet 替代位字段,...
介绍 注解是JDK1.5版本开始引入的一个特性,用于对代码进行说...
介绍 LinkedList同时实现了List接口和Deque接口,也就是说它...
介绍 TreeSet和TreeMap在Java里有着相同的实现,前者仅仅是对...
HashMap为什么线程不安全 put的不安全 由于多线程对HashMap进...