Rx reactive extensions Observeondispatcher unit test error: The current thread has no Dispatcher associated with it

StackOverflow https://stackoverflow.com/questions/18914544

Question

I want to unit test a view model which contains a registration like:

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

When I run the unit test it tells me that "The current thread has no Dispatcher associated with it." when reaching this code.

One solution would be to use a Scheduler but I don't want to modify the Viewmodel.

Is there a solution to make the unit test pass this statement without getting an error?

Was it helpful?

Solution

I would suggest that you provide you own IScheduler implementation to ObserveOn(IScheduler) instead of using the ObserveOnDispatcher() operator. I have used techniques for loading a DispatcherFrame or a Dispatcher but the problem is that you are still using a Dispatcher. Eventually I found that you just "fall off the cliff" especially once you have long running background threads involved. Following the guidelines of "No threading in Unit tests" just dont let the dispatcher get near your ViewModels! Your Unit tests will run much, much faster.

A far superior way to deal with this is to inject an interface that gives access to your Dispatcher Scheduler (via the IScheduler interface). This allows you to substitute in an implementation that exposes the TestScheduler. You now can control time in your unit test. You can control and validate which actions are marshalled to each scheduler.

This is a really old (pre-Rx) post on 'Unit' testing WPF with Dispatcher calls from early 2009. It seemed like a good idea at the time.

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

More information on Testing with Rx and the TestScheduler is found in my other site on Rx

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

OTHER TIPS

This works for me. When setting up the unit test I create an application to simulate the environment for my 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();      
}

and this is how I use it to instanciate the view model.

App.Dispatcher.Invoke(() => { this.viewModel = new ViewModel(); }); 

To properly unit test your viewmodel, you really need to be able to supply all of its dependencies. In this case, your viewmodel has a dependency upon the dispatcher. Making your viewmodel take a IScheduler dependency is the ideal way. But if you really don't want to do that, then try looking at this duplicate question: Unit test IObservable<T> with ObserveOnDispatcher

I found a solution for avoiding the error, simply from Unit Test code instantiate the ViewModel by using a dispatcher like:

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

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

That's all and seems to work without modifying current code, maybe there are also better solutions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top