I take the code from ReactiveUi website documentation and try to unit test it but it fails.
It is about invoking a command to cancel another one.
Below is the class to test.
public class SomeViewModel : ReactiveObject
{
public SomeViewModel(IScheduler scheduler)
{
this.CancelableCommand = ReactiveCommand
.CreateFromObservable(
() => Observable
.StartAsync(DoSomethingAsync)
.TakeUntil(CancelCommand), outputScheduler: scheduler);
this.CancelCommand = ReactiveCommand.Create(
() =>
{
Debug.WriteLine("Cancelling");
},
this.CancelableCommand.IsExecuting, scheduler);
}
public ReactiveCommand<Unit, Unit> CancelableCommand
{
get;
private set;
}
public ReactiveCommand<Unit, Unit> CancelCommand
{
get;
private set;
}
public bool IsCancelled { get; private set; }
private async Task DoSomethingAsync(CancellationToken ct)
{
try
{
await Task.Delay(TimeSpan.FromSeconds(3), ct);
}
catch (TaskCanceledException)
{
IsCancelled = true;
}
}
}
And here is the unit test:
[TestFixture]
[Category("ViewModels")]
public class SomeViewModelFixture
{
public async Task Executing_cancel_should_cancel_cancelableTask()
{
var sut = new SomeViewModel(Scheduler.Immediate);
var t = sut.CancelableCommand.Execute();
await sut.CancelCommand.Execute();
await t;
Assert.IsTrue(sut.IsCancelled);
}
}
The CancelCommand
is excuted (a breakpoint on the Console log is hit) however the Task.Delay
is never cancelled. It seems TakeUntil
doesn't request the cancellation.
UPDATE
I edited the code above so that my ViewModel
ctor takes a IScheduler
and create the commands with it as per that issue about unit testing but the test still fails.
I tried both nUnit and xUnit.
I also tried to do RxApp.MainThreadScheduler = Scheduler.Immediate
in my test setup as per that article but still fails.
UPDATE2
From the solution that I marked as the answer and the comments, the simplest is not to use IScheduler in the ctor and then to write the test like that and it passes.
[Test]
public async Task Executing_cancel_should_cancel_cancelableTask()
{
var sut = new SomeViewModel();
sut.CancelableCommand.Execute().Subscribe();
await sut.CancelCommand.Execute();
Assert.IsTrue(sut.IsCancelled);
}