2015-04-17 31 views
6

我正在开发和Android应用程序。我使用改进(与OkClient)的API请求和Robolectric进行测试。我的API看起来是这样的:Robolectric + rxJava +翻新第二次调用抛出java.io.InterruptedIOException

@GET("/v1/book/{bookId}") Observable<Book> getBook(@Path("bookId") int bookId); 

只是为Robolectric我强迫api调用是同步的。该restAdapter建设者看起来是这样的:

RestAdapter.Builder builder = new RestAdapter.Builder().setEndpoint(environment.getServerEndpoint()) 
         .setClient(new OkClient(client)) 
         .setExecutors(new ImmediateExecutor(), null) 
         .setErrorHandler(new ErrorHandler()) 
         .setRequestInterceptor(new RequestInterceptor() { 
          @Override 
          public void intercept(RequestFacade request) { 
           // Always ask for JSON data 
           request.addHeader("Accept", "application/json"); 
           request.addHeader("Content-Type", "application/json");    
          } 
         }); 

public class ImmediateExecutor implements Executor { 

     @Override public void execute(Runnable command) { 
      command.run(); 
     } 
    } 

我有一个简单的测试,看起来像这样:

API.getBook(1).subscribe(); 
API.getBook(2).subscribe(); 

Restadapter与制造商创建的,它的API对象(restadapter.create(。 ..))。我忽略了它,因为它是微不足道的。

的第一个作品没有问题,但第二个应该是相同抛出异常:

java.io.InterruptedIOException 
    at okio.Timeout.throwIfReached(Timeout.java:146) 
    at okio.Okio$1.write(Okio.java:75) 
    at okio.AsyncTimeout$1.write(AsyncTimeout.java:155) 
    at okio.RealBufferedSink.flush(RealBufferedSink.java:201) 
    at com.squareup.okhttp.internal.http.HttpConnection.flush(HttpConnection.java:140) 
    at com.squareup.okhttp.internal.http.HttpTransport.finishRequest(HttpTransport.java:52) 
    at com.squareup.okhttp.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:828) 
    at com.squareup.okhttp.internal.http.HttpEngine.access$200(HttpEngine.java:95) 
    at com.squareup.okhttp.internal.http.HttpEngine$NetworkInterceptorChain.proceed(HttpEngine.java:823) 
    at com.carmacarpool.carmaridepool.rest.CarmaHttpClientFactory$NetworkLoggingInterceptor.intercept(CarmaHttpClientFactory.java:77) 
    at com.squareup.okhttp.internal.http.HttpEngine$NetworkInterceptorChain.proceed(HttpEngine.java:803) 
    at com.squareup.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.java:684) 
    at com.squareup.okhttp.Call.getResponse(Call.java:272) 
    at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:228) 
    at com.carmacarpool.carmaridepool.rest.CarmaHttpClientFactory$LoggingInterceptor.intercept(CarmaHttpClientFactory.java:53) 
    at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:225) 
    at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:199) 
    at com.squareup.okhttp.Call.execute(Call.java:79) 
    at retrofit.client.OkClient.execute(OkClient.java:53) 
    at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:326) 
    at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220) 
    at retrofit.RestAdapter$RestHandler$1.invoke(RestAdapter.java:265) 
    at retrofit.RxSupport$2.run(RxSupport.java:55) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:262) 
    at com.carmacarpool.carmaridepool.testutils.ShadowUICarmaRESTClassFactory$ImmediateExecutor.execute(ShadowUICarmaRESTClassFactory.java:91) 
    at retrofit.RxSupport$1.call(RxSupport.java:42) 
    at retrofit.RxSupport$1.call(RxSupport.java:32) 
    at rx.Observable.subscribe(Observable.java:7393) 
    at rx.Observable.subscribe(Observable.java:7083) 
    at com.carmacarpool.carmaridepool.CorridorTest.test(CorridorTest.java:99) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) 
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:265) 
    at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:205) 
    at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:173) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86) 
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49) 
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:64) 
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:50) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35) 
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) 
    at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32) 
    at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93) 
    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source) 
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:106) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35) 
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) 
    at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:360) 
    at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    at java.lang.Thread.run(Thread.java:745) 

我有一个网络拦截器只是一个日志,它工作正常。我有权访问服务器日志,并且请求甚至没有到达服务器。

有没有人有任何线索可能是什么问题?这似乎是因为某种未知的原因导致线程被杀害?

谢谢。

编辑:如果在onNext函数(订阅的第一个参数),我执行第二个请求,然后它的工作。如预期一切都是同步的。

解决方案 经过多次尝试,我可以找到解决方案。这个问题似乎来自Okio。显然有一个缓冲区写回应(或类似的东西,我几个星期前解决了它,但我不记得100%)。这个缓冲区在第二个请求的中间被关闭,这就是导致错误的原因。

要解决此问题,我所做的是将请求包装在try/catch块中。如果发生IOException,那么我重试。我最多重试5次(以避免无限循环)。

代码看起来像:

try { 
     // Perform the request 
     return chain.proceed(request); 
    } catch (IOException e) { 

     // Retry again if we haven't tried at least REQUEST_RETRIES times 
     if (iteration < REQUEST_RETRIES) { 
      return performRequest(chain, ++iteration); 
     } 

     // Otherwise, save the exception and throw it later 
     exception = e; 
    } 

链对象来自一个OkHttpClient拦截:

OkHttpClient客户=新OkHttpClient(); client.interceptors()。add(new CustomInterceptor());

私有类CustomInterceptor实现拦截器@覆盖 公开回应拦截(连锁链)抛出IOException异常{...

希望这是有帮助的。

+2

关于您的测试只需两美分 - 为什么不测试没有真正的网络? –

+0

这也可以帮助 - https://groups.google.com/forum/#!topic/robolectric/-HVhS3rnU54 –

回答

2

我认为你在测试过程中做了太多的事情来让observables同步运行。相反,所有你需要做的是在你的测试中

Book book = retrofitAPI.getBook(someId).toBlocking.first() 

这将执行observable同步。 Rx库中我最喜欢的部分之一。

+0

这对我不起作用,因为在我的测试中,我创建了一个活动,这是活动的人调用执行请求的服务。所以我不能做到阻塞()。first()。当我测试服务本身时,我正在做这件事。 –

相关问题