<T> 模拟改造 Android 单元测试中的可观察响应



我有一个API接口,我正在测试一个涉及网络调用的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方法永远不会被调用,验证总是失败。

在我看来,我是这样调用api的

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

我在这里错过了什么?

Update # 1:
经过一些调查,在我的实现(上面的示例)中,似乎没有调用observeOn(AndroidSchedulers.mainThread())订阅者。还是不知道为什么。

更新# 2:
当订阅时,就像apiV2.requestA().subscribe(new Observer());一样,一切都工作得很好——mock api被调用,测试通过。
推进ShadowLooper.idleMainLooper(5000)没有任何作用。甚至在HandlerThreadScheduler中从处理程序中抓取了looper并推进了它。相同的结果。

更新# 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());
}

我仍然在思考如何正确使用rxjava,但我会尝试修改你的代码,以便你只在最终压缩的可观察对象上观察到(mainThread),而不是在原始请求响应的可观察对象上做它。然后我将验证这是否会影响你必须推进两个循环器的事实。

为了简化您的测试并消除对loop空闲的需要,我将把线程从等式中去掉,因为您在运行测试时不需要后台处理。可以通过注入调度器而不是静态地创建调度器来实现这一点。当运行你的产品代码时,你会有AndroidSchedulers。主线程和调度程序。当运行测试代码时,您将注入调度器。立即执行

@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的修复修复了我的问题。

不幸的是,我不能真正解释什么是固定的细节,这超出了我的理解在这一点上,但如果它被证明是相同的原因也许有人更了解可以解释。这是我正在谈论的内容的链接https://github.com/Netflix/RxJava/issues/1219。

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

正如@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());
}

相关内容

  • 没有找到相关文章

最新更新