Testing ReactiveCommand and ReactiveObject ViewModels



我在测试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不为null并且有项。

    [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,但我不知道为什么。我的问题是:

  • 我该如何通过考试
  • 我应该在命令上测试CanExecute吗
  • 我应该使用ToPropery和ObservableAsPropertyHelper,而不是CanExecute的公共IOobservable吗

更新1

根据下面的建议,我将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);
        ...
        }
    }

更新2

将测试更新为awaitCommandThatDoesStuff会导致测试运行程序永远不会返回。

    [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());
         });
    }

WhenAnyValue不适用于ObservableCollection

最好使用ReactiveUI附带的ReactiveList并观察CountChanged属性。

首先,因为您使用的是.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

相关内容

  • 没有找到相关文章

最新更新