Boiled down: I need to delay execution in my unit test thread so that an observable has time to update a property. Is there a Reactive way to do this without having to resort to Thread.Sleep?
I have a ViewModel that manages a ReactiveList of "Thing". Both ThingViewModel and the main ViewModel are derived from ReactiveObject. Thing has an IsSelected property and the ViewModel has a SelectedThing property that I keep synched based on observing changes on IsSelected. I have a couple of different views that use the ViewModel and this allows me to synch the selected Things between those views nicely. And it works. The problem comes when I try to unit test this interaction.
The ViewModel has this subscription in its constructor:
Things.ItemChanged.Where(c => c.PropertyName.Equals(nameof(ThingViewModel.IsSelected))).ObserveOn(ThingScheduler).Subscribe(c =>
{
SelectedThing = Things.FirstOrDefault(thing => thing.IsSelected);
});
In my unit test, this assert always fails:
thingVM.IsSelected = true;
Assert.AreEqual(vm.SelectedThing, thingVM);
But this assert always passes:
thingVM.IsSelected = true;
Thread.Sleep(5000);
Assert.AreEqual(vm.SelectedThing, thingVM);
Essentially, I need to wait long enough for the subscription to complete the change. (I don't really need that long to wait as when running in the UI, it's pretty snappy.)
I tried adding an observer in my unit test to wait on that processing, hoping they'd be similar. But that's been a wash. Here's what didn't work.
var itemchanged = vm.Things.ItemChanged.Where(x => x.PropertyName.Equals("IsSelected")).AsObservable();
. . .
thingVM.IsSelected = true;
var changed = itemChanged.Next();
Assert.AreEqual(vm.SelectedThing, thingVM);
Moving the itemChanged.Next around didn't help, nor did triggering iteration by calling .First() or .Any() on changed
(both of those hung the process as it blocked the thread for a notification that never occurred).
So. Is there a Reactive way to wait on that interaction so that I can Assert that the property change is happening correctly? I messed around some with TestScheduler (I needed manual Scheduler setting for the UI anyway, so this wasn't hard), but that doesn't seem to apply, as the actual action given to the scheduler happens in my ViewModel on ItemChanged and I couldn't find a way to make that trigger in the ways TestScheduler seems set up to work.