How to test SelectMany() calling an async method? #3643
-
I'm trying to test a Viewmodel that calls an async method on my model(Foo). This is what I got:
I expected What do I do wrong? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 4 replies
-
TestScheduler isn't compatible with async/await sadly - if you use TestScheduler, everything has to go through That being said, TestScheduler is more appropriate for testing elapsed time, but what you really care about here is ordering - "A" happened then "B", then "C" - we don't care about exactly how much time passes. The easiest way to do this is to start mocking methods that return public class ViewModel : ReactiveObject
{
public ViewModel(Foo foo, Func<Foo, val, Task<Unit>> fooSetter = null)
{
// NB: There are lots of way better ways to replace methods to test them, this
// is just for illustration purposes
fooSetter = fooSetter ?? ((x, val) => x.SetValueAsync(val));
this.WhenAnyValue(x => x.Setpoint)
//.Skip(1) // Skip the initial value
// .ObserveOn(RxApp.MainThreadScheduler) // NB: WhenAny is guaranteed to already be on UI thread!
.SelectMany(v => fooSetter(foo, v))
.Subscribe();
}
[Reactive]
public int Setpoint { get; set; }
}
public class Test
{
[Fact]
public void ShouldCallAsyncMethodOnSettingReactiveSetpoint()
{
//set it up
var myFoo = new Foo();
var completion = new AsyncSubject<Unit>();
var myVm = new ViewModel(myFoo, (foo, x) => {
await completion;
foo.Value = x;
}));
// Set but we didn't complete it yet!
myVm.Setpoint = 123;
Assert.NotEqual(123, myFoo.Value);
completion.OnNext(Unit.Default);
completion.OnCompleted();
// Now we did it!
Assert.Equal(123, myFoo.Value);
});
}
} |
Beta Was this translation helpful? Give feedback.
TestScheduler isn't compatible with async/await sadly - if you use TestScheduler, everything has to go through
RxApp.MainThreadScheduler
andRxApp.TaskPoolScheduler
.That being said, TestScheduler is more appropriate for testing elapsed time, but what you really care about here is ordering - "A" happened then "B", then "C" - we don't care about exactly how much time passes. The easiest way to do this is to start mocking methods that return
Task<T>
withAsyncSubject
andIObservable<T>
s withSubject
: