C# 订阅属性上的TestScheduler未按预期工作(w)

C# 订阅属性上的TestScheduler未按预期工作(w),c#,system.reactive,reactive-programming,reactiveui,C#,System.reactive,Reactive Programming,Reactiveui,我对rx/ReactiveUi非常熟悉,希望使用TestScheduler编写一个xunit测试,以检查检索搜索建议的节流阀是否正常工作 其思想是使用TestScheudler进行计时,更改search term属性的值,并检查是否调用了异步方法。不幸的是,该方法没有在预期的位置调用,请参阅所附代码,尤其是单元测试 我错过了什么?我试着用这种方法来测试这一点是不是一个好方法 我的视图模型: 我的单元测试xunit: Throttle没有设置调度程序,而是编写Throttletimespan,Rx

我对rx/ReactiveUi非常熟悉,希望使用TestScheduler编写一个xunit测试,以检查检索搜索建议的节流阀是否正常工作

其思想是使用TestScheudler进行计时,更改search term属性的值,并检查是否调用了异步方法。不幸的是,该方法没有在预期的位置调用,请参阅所附代码,尤其是单元测试

我错过了什么?我试着用这种方法来测试这一点是不是一个好方法

我的视图模型:

我的单元测试xunit:


Throttle没有设置调度程序,而是编写Throttletimespan,RxApp.MainThreadScheduler

我可能在这里遗漏了一些东西-但我只是看看-根据评论,MainThreadScheduler相当于DispatcherScheduler-您希望在那里运行一个Throttle吗?也许RxApp.TaskpoolScheduler后面跟一个ObserveOnRxApp.MainThreadScheduler或者任何惯用的ReactiveUI都是可取的?不,DispatchersScheduler比TaskpoolScheduler更能有效地将计时器调度到—前者只需要将一个项目添加到列表中,后者需要创建实时计时器。想想看——只要应用程序还在运行,调度程序就会一直运行——它所要做的就是检查当前时间,并将其与优先级队列的首要项进行比较。你知道吗,我不知道我在想什么,你当然完全正确。事实上我有点尴尬。删除我的评论并销毁证据很有诱惑力,但那不行!也许圣诞节该放下键盘了!大家好,Paul.Hmmm,环顾四周,令人惊讶的是,在这种情况下,没有太多的示例为节流阀指定调度器,而且通常是在可测试性而不是效率的上下文中。当然,对于WPF,它将默认为平台默认值,而不是调度程序。很高兴这个问题出现了,因为我现在将对此保持警惕!
public class MyViewModel : ReactiveObject
{
    public MyViewModel (IMyQueryHandler queryHandler)            
    {
        ...
        // Type suggestions
        this.SearchTerms = this.ObservableForProperty(x => x.SearchTerm)
            .Throttle(SuggestionThrottle).Value();

        this.SearchTerms.Subscribe(this.LoadSearchSuggestionsAsync);
        ...
    }

    internal async void LoadSearchSuggestionsAsync(string search)
    { 
        ... 
    this.SearchSuggestions = this.queryHandler.ExecuteQuery(...);
        ...
    }       

    public IList<SearchSuggestion> SearchSuggestions
    {
        get { return this.searchSuggestions; }
        set { this.RaiseAndSetIfChanged(ref this.searchSuggestions, value); }
    }

    ...
} 
...

public class TestFixture : ReactiveObject
{
    public string SearchTerms { get { return this._searchTermsBackingField.Value; } }
    public ObservableAsPropertyHelper<string> _searchTermsBackingField;
}

[Fact]
public void WillTryToLoadSearchSuggestionsAfterThrottleTime()
{
    new TestScheduler().With(
        sched =>
        {                    
            var fixture = new TestFixture();
            var queryClient = Substitute.For<IMyQueryHandler>();

            var caseSuggestions = new List<...> { ... }

            queryClient.ExecuteQuery<...>(...).ReturnsForAnyArgs(...);  // Nsubstitute

            var vm = new MyViewModel(queryClient);

            vm.SearchTerms.ToProperty(fixture, p => p.SearchTerms, out fixture._searchTermsBackingField);

            sched.Schedule(() => vm.SearchTerm = "Tes");
            sched.Schedule(MyViewModel.SuggestionThrottle, () => vm.SearchTerm = "Test");

            sched.AdvanceBy(MyViewModel.SuggestionThrottle.Ticks);
            sched.AdvanceBy(1);

            // why is the method MyViewModel.LoadSearchSuggestionsAsync not called here (in debug)???

            sched.AdvanceBy(1);
         }  // method gets called here...
 }
 ...