我有一个 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/