ReactiveUI - 使用节流时测试订阅

时间:2015-10-19 13:27:00

标签: c# reactiveui

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

我的解决方案适用于生产,但我的单元测试遇到了一些问题。这似乎与不让测试调度程序正确前进有关,因此实际运行了节流之后的订阅。我已经创建了我的问题的简化版本,我希望这是一个说明性的。

查看要测试的模型

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 ,我需要做什么?

1 个答案:

答案 0 :(得分:4)

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

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

解决这个问题的方法很多:

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

  2. Skip之前移动Throttle(不需要调度程序,因此会立即申请)

  3. (后者可能更好,因为你的代码错误地认为它在创建视图模型后的500ms内不会得到选择,这不太可能,但也不是完全不可能的)