在Androidunit testing中模拟Retrofit Observable <T>响应

我有一个API接口,我正在testing涉及networking调用的View

 @Config(emulateSdk = 18) public class SampleViewTest extends RobolectricTestBase { ServiceApi apiMock; @Inject SampleView fixture; @Override public void setUp() { super.setUp(); //injection is performed in super apiMock = mock(ServiceApi.class); fixture = new SampleView(activity); fixture.setApi(apiMock); } @Test public void testSampleViewCallback() { when(apiMock.requestA()).thenReturn(Observable.from(new ResponseA()); when(apiMock.requestB()).thenReturn(Observable.from(new ResponseB()); AtomicReference<Object> testResult = new AtomicReference<>(); fixture.updateView(new Callback() { @Override public void onSuccess(Object result) { testResult.set(result); } @Override public void onError(Throwable error) { throw new RuntimeException(error); } }); verify(apiMock, times(1)).requestA(); verify(apiMock, times(1)).requestB(); assertNotNull(testResult.get()); } } 

出于某种原因, apiMock方法永远不会被调用,validation总是失败。

在我看来,我打电话给我这样的API

 apiV2.requestA() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer()); 

我在这里错过了什么?

更新#1:
经过一番调查,似乎在我的实现(上面的示例)时,我observeOn(AndroidSchedulers.mainThread())订阅服务器没有被调用。 仍然不知道为什么。

更新#2:
订阅时就像apiV2.requestA().subscribe(new Observer()); 一切工作正常 – 模拟API被称为和testing通过。
推进ShadowLooper.idleMainLooper(5000)什么也没做。 甚至从HandlerThreadScheduler处理程序中抓取HandlerThreadScheduler并将其提前。 同样的结果。

更新#3:添加使用API​​的实际代码。

 public void updateView(final Callback) { Observable.zip(wrapObservable(api.requestA()), wrapObservable(api.requestB()), new Func2<ResponseA, ResponseB, Object>() { @Override public Object call(ResponseA responseA, ResponseB responseB) { return mergeBothResponses(responseA, responseB); } } ).subscribe(new EndlessObserver<Object>() { @Override public void onError(Throwable e) { Log.e(e); listener.onError(e); } @Override public void onNext(Object config) { Log.d("Configuration updated [%s]", config.toString()); listener.onSuccess(config); } }); } protected <T> Observable<T> wrapObservable(Observable<T> observable) { return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); } 

Related of "在Androidunit testing中模拟Retrofit Observable <T>响应"

我仍然围绕如何正确使用rxjava我自己的头,但我会尝试修改您的代码,以便您只观察最终压缩的ObservableOn(mainThread),而不是在原始请求响应的Observable上这样做。 然后,我会validation这是否影响到事实,你必须提前两个活套。

为了简单地进行testing,并消除Looper闲置的需要,我将采用线程的方法,因为运行testing时不需要后台处理。 你可以通过注入你的调度器而不是静态地创build它们。 在运行你的生产代码时,你需要注入AndroidSchedulers.mainThread和Schedulers.io,当运行testing代码时,你可以注入Schedulers.immediate(如果适用)。

 @Inject @UIScheduler /* Inject Schedulers.immediate for tests and AndroidSchedulers.mainThread for production code */ private Scheduler mainThreadSched; @Inject @IOScheduler /* Inject Scheduler.immediate for tests and Schedulers.io for production code */ private Scheduler ioSched; public void updateView(final Callback) { Observable.zip(wrapObservable(api.requestA()), wrapObservable(api.requestB()), new Func2<ResponseA, ResponseB, Object>() { @Override public Object call(ResponseA responseA, ResponseB responseB) { return mergeBothResponses(responseA, responseB); } } ).observeOn(mainThreadSched) .subscribe(new EndlessObserver<Object>() { @Override public void onError(Throwable e) { Log.e(e); listener.onError(e); } @Override public void onNext(Object config) { Log.d("Configuration updated [%s]", config.toString()); listener.onSuccess(config); } }); } protected <T> Observable<T> wrapObservable(Observable<T> observable) { return observable.subscribeOn(ioSched); } 

你使用的是什么版本的rxjava? 我知道0.18版本的ExecutorScheduler有一些变化。 在使用0.18.3时,我遇到了类似的问题,因为我的订阅将会提前退订,我不会收到onComplete消息。 我提到这个给你的唯一原因是在0.19.0修复了我的问题。

不幸的是,我不能真正解释什么是固定的细节,这是超出我的理解,但如果事实certificate是相同的原因,也许有更多的人理解可以解释。 以下是我正在谈论的有关https://github.com/Netflix/RxJava/issues/1219的链接&#x3002;

这不是一个很好的答案,但更多的是提醒,以免它可以帮助你。

正如@ champ016所述,RxJava版本的版本低于0.19.0

当使用0.19.0 ,以下方法起作用。 虽然还是不明白为什么我必须推进两个弯腰。

 @Test public void testSampleViewCallback() { when(apiMock.requestA()).thenReturn(Observable.from(new ResponseA()); when(apiMock.requestB()).thenReturn(Observable.from(new ResponseB()); AtomicReference<Object> testResult = new AtomicReference<>(); fixture.updateView(new Callback() { @Override public void onSuccess(Object result) { testResult.set(result); } @Override public void onError(Throwable error) { throw new RuntimeException(error); } }); ShadowLooper.idleMainLooper(5000); Robolectric.shadowOf( Reflection.field("handler") .ofType(Handler.class) .in(AndroidSchedulers.mainThread()) .get().getLooper()) .idle(5000); verify(apiMock, times(1)).requestA(); verify(apiMock, times(1)).requestB(); assertNotNull(testResult.get()); }