使用Rx RTM进行可观察的命令和单元测试

时间:2012-08-30 00:42:57

标签: windows-runtime system.reactive reactiveui

我已将我的代码移植到WinRT和Rx的RTM版本。我在ViewModels中使用ReactiveUI。在移植代码之前,我的单元测试运行没有问题,但现在我有一个奇怪的行为。

这里测试:

var sut = new MyViewModel();
myViewModel.MyCommand.Execute(null) //ReactiveAsyncCommand
Assert.AreEqaul(0, sut.Collection.Count)

如果我逐步调试测试,断言失败,但使用测试运行器失败...

声明的Collection由订阅命令的方法修改:

MyCommand.RegisterAsyncTask(_ => DoWork())
            .ObserveOn(SynchronizationContext.Current)
            .Subscribe(MethodModifyingCollection);

在将代码移至RTM之前,代码正在运行。我还尝试删除ObserveOn并在Assert之前添加await Task.Delay()但没有成功。

2 个答案:

答案 0 :(得分:3)

史蒂文得到了正确的答案,但有一些RxUI特定的东西丢失了。这肯定与测试运行器中的调度有关,但原因是ReactiveUI的WinRT版本无法正确检测到它是否在测试运行器中。

现在的愚蠢解决方法是将其设置在所有测试的顶部:

RxApp.DeferredScheduler = Scheduler.CurrentThread;

对每个测试使用TestScheduler,它是过度的,实际上与某些类型的测试不兼容。 TestScheduler适用于模拟时间流逝的测试。

答案 1 :(得分:1)

您的问题是MSTest单元测试具有默认SynchronizationContext。因此ObserveOnReactiveAsyncCommand将封送到线程池而不是WPF上下文。这会导致竞争状态。

您的第一个也是最好的选择是Rx TestScheduler

另一种选择是await一些完成信号(确保您的测试方法为async Task,而不是async void)。

否则,如果您只需要SynchronizationContext,则可以使用AsyncContext from my AsyncEx library在自己的SynchronizationContext内执行测试。

最后,如果您有任何代码直接使用Dispatcher代替SynchronizationContext,您可以使用Async CTP下载中的WpfContext