c# - ReactiveUI - 使用 throttle 时测试订阅

标签 c# reactiveui

我在尝试对使用 WhenAnyValue 监听属性更改并根据属性的新值填充列表的 View 模型进行单元测试时遇到问题。由于与 3'rd 方软件的交互,我在监听属性变化时需要使用 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);
        });
    }
}

测试失败,说 Expected: 3 But was 0. 在不使用 Throttle 的情况下运行测试时(我需要在生产中使用它),测试通过。我使用的测试调度程序错误吗?我需要做什么才能消耗 Throttle?

最佳答案

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

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

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

  • 添加 scheduler.AdvanceByMs(1000);在设置测试值之前(将确保初始值得到传播)
  • 搬家 Skip之前Throttle (不需要调度程序,因此将立即应用)

  • (后者可能更好,因为您的代码错误地假设它不会在 View 模型创建后的 500 毫秒内获得选择,这不太可能,但也并非完全不可能)

    关于c# - ReactiveUI - 使用 throttle 时测试订阅,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33215683/

    相关文章:

    c# - 在后面的代码中访问 ascx 参数

    c# - ReactiveCommand IsExecuting 在第一次发出值后更改为 false

    c# - 我应该如何过滤绑定(bind)到网格的 IReactiveList?

    mvvm - ReactiveUI RaiseAndSetIfChanged 在文本框失去焦点时命中

    c# - 响应式UI 6:如何在版本6中实现与版本4相同的功能

    c# - 为什么 Entity Framework 核心加载实体的关系而不添加包含

    c# - 应用程序启动检查,我应该在 MVVM 模式中在哪里执行它们?

    c# - Math.Sin 给了我奇怪的值

    c# - 如何将 Enumerable.ToList<>() 反序列化为 List<>

    reactiveui - 使用 ReactiveUI 进行 Xaml 绑定(bind)时避免绑定(bind)错误