android - Android 单元测试中的模拟改造 Observable<T> 响应

标签 android unit-testing mockito robolectric retrofit

我有一个 API 接口(interface),我正在测试一个涉及网络调用的 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());

我在这里错过了什么?

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

更新 #2:
当像 apiV2.requestA().subscribe(new Observer()); 那样订阅时,一切正常 - 调用模拟 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,但我会尝试修改您的代码,以便您仅在最终压缩的 Observable 上观察 On(mainThread),而不是在两个原始请求响应的 Observable 上都这样做.然后我会验证这是否会影响您必须推进两个 Loopers 的事实。

为了简化您的测试并消除对 Looper 空闲的需要,我将把线程排除在等式之外,因为您在运行测试时不需要后台处理。您可以通过注入(inject)调度程序而不是静态创建它们来做到这一点。在运行生产代码时,您将注入(inject) AndroidSchedulers.mainThread 和 Schedulers.io,在运行测试代码时,您将在适用的情况下注入(inject) 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);
}

关于android - Android 单元测试中的模拟改造 Observable<T> 响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24041294/

相关文章:

android - 在 Codenamone 中集成 Android 代码

android - 单击刷新按钮刷新 Activity 内容

java - 如何验证调用了非模拟对象的方法?

android - 使用 LiveData、协程和 MockK 测试多个 View 状态的 ViewModel 单元

scala - 如何在 Scala 测试中将模拟调用与通配符匹配?

java - 方法返回字符串的 Mockito 测试

android - 单元测试中的 Sugar orm 产生了空指针异常

android - 在 android 的 AsyncTask 类中使用 sqlite 时出错?

unit-testing - 测试时模拟 Gradle 插件使用的类

java - 在Java中,如何使用断言测试Junit Mockito中的void方法?