我在测试ReactiveCommands及其执行能力方面遇到了麻烦。
鉴于以下视图模型:
public class HowToTestViewModel : ReactiveObject
{
public ReactiveCommand<Unit> CommandThatDoesStuff { get; set; }
public IObservable<bool> CanExecute { get; set; }
public ObservableCollection<string> TheCollectionMustHaveItems { get; set; }
public HowToTestViewModel()
{
TheCollectionMustHaveItems = new ObservableCollection<string>();
this.CanExecute = this.WhenAnyValue(vm => vm.TheCollectionMustHaveItems)
.Do(debug => Console.WriteLine("Can Execute Value: " + debug.Count()))
.Where(col => col.Any())
.Do(debug => Console.WriteLine("Can Execute (not empty?) Value: " + debug.Count()))
.Select(x => true);
CommandThatDoesStuff = ReactiveCommand.CreateAsyncTask(this.CanExecute, async param => {
//web service or something...
await Task.Delay(1000);
});
CommandThatDoesStuff.Subscribe(next => Console.WriteLine("The command fired and no exceptions were thrown."));
CommandThatDoesStuff.ThrownExceptions.Subscribe(error => Console.WriteLine("boom. handle your business here."));
}
}
我想测试以确保命令无法执行,除非TheCollectionMustHaveItems
不为空且有项目。
[Test]
public void CanExecute_spec()
{
(new TestScheduler()).With(sched =>
{
var sut = new HowToTestViewModel();
sut.CommandThatDoesStuff.Execute(null);
sut.CommandThatDoesStuff.CanExecute(null).Should().BeFalse();
sut.TheCollectionMustHaveItems.Should().BeEmpty();
sut.TheCollectionMustHaveItems.Add("item added"); //CanExecute should update
sched.AdvanceBy(1000);
sut.CommandThatDoesStuff.CanExecute(null).Should().BeTrue();
});
}
我正在使用TestScheduler
,但我不知道为什么。我的问题是:
根据以下建议,我将ObservableCollection更改为ReactiveList,我(我想)我使用TheCollectionMustHaveItems.CountChanged
来验证CommandThatDoesStuff
是否可以执行。使用以下更新的VM和测试我得到相同的错误。
public class HowToTestViewModel : ReactiveObject
{
....
public IReactiveList<string> TheCollectionMustHaveItems { get; set; }
public HowToTestViewModel()
{
TheCollectionMustHaveItems = new ReactiveList<string>();
this.CanExecute = this
.TheCollectionMustHaveItems.CountChanged
.Do(next => Console.WriteLine("logging the next result:" + next))
.ObserveOn(RxApp.MainThreadScheduler)
.Where(collection => TheCollectionMustHaveItems.Any())
.Select(x => true);
...
}
}
将测试更新为await
CommandThatDoesStuff
会导致测试运行器永远不会返回。
[Test]
public async void CanExecute_spec()
{
await (new TestScheduler()).With(async sched =>
{
var sut = new HowToTestViewModel();
await sut.CommandThatDoesStuff.ExecuteAsyncTask(null);
sut.CommandThatDoesStuff.CanExecute(null).Should().BeFalse();
sut.TheCollectionMustHaveItems.Should().BeEmpty();
sut.TheCollectionMustHaveItems.Add("item added"); //CanExecute should update
sut.CanExecute.Subscribe(next => next.Should().BeTrue());
sched.AdvanceBy(1000);
sut.CommandThatDoesStuff.CanExecuteObservable.Subscribe(next => next.Should().BeTrue());
});
}
答案 0 :(得分:2)
WhenAnyValue
不适用于ObservableCollection
最好的办法是使用ReactiveUI附带的ReactiveList
并观察CountChanged
属性。
答案 1 :(得分:1)
首先,因为您使用.Where
后跟.Select
,所以CanExecute
只会返回true
个值。将其更改为:
this.CanExecute = this
.TheCollectionMustHaveItems.CountChanged
.Log(this, "next result") // RxUI has a nice Log extension method that can replace your previous usage of Do
.ObserveOn(RxApp.MainThreadScheduler)
.Select(count => count > 0);
其次,async
测试返回类型应为Task
,而不是void
。