[英]RxJava: How to unit test that an Observable is observed on and subscribed on the right scheduler?
[英]Unit Test - Verify Observable is subscribed
我有這樣的java代碼
mDataManager.getObservable("hello").subscribe( subscriber );
我想verify
以下Observable是.subscribe()
我試圖模擬getObservable()
並verify
Observable<Response> res = mock(Observable.class);
when(mDataManager.getObservable("hello")).thenReturn(res);
verify(res).subscribe();
但是有一個錯誤
Caused by: java.lang.IllegalStateException: onSubscribe function can not be null.
at rx.Observable.subscribe(Observable.java:8167)
at rx.Observable.subscribe(Observable.java:8158)
at rx.Observable.subscribe(Observable.java:7962)
....
Caused by: rx.exceptions.OnErrorThrowable$OnNextValue: OnError while emitting onNext value: omni.neo.hk.omniapiservice.v4.model.external.UserLoginBean.class
at rx.exceptions.OnErrorThrowable.addValueAsLastCause(OnErrorThrowable.java:109)
at rx.exceptions.Exceptions.throwOrReport(Exceptions.java:187)
at rx.internal.operators.OperatorDoOnEach$1.onNext(OperatorDoOnEach.java:82)
... 48 more
我認為這里不可能mock
一個Observable,但沒有一個mock
的Observable我不能做verify(res).subscribe()
在這種情況下的任何建議?
我發現RxJava提供了一個名為TestSubject
的類
你可以像這樣創建它
private TestScheduler eventsScheduler = new TestScheduler();
private TestSubject<MyEvent> eventObservable = TestSubject.create(eventsScheduler);
這將為您提供返回布爾值的方法hasObservers()
。
@Test
public void testSubscription(){
myTestClass.init(eventObservable);
assertTrue(eventObservable.hasObservers());
}
此外,TestSubject還可以讓您在發送事件時獲得完美的時間。
eventObservable.onNext(new MyEvent());
eventsScheduler.triggerActions();
也許您可以將Observable.onSubscribe
方法與RunTestOnContext
規則一起使用? TestContext
可以為您提供Async
對象,只有在完成后才會終止測試。 我認為,如果將它與Observable#doOnSubscribe
結合使用,您可以實現所需的行為。
但是,使用Async
有時可能會有點混亂。 在下面的示例中,如果從未訂閱observable,則永遠不會評估doOnSubscribe
函數,並且您的測試不會終止。
例:
@RunWith(VertxUnitRunner.class)
public class SubscriptionTest {
@Rule
public RunTestOnContext vertxRule = new RunTestOnContext();
@Test
public void observableMustBeSubscribed(final TestContext context) {
final Async async = context.async();
final Observable<String> observable = Observable.just("hello").doOnSubscribe(async::complete);
final Manager mock = mock(Manager.class);
when(mock.getObservable()).thenReturn(observable);
mock.getObservable().subscribe();
}
interface Manager {
Observable<String> getObservable();
}
}
我不確定我是在回答這個被問到的問題,但我想是的......
可以創建單元測試,以檢查是否已對可觀察的訂閱進行了訂閱。 請注意,在RxJava 1.x中,TestSubject支持此功能,但Subject實現可以促進該功能。 針對RxJava 2刪除了TestSubject 。
不要試圖像原始海報那樣試圖模仿observable,而是使用PublishSubject,運行業務邏輯,然后使用發布主題查看是否正在觀察Observable。 下面是一些驗證此測試的測試代碼。 測試在我運行時通過。
有關代碼的說明,請參閱代碼注釋。 就個人而言,這個測試似乎是其他測試的冗余,可以驗證控制器如何處理數據。 如果控制器從未訂閱並從數據服務接收數據,那么其他測試將失敗。 另一方面,測試取消訂閱有助於避免內存泄漏,這可能是很高的價值。
import org.junit.Test;
import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import io.reactivex.subjects.PublishSubject;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
/**
* Tests whether it is possible to test whether a controller properly unsubscribes from an Observable.
*/
public class SubscribeUnsubscribeTests {
/**
* A service that returns a stream of strings.
*/
interface StringService {
Observable<String> getStrings();
}
/**
* A controller that requests strings from the {@link StringService} and logs them
* to system out as they are received.
*/
class StringLoggingController {
private StringService stringService;
private Disposable stringSubscriptionDisposable;
public StringLoggingController(StringService stringService) {
this.stringService = stringService;
}
/**
* Causese the controller to begin strings request and logging.
*/
public void start() {
stringSubscriptionDisposable = stringService.getStrings()
.subscribe(string -> System.out.print(string));
}
public void stop() {
if (stringSubscriptionDisposable != null) {
if (!stringSubscriptionDisposable.isDisposed()) {
stringSubscriptionDisposable.dispose();
stringSubscriptionDisposable = null;
}
}
}
}
/**
* A {@link StringService} that can report whether {@link StringService#getStrings()}
* has observers.
*/
class ReportIsSubscribedStringService implements StringService {
private PublishSubject<String> publishSubject = PublishSubject.create();
public Observable<String> getStrings() {
return publishSubject;
}
/**
* @return true if the {@link #getStrings()} observable has observers.
*/
public boolean stringsAreBeingObserved() {
return publishSubject.hasObservers();
}
}
/**
* Verifies that the {@link StringLoggingController} is subscribing to the service.
*/
@Test
public void stringsLoggingControllerSubscribesToStringService() {
ReportIsSubscribedStringService service = new ReportIsSubscribedStringService();
StringLoggingController controller = new StringLoggingController(service);
controller.start();
assertTrue(service.stringsAreBeingObserved());
}
/**
* Verifies that the {@link StringLoggingController} is unsubscribing from the service.
*/
@Test
public void stringsLoggingControllerUnsubscribesFromStringService() {
ReportIsSubscribedStringService service = new ReportIsSubscribedStringService();
StringLoggingController controller = new StringLoggingController(service);
controller.start();
controller.stop();
assertFalse(service.stringsAreBeingObserved());
}
}
- 編輯 - 我之前寫過,我無法測試取消訂閱。 我確實弄清楚如何測試。 事實證明我的測試失敗了,因為測試的代碼沒有正確取消訂閱(哈哈 - 測試工作,去圖)。 我已經更新了上面的代碼,以說明測試訂閱和取消訂閱。
我今天花了幾個小時意識到這是一個愚蠢的錯誤。 如果您使用的是PowerMockito,請檢查您的@PrepareForTest。
@PrepareForTest({Observable.class})
也別忘了嘲笑它。 我是在@before上做的:
PowerMockito.mockStatic(Observable.class);
我希望它可以提供幫助。 謝謝
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.