0

I have ported my code to the RTM version of both WinRT and Rx. I use ReactiveUI in my ViewModels. Before porting the code my unit tests were running without problem but now I got a strange behavior.

Here the test:

var sut = new MyViewModel();
myViewModel.MyCommand.Execute(null) //ReactiveAsyncCommand
Assert.AreEqaul(0, sut.Collection.Count)

If I debug the test step by step, the assertion is not failing, but using the test runner it's failing...

The Collection asserted is modified by a method subscribing to the command:

MyCommand.RegisterAsyncTask(_ => DoWork())
            .ObserveOn(SynchronizationContext.Current)
            .Subscribe(MethodModifyingCollection);

The code was working before moving it to the RTM. I tried also to remove the ObserveOn and add an await Task.Delay() before the Assert without success.

MatthieuGD
  • 4,552
  • 2
  • 30
  • 29

2 Answers2

3

Steven's got the rightish answer, but there are a few RxUI specific things missing. This is definitely related to scheduling in a test runner, but the reason is that the WinRT version of ReactiveUI can't detect properly whether it's in a test runner at the moment.

The dumb workaround for now is to set this at the top of all your tests:

RxApp.DeferredScheduler = Scheduler.CurrentThread;

Do not use the TestScheduler for every test, it's overkill and actually isn't compatible with certain kinds of testing. TestScheduler is good for tests where you're simulating time passing.

Ana Betts
  • 73,868
  • 16
  • 141
  • 209
1

Your problem is that MSTest unit tests have a default SynchronizationContext. So ObserveOn and ReactiveAsyncCommand will marshal to the thread pool instead of to the WPF context. This causes a race condition.

Your first and best option is the Rx TestScheduler.

Another option is to await some completion signal (and ensure your test method is async Task, not async void).

Otherwise, if you just need a SynchronizationContext, you can use AsyncContext from my AsyncEx library to execute the tests within your own SynchronizationContext.

Finally, if you have any code that directly uses Dispatcher instead of SynchronizationContext, you can use WpfContext from the Async CTP download.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Thank Stephen for the answer. I'm going to test it tomorrow but I'm on WinRT so the WPF-related solutions are not an option. TestScheduler seems promising. – MatthieuGD Aug 30 '12 at 02:17
  • `WpfContext` - despite the name - just uses `Dispatcher` and I believe works for SL, so I expect it would work for WinRT as well. – Stephen Cleary Aug 30 '12 at 02:26