Unit testing ReactiveUI-取消另一个命令-文档中代码的单元测试失败
我从中获取代码并尝试对其进行单元测试,但失败。Unit testing ReactiveUI-取消另一个命令-文档中代码的单元测试失败,unit-testing,reactiveui,Unit Testing,Reactiveui,我从中获取代码并尝试对其进行单元测试,但失败。 它是关于调用一个命令来取消另一个命令 下面是要测试的类 public class SomeViewModel : ReactiveObject { public SomeViewModel(IScheduler scheduler) { this.CancelableCommand = ReactiveCommand .CreateFromObservable(
它是关于调用一个命令来取消另一个命令 下面是要测试的类
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;
}
}
}
执行cancel命令
(控制台日志上的断点被命中),但是任务延迟
从未被取消。似乎,TakeUntil
没有请求取消
更新我编辑了上面的代码,以便我的
ViewModel
ctor使用IScheduler
并根据创建命令,但测试仍然失败。我试过nUnit和xUnit。
我还尝试按照在测试设置中执行
RxApp.MainThreadScheduler=Scheduler.Immediate
,但仍然失败
更新2从我标记为答案和注释的解决方案来看,最简单的方法是不在ctor中使用isScheduler,然后像这样编写测试,测试就通过了
[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);
}
这对我有用:
public class SomeViewModelTest
{
SomeViewModel m_actual;
[SetUp]
public void Setup()
{
m_actual = new SomeViewModel(CurrentThreadScheduler.Instance);
m_actual.Activator.Activate();
}
[Test]
public void Executing_cancel_should_cancel_cancelableTask()
{
m_actual.CancelableCommand.Execute().Subscribe();
m_actual.CancelCommand.Execute().Subscribe();
Assert.IsTrue(m_actual.IsCancelled);
}
}
我在测试中更改了调度程序以使用相同的方法,并且我的ViewModel确实实现了ISupportsActivation,我敢说在这里不会有任何区别。
除此之外,我从测试中删除了async/await,在Rx中不需要它,只需订阅命令。问题是,取消命令后,您正在等待命令的执行。由于取消发生在命令执行之前,因此不会影响命令的执行。您可以按如下方式使其通过:
public async Task Executing_cancel_should_cancel_cancelableTask()
{
var sut = new SomeViewModel(Scheduler.Immediate);
sut.CancelableCommand.Execute().Subscribe();
await sut.CancelCommand.Execute();
Assert.True(sut.IsCancelled);
}
在这里,我立即开始执行命令(通过订阅)。随后的取消将影响该执行
一般来说,Rx和TPL的混合总是有点混乱。这是可行的,但每个角落都潜伏着这样的陷阱和丑恶。作为一个长期的解决方案,我强烈建议转向“纯”Rx。您不会回头看-这太神奇了。也许,您需要看看如何使用没有延迟的单元测试运行程序。快速搜索发现这篇文章可能会有所帮助。Tks但是:i)我不完全理解ii)RxApp没有aDeferredScheduler属性ii)在文章中,作者说reactiveui正在检测测试运行程序并正在执行调度程序切换。DeferredScheduler被重命名为MainThreadScheduler。我使它成为即时调度程序,但测试仍然失败。我在用NUnit。将尝试使用xUnit。问题仍然存在于即时计划程序以及nUnit和xUnit上。@François如果这是一个测试/学习项目,您介意与我分享吗,这样我可以尝试调试并查看发生了什么?实际上,订阅使其工作(而不是安装或激活程序)。我不明白为什么。我会深入调查医生的。Tks无论如何:-)调度程序也是无用的。解决方案只来自于订阅。所以考虑一下这个问题。。。调用Execute时,它将调用传递到ReactiveCommand中的函数。因此,在您的例子中,该函数是Observable.StartAsync,用于检索任务,但此时,即使检索到任务,Observable本身仍然没有被订阅。因此,在您等待取消的原始代码中,“CancelableCommand”在技术上仍然没有启动。所以cancel命令运行,然后完成运行,然后您“等待t”,但现在cancel命令已经运行了。希望这能让SENSEYA变得有意义,但它是值得的:-)我只想指出,这更多的是关于理解Observable.StartAsync是如何工作的,而不是RxUI是如何工作的。当你调用Observable.StartAsync时,它将立即执行你的任务方法,但是Observable本身在技术上还没有启动。因此,如果您想延迟任务的执行,那么您需要将Observable.StartAsync与Observable.deference包在一起,这将是最困难的部分。我不仅对ReactiveUI而且对Rx编程都是新手。我非常习惯于任务,而不是观察到的任务。每次执行一个步骤,在取消任务后等待该任务,该步骤可处理任务。我会采纳你的建议,避免把任务和观察结果混为一谈
public async Task Executing_cancel_should_cancel_cancelableTask()
{
var sut = new SomeViewModel(Scheduler.Immediate);
sut.CancelableCommand.Execute().Subscribe();
await sut.CancelCommand.Execute();
Assert.True(sut.IsCancelled);
}