I'm trying to write an integration test for a Viewmodel that calls an async method on my model(Foo). However I can't get the timing/threading/async processing to work.
I've reduced to problem to the code below. For now this test fails because the actual value of myFoo.Value is 0 instead of 123.
using System.Reactive;
using Microsoft.Reactive.Testing;
using ReactiveUI.Testing;
using ReactiveUI.Fody.Helpers;
using ReactiveUI;
using System.Reactive.Linq;
using System.Reactive.Concurrency;
namespace Cooler.Test;
public class Foo
{
public int Value { get; private set; }
public Foo() => Value = 42;
public async Task<Unit> SetValueAsync(int value)
{
await RxApp.TaskpoolScheduler.Sleep(TimeSpan.FromMilliseconds(10));
Value = value;
return Unit.Default;
}
}
public class ViewModel : ReactiveObject
{
public ViewModel(Foo foo)
{
this.WhenAnyValue(x => x.Setpoint)
//.Skip(1) // Skip the initial value
.ObserveOn(RxApp.MainThreadScheduler)
.SelectMany(foo.SetValueAsync)
.Subscribe();
}
[Reactive]
public int Setpoint { get; set; }
}
public class Test
{
[Fact]
public void ShouldCallAsyncMethodOnSettingReactiveSetpoint()
{
new TestScheduler().With(scheduler =>
{
//set
var myFoo = new Foo();
var myVm = new ViewModel(myFoo);
//act
scheduler.AdvanceBy(1); //process the initial value if not skipped
scheduler.AdvanceByMs(20); //async processing
myVm.Setpoint = 123;
scheduler.AdvanceBy(2); //process reactive
scheduler.AdvanceByMs(20); //I expect it to process setpoint setting
//assert
Assert.Equal(123, myFoo.Value);
});
}
}
I expected the value to be 123. But foo.SetValueAsync is not called with 123. Only the initial call with value 0. If I use the skip(1) line the value is 42, which is logical seeing the previous result.
Why does this test fail?
I was mistaken in thinking the method called by SelectMany
would run on the RxApp.MainThreadScheduler
as well. It doesn't. So the Assert
is finished before SetValueAsync
is called.