共用方式為


測試和偵錯可觀察序列

測試 Rx 應用程式

如果您有一個可觀察的序列,它會在一段長時間內發佈值,則即時測試它可以是延展性。 「反應延伸模組」程式庫提供 TestScheduler 類型,以協助測試這種與時間相關的程式碼,而不需要實際等待時間通過。 TestScheduler 會繼承 VirtualScheduler,並可讓您建立、發佈及訂閱模擬時間中的序列。 例如,您可以壓縮需要 5 天才能完成的出版物,以執行 2 分鐘,同時維持正確的縮放比例。 您也可以擷取過去 (實際發生的序列,例如,過去一年的股票刻度序列) ,並計算或訂閱它,就像是即時推送新的值一樣。

Factory 方法 Start 會執行所有排程的工作,直到佇列是空的,或者您可以指定一個時間,讓排入佇列的工作只執行到指定的時間。

下列範例會建立具有指定 OnNext 通知的熱可觀察序列。 然後,它會啟動測試排程器,並指定何時訂閱和處置熱可觀察序列。 Start 方法會傳回 ITestableObserver 的實例,其中包含會記錄清單中所有通知的 Messages 屬性。

序列完成之後,我們會使用 ReactiveAssert.AreElementEqual 方法來比較 Messages 屬性,以及預期的值清單,以查看兩者是否與相同數目的專案相同 (,且專案相同且順序相同) 。 如此一來,我們可以確認我們確實收到預期的通知。 在我們的範例中,因為我們只開始訂閱 150,所以會遺漏值 abc 。 不過,當我們比較到目前為止收到的值 400 時,我們注意到我們實際上在訂閱序列之後收到所有已發佈的值。 此外,我們也確認 OnCompleted 在 500 正確時間引發通知。 此外,訂閱資訊也會由 CreateHotObservable 方法傳回的 ITestableObservable 類型擷取。

同樣地,您可以使用 ReactiveAssert.AreElementsEqual 來確認訂用帳戶確實在預期時間發生。

using System;
using System.Reactive;
using System.Reactive.Linq;
using Microsoft.Reactive.Testing;

class Program : ReactiveTest
{
    static void Main(string[] args)
    {
        var scheduler = new TestScheduler();

        var input = scheduler.CreateHotObservable(
            OnNext(100, "abc"),
            OnNext(200, "def"),
            OnNext(250, "ghi"),
            OnNext(300, "pqr"),
            OnNext(450, "xyz"),
            OnCompleted<string>(500)
            );

        var results = scheduler.Start(
            () => input.Buffer(() => input.Throttle(TimeSpan.FromTicks(100), scheduler))
                       .Select(b => string.Join(",", b)),
            created: 50,
            subscribed: 150,
            disposed: 600);

        ReactiveAssert.AreElementsEqual(results.Messages, new Recorded<Notification<string>>[] {
                OnNext(400, "def,ghi,pqr"),
                OnNext(500, "xyz"),
                OnCompleted<string>(500)
            });

        ReactiveAssert.AreElementsEqual(input.Subscriptions, new Subscription[] {
                Subscribe(150, 500),
                Subscribe(150, 400),
                Subscribe(400, 500)
            });
    }
}

對 Rx 應用程式進行偵錯

您可以使用 Do 運算子來偵錯 Rx 應用程式。 Do 運算子可讓您指定要針對可觀察序列的每個專案採取的各種動作 (,例如列印或記錄專案等) 。 當您鏈結許多運算子,而且想要知道每個層級產生的值時,這特別有用。

在下列範例中,我們將重複使用 Buffer 範例,以每秒產生整數,同時將它們放入可保留 5 個專案的緩衝區中。 在 使用 LINQ 運算子查詢可觀察序列 主題的原始範例中,我們只會訂閱緩衝區已滿 (,以及在緩衝區已清空之前,只訂閱最終的 Observable (IList <>) ) 序列。 不過,在此範例中,我們會使用 Do 運算子,在原始序列推送值時列印出值, (每秒一個整數) 。 當緩衝區已滿時,我們會使用 Do 運算子來列印狀態,然後再將這全部交接為觀察者訂閱的最後序列。

var seq1 = Observable.Interval(TimeSpan.FromSeconds(1))
           .Do(x => Console.WriteLine(x.ToString()))
           .Buffer(5)
           .Do(x => Console.WriteLine("buffer is full"))
           .Subscribe(x => Console.WriteLine("Sum of the buffer is " + x.Sum()));
Console.ReadKey();

如您在此範例中所見,訂用帳戶位於一系列鏈結可觀察序列的收件者端。 首先,我們會使用 Interval 運算子,建立以第二個分隔的可觀察整數序列。 然後,我們會使用 Buffer 運算子將 5 個專案放入緩衝區中,並只在緩衝區已滿時將其傳送為另一個序列。 最後,這會交接給訂閱運算子。 資料會向下傳播所有這些中繼序列,直到推送至觀察者為止。 同樣地,訂用帳戶會以反向方向傳播至來源序列。 藉由在這類傳播中間插入 Do 運算子,您可以在這類資料流程上「spy」,就像在 .NET 中使用 Console.WriteLine 或 C 中的 printf () 來執行偵錯一樣。

您也可以使用 Timestamp 運算子來驗證專案由可觀察序列推出的時間。 這可協助您針對以時間為基礎的作業進行疑難排解,以確保正確性。 回想一下下列範例,從 建立和訂閱簡單觀察序列 主題中,我們將 Timestamp 運算子鏈結至查詢,讓來源序列所推送的每個值都會在發佈時附加。 如此一來,當我們訂閱此來源序列時,我們可以同時接收其值和時間戳記。

Console.WriteLine(“Current Time: “ + DateTime.Now);

var source = Observable.Timer(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(1))
                       .Timestamp();
using (source.Subscribe(x => Console.WriteLine("{0}: {1}", x.Value, x.Timestamp)))
      {
           Console.WriteLine("Press any key to unsubscribe");
           Console.ReadKey();
      }
Console.WriteLine("Press any key to exit");
Console.ReadKey();

輸出類似如下:

Current Time: 5/31/2011 5:35:08 PM

Press any key to unsubscribe

0: 5/31/2011 5:35:13 PM -07:00

1: 5/31/2011 5:35:14 PM -07:00

2: 5/31/2011 5:35:15 PM -07:00

藉由使用 Timestamp 運算子,我們已確認第一個專案確實在序列之後 5 秒外推,且每個專案稍後都會發佈 1 秒。

此外,您也可以在 Lambda 運算式內設定中斷點,以協助偵錯。 一般而言,您只能為整個查詢設定中斷點,而不需要擷取特定值來查看它。 若要因應這項限制,您可以將 Select 運算子插入查詢中間並設定中斷點,然後在 Select 語句中,使用傳回語句在自己的行上使用 return 語句,將相同的值投射為來源。 接著,您可以在語句行設定中斷點 return ,並在值透過查詢時加以檢查。

var seq = Observable.Interval(TimeSpan.FromSeconds(1))
          .Do(x => Console.WriteLine(x.ToString()))
          .Buffer(5)
          .Select(y => { 
                  return y; }) // set a breakpoint at this line
          .Do(x => Console.WriteLine("buffer is full"))
          .Subscribe(x => Console.WriteLine("Sum of the buffer is " + x.Sum()));
Console.ReadKey();

在此範例中,中斷點是在 行中 return y 設定。 當您對程式進行偵錯時, y 變數會顯示在 [ 區域變數 ] 視窗中,而且您可以檢查其總計數 (5) 。 如果您展開 y ,您也可以檢查清單中的每個專案,包括其值和類型。

或者,您可以將 Lambda 運算式轉換成語句 Lambda 運算式、格式化程式碼,讓語句位於自己的行上,然後設定中斷點。

完成偵錯之後,您可以移除任何 Do 和 Select 呼叫。

另請參閱

概念

建立和訂閱簡單的可觀察序列
使用 LINQ 運算子查詢可觀察序列
使用排程器