ReactiveUI - 在使用油门时测试订阅

ReactiveUI - testing subscribe when using throttle

我在尝试对使用 WhenAnyValue 侦听 属性 中的更改的视图模型进行单元测试时遇到问题,并根据新的填充列表属性 的值。由于与第 3 方软件交互,我需要使用 Throttle 来监听 属性 上的变化。

我的解决方案在生产中有效,但我的单元测试遇到了一些问题。好像跟没有让test scheduler正确推进有关,以至于throttle之后的subscription居然是运行。我已经创建了我的问题的简化版本,希望它能说明问题。

查看要测试的模型

public class ViewModel : ReactiveObject
{

    public ViewModel(IScheduler scheduler)
    {
        ListToBeFilled = new List<int>();

        this.WhenAnyValue(vm => vm.SelectedValue)
            .Throttle(TimeSpan.FromMilliseconds(500), scheduler)
            .Skip(1)
            .Subscribe(value =>
            {
                // Do a computation based on value and store result in
                // ListToBeFilled.
                ListToBeFilled = new List<int>() {1, 2, 3};
            });

    }

    private string _selectedValue;
    public string SelectedValue
    {
        get { return _selectedValue; }
        set { this.RaiseAndSetIfChanged(ref _selectedValue, value); }
    }

    public List<int> ListToBeFilled { get; set; } 
}

查看模型测试

[TestFixture]
[RequiresSTA]
public class ViewModelTests
{
    [Test]
    public void TestViewModel()
    {
        // Arrange
        (new TestScheduler()).With(scheduler =>
        {
            ViewModel vm = new ViewModel(scheduler);

            // Act
            vm.SelectedValue = "test value";
            scheduler.AdvanceByMs(1000);

            // Assert
            Assert.AreEqual(3, vm.ListToBeFilled.Count);
        });
    }
}

测试失败说 预期:3 但为 0。当 运行 在不使用 Throttle 的情况下进行测试(我需要在生产中使用它)时,测试通过。我使用的测试调度程序错了吗?我需要做什么才能消耗 Throttle

您的代码(几乎)完全正确,但您被 WhenAnyValue/Skip 行为欺骗了。

WhenAnyValue 将发布您尝试使用 Skip 跳过的初始值(空值)。但是因为 Throttle 在 TestScheduler 上是 运行,所以在有效启动调度程序 (AdvanceBy) 之前不会触发 Skip,此时 2 个更改已排队(null 和 "test value"), 但 Throttle 将删除第一个,Skip 第二个,因此您的订阅代码将永远不会被调用。

多种解决方法:

  1. 在设置测试值之前添加scheduler.AdvanceByMs(1000);(将确保传播初始值)

  2. Skip 移到 Throttle 之前(不需要调度程序,因此会立即应用)

(越晚越好,因为您的代码错误地假设它不会在视图模型创建后的 500 毫秒内获得选择,这不太可能,但也不是完全不可能)