RxJava Testing<二九>
在設計任何系統時,您需要保證操作的正確性,並且隨著系統在其整個生命週期內進行修改,此質量不會消退。您將設計測試,理想情況下,測試應該是自動化的。現代軟體由徹底的單元測試支援,Rx程式碼應該沒有什麼不同。
在單元測試中,我們一般會預定義一些序列值來驗證,但是對於非同步程式碼呢?比如下面的程式碼
Observable.interval(1, TimeUnit.SECONDS).take(5)
這是一個需要5秒鐘才能完成的序列。這意味著使用此序列的每個測試都需要5秒或更長時間。如果您要執行數千個測試,這根本不方便。
TestScheduler
上面的程式碼不僅耗費時間,而且在等待時實際上浪費了所有的時間。如果您可以快進時鐘,那麼幾乎可以立即評估該序列。您實際上無法快進系統的時鐘,但您可以快進虛擬時鐘。在Rx中,設計決定只通過排程程式使用時間。此決定允許您使用稱為TestScheduler的虛擬化時間的排程程式替換。
TestScheduler的排程方式與我們在[Scheduling and threading]一章中所見的排程程式相同(/Part 4 - Concurrency/1. Scheduling and threading.md))。它會安排立即或將來執行的操作。不同之處在於時間被凍結,只能根據要求進行。我們決定時間進展和多少。
advanceTimeTo
顧名思義,advanceTimeTo將執行計劃到特定時刻的所有操作。這包括在排程程式被快進時排程的動作,即由其他動作排程的動作。
輸出:
我們安排了3個任務:一個是立即執行,另外兩個是將來執行。排程程式將按計劃的時間順序同步執行在該段時間內安排的所有任務。
advanceTimeTo允許您將時間設定為任何值,包括當前時間之前的值。此實現決策可能會在測試中不必要地引入bug,因此在適用時最好使用下一個方法。
advanceTimeBy
advanceTimeBy提前相對於當前時刻的時間。在其他方面,像advanceTimeTo一樣。
輸出:
triggerActions
triggerActions不提前時間。它只執行計劃到目前為止執行的操作。
輸出:
Scheduling collisions
沒有什麼能阻止在同一時刻併發執行。當發生這種情況時,我們會發生scheduling衝突。執行兩個同時執行任務的順序與排程它們的順序相同。
輸出:
Testing
涉及非同步操作的Rx operators使用scheduler排程這些操作。如果您檢視Observable中的所有運算子,您將看到此類運算子具有scheduler的過載。這是您可以為TestScheduler補充實時排程程式的方法。
下面是一個示例,我們將測試Observable.interval的輸出與我們期望它發出的內容。
輸出:
這對於測試小的Rx程式碼片段(例如自定義運算子)非常有用。一個完整的系統可能會單獨使用schedulers,從而使我們的虛擬時間失效。Lee Campbell建議使用我們自己的提供商來抽象Rx的排程工廠(Schedulers)。在除錯模式下,我們的自定義排程程式工廠將使用TestScheduler替換所有排程程式,然後我們將使用它來控制整個系統的時間。
TestSubscriber
在上面的測試中,我們手動收集了發出的值,並將它們與我們的預期進行了比較。這個過程在測試中很常見,Rx與TestSubscriber一起打包,這將為我們做到這一點。其事件處理程式將收集收到的每個通知,並使它們可供我們檢查。使用TestSubscriber,我們之前的測試成為:
輸出:
TestSubscriber收集的不僅僅是值,而是通過以下方法露出它們:
這裡有兩件事需要注意。首先是getLastSeenThread方法。TestSubscriber檢查什麼執行緒被喚起並且記錄最新的。例如,如果要驗證GUI執行緒上是否執行了操作,那麼這將非常有用。另一個有趣的事情是,可能會有多個終止事件,這違背了我們在本指南開頭時定義序列的方式。這也是subscriber能夠收集多個終止事件的原因。
TestSubscriber為一些基本斷言:
還有一種方法可以阻止執行,直到TestSubscriber訂閱的observable終止。
如果observable未能按時完成,則等待超時將丟擲異常。
原文:https://github.com/Froussios/Intro-To-RxJava/blob/master/Part%204%20-%20Concurrency/2.%20Testing%20Rx.md