如果你有一個可觀察的序列在一個延長的時間內發布值,實時測試可以是一個伸展。 Reactive Extension庫提供TestScheduler類型,以幫助測試這種時間依賴代碼,而不需要等待時間通過。 TestScheduler繼承VirtualScheduler并允許您在仿真時間創建,發布和訂閱序列。例如,您可以壓縮出版物,需要5天才能完成到2分鐘運行,同時保持正確的比例。您還可以采用實際上在過去發生的序列(例如,前一年的股票行情序列),并計算或訂閱該序列,就像實時推出新值一樣。 工廠方法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) }); }}您可以使用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個項目放入一個緩沖區中,并且只有當緩沖區已滿時才將它們作為另一個序列發送出去。最后,這被交給Subscribe運算符。數據沿著所有這些中間序列傳播,直到它們被推送到觀察者。以相同的方式,訂閱以與源序列相反的方向傳播。通過在這樣的傳播過程中插入Do操作符,您可以對這種數據流進行“間諜”,就像在.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語句將相同的值投影到其源。 然后,您可以在返回語句行設置斷點,并在查找值時檢查值
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();在此示例中,斷點設置在返回y線。 當調試到程序中時,y變量顯示在Locals窗口中,您可以檢查其總數(5)。 如果您展開y,您還可以檢查列表中的每個項目,包括其值和類型。 或者,您可以將lambda表達式轉換為語句lambda表達式,格式代碼,以便語句在其自己的行上,然后設置斷點。 完成調試后,可以刪除任何Do和Select調用。
新聞熱點
疑難解答