Using the dispatcher in the module being tested by the MVVM module

I have an MVVM-lite application that I would like to test for unit. The model uses System.Timers.Timer, and therefore the update event ends in the background thread. This unit test is excellent, but at runtime threw a System.NotSupportedException "This type of CollectionView does not support changes to the SourceCollection from a stream other than the Dispatcher stream." I was hoping the MVVM-lite Threading.DispatcherHelper class would fix everything, but calling DispatcherHelper.CheckBeginInvokeOnUI would result in a unit test error. Here is the code I got in the view model

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); } } } 

I tried the trick at http://kentb.blogspot.com/2009/04/mvvm-infrastructure-viewmodel.html , but the Invoke call on Dispatcher.CurrentDispatcher did not start during the unit test and so it failed. This is why I call the helper method directly if the run is in a test and not in the application.

This may not be right - the ViewModel does not have to care about where it is being called from. Can anyone understand why neither the Kent Boogaart dispatcher method nor the MVVM-lite DispatcherHelper.CheckBeginInvokeOnUI work in my unit test?

+4
source share
3 answers

I do it like this:

 class MyViewModel() { private readonly SynchronizationContext _syncContext; public MyViewModel() { _syncContext = SynchronizationContext.Current; // or use DI ) ... public void SomeTimerEvent() { _syncContext.Post(_ => UpdateUi(), null); } } 

The default context will be threadpool in your test and dispatcher in the user interface. You can also easily create your own test context if you want a different behavior.

+1
source

I do not believe that in MVVM-lite there is an easy answer. You have the right solution to calling DispatcherHelper.CheckBeginInvokeOnUI. But, when the unit test runs, the user interface does not exist, and DispatcherHelper will not work correctly.

I am using ReactiveUI . Its version of DispatcherHelper.CheckBeginInvokeOnUI (RxApp.DeferredScheduler) will check if it will run in the unit test. If so, it will work in the current thread, instead of trying to marshal a nonexistent UI thread. You can use this code to create your own check in DispatcherHelper. The corresponding code is in the RxApp.cs InUnitTestRunner () method (line 196). These are pretty hacks, but it works, and I don't think there is a better way.

0
source

I just call the Initialize method in my ViewModelUnitTestBase and it works fine. Make sure DispatcherHelper.UIDispatcher is not null.

 public abstract class ViewModelUnitTestBase<T> where T : ViewModelBase { private T _viewModel = default(T); public T ViewModel { get { return _viewModel; } set { _viewModel = value; } } static ViewModelUnitTestBase() { DispatcherHelper.Initialize(); } } 
0
source

Source: https://habr.com/ru/post/1336733/


All Articles