2

私はこれを読んでいます: Virtual Time Scheduling を使用した Rx クエリのテスト

「単体テスト プロジェクトの使用」(ページの半分くらい) の部分に到達し、自分で (VS2012 と MSTest を使用して) 試しましたが、結果はドキュメントと同じではありません。具体的には、私の主張は失敗します。

ここに私のテストコードがあります:

[TestMethod]
public void TestMethod1()
{
    var scheduler = new TestScheduler();

    var xs = scheduler.CreateColdObservable(
        OnNext(10, 42),
        OnCompleted<int>(20));

    var observer1 = scheduler.CreateObserver<int>();
    scheduler.Schedule(TimeSpan.FromTicks(190), 
                       (s, t) => xs.Subscribe(observer1));

    var observer2 = scheduler.CreateObserver<int>();
    scheduler.Schedule(TimeSpan.FromTicks(220), 
                       (s, t) => xs.Subscribe(observer2));

    scheduler.Start();

    observer1.Messages.AssertEqual(
        OnNext(200, 42),
        OnCompleted<int>(210));

    observer2.Messages.AssertEqual(
        OnNext(230, 42),
        OnCompleted<int>(240));
}

私がしなければならなかった1つの変更はこれでした:

scheduler.Schedule(TimeSpan.FromTicks(190),
                   () => xs.Subscribe(observer1));

なりました:

scheduler.Schedule(TimeSpan.FromTicks(190), 
                   (s, t) => xs.Subscribe(observer1));

正直に言うと、私はこの変更の影響を把握していません (C# でのコーディングはそれほど長くありません!)。

結果は次のとおりです。

Assert.Fail failed. 
Expected: [OnNext(42)@200, OnCompleted()@210]
Actual..: [OnNext(42)@11, OnCompleted()@21]

私が理解している方法は、10 番目のティックで値 42 を返し、20 番目のティックでシーケンスが完了するコールド オブザーバブルを作成していることです。次に、このオブザーバブルにサブスクライブするオブザーバーを作成し、スケジュールをティック 190 で開始することを示します。したがって、ティック 200 (190 + 10) で値 42 をテストし、ティック 210 で完了時間をテストします。しかし、ティック 11 を取得し、それぞれ21。

このドキュメントは V2 の pre-RTM に基づいているため、TestScheduler の動作が RTM で変更されたのか、それともどこかで間違いを犯したのかはわかりません。誰かが何が起こっているのか説明していただければ幸いです。

4

1 に答える 1

9

使用したい Schedule オーバーロードが定義されている System.Reactive.Concurrency 名前空間をインポートするのを忘れたようです。これは、コードを変更する必要がある理由を説明しています-便利な拡張メソッドが表示されなかった可能性があります。

using System.Reactive.Concurrency;

使用している Schedule のオーバーロードは、TimeSpan 値を TState パラメーターとして渡す即時スケジューリングに使用されるものです。

public IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)

したがって、xs へのサブスクリプションは、スケジューラーが時間 0 で開始されるとすぐに実行されます。各作業項目はクロックをインクリメントします (単一の実行スレッドを模倣するテスト スケジューラーでイベントが同時に発生することはありません)。時間 1 で 1 つのシーケンス サブスクリプション、時間 2 で別のシーケンス サブスクリプション。

考えられる修正の 1 つは、以下を使用することです。

var observer1 = scheduler.CreateObserver<int>();
scheduler.ScheduleAbsolute(190, () => xs.Subscribe(observer1));

var observer2 = scheduler.CreateObserver<int>();
scheduler.ScheduleAbsolute(220, () => xs.Subscribe(observer2));

これらのオーバーロードを見つけるために、System.Reactive.Concurrency 名前空間を必ずインポートしてください。ここでも ScheduleRelative を使用できます。スケジューラはまだ開始されていないため、期限は現在のスケジューラのクロック値 (= 0) に指定された相対的な期間を加えたものになります。

または、DateTimeOffset または TimeSpan オーバーロードを使用して、IScheduler API サーフェスを通過することもできます。適切なオーバーロードを選択するように注意してください (選択したオーバーロードを確認するには、F12 を使用して定義に移動します)。

var observer1 = scheduler.CreateObserver<int>();
scheduler.Schedule(TimeSpan.FromTicks(190), () => xs.Subscribe(observer1));

var observer2 = scheduler.CreateObserver<int>();
scheduler.Schedule(TimeSpan.FromTicks(220), () => xs.Subscribe(observer2));

繰り返しますが、このオーバーロードを確認するには、using ディレクティブを使用して System.Reactive.Concurrency 名前空間をインポートしてください :-)。

于 2012-10-05T10:10:34.070 に答える