com.squareup.okhttp.internal.framed.IncomingStreamHandler的ClassNotFoundException

时间:2016-01-08 08:04:33

标签: android unit-testing rx-java rx-android retrofit2

我正在为使用Reactive编程和Retrofit的类编写单元测试用例。我得到以下例外:

com.locationlabs.finder.android.core.manager.AuthManagerTest > logout_ok STANDARD_ERROR
    Jan 07, 2016 11:28:06 PM com.squareup.okhttp.mockwebserver.MockWebServer$3 execute
    INFO: MockWebServer[51867] starting to accept connections
    Jan 07, 2016 11:28:07 PM com.squareup.okhttp.mockwebserver.MockWebServer$3 execute
    WARNING: MockWebServer[51867] failed unexpectedly
    java.lang.NoClassDefFoundError: com/squareup/okhttp/internal/framed/IncomingStreamHandler
        at com.squareup.okhttp.mockwebserver.MockWebServer.serveConnection(MockWebServer.java:414)
        at com.squareup.okhttp.mockwebserver.MockWebServer.access$800(MockWebServer.java:93)
        at com.squareup.okhttp.mockwebserver.MockWebServer$3.acceptConnections(MockWebServer.java:389)
        at com.squareup.okhttp.mockwebserver.MockWebServer$3.execute(MockWebServer.java:356)
        at com.squareup.okhttp.internal.NamedRunnable.run(NamedRunnable.java:33)
        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)
    Caused by: java.lang.ClassNotFoundException: com.squareup.okhttp.internal.framed.IncomingStreamHandler
        at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
        ... 8 more

这是我的Retrofit类和Manager类。

import java.util.Map;

import retrofit.http.Body;
import retrofit.http.Headers;
import retrofit.http.POST;
import rx.Observable;

public interface AuthService {
   @POST("auth/endAuthSession")
   @Headers({"Content-Type: application/json"})
   Observable<Void> logout();
}

public class AuthManager {
   private AuthService authService;
    public AuthManager(AuthService authService) {
      this.authService = authService;
   }

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import rx.Observable;
import rx.functions.Func1;

public Observable<Void> logout() {
    return authService.logout()
            .map(new Func1<Void, Void>() {
               @Override
               public Void call(Void nothing) {
                  JsonUtil.token = null;
                  return null;
               }
            });
   }
}

以下是我的单元测试用例:

import com.ll.core.manager.AuthManager;
import com.ll.core.service.AuthService;
import retrofit.GsonConverterFactory;
import rx.Subscriber;
import rx.observers.TestSubscriber;

import junit.framework.Assert;
import com.google.gson.Gson;
import com.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.MockWebServer;
import com.squareup.okhttp.OkHttpClient;
import org.junit.Before;
import org.junit.Test;
import retrofit.JacksonConverterFactory;
import retrofit.Retrofit;
import retrofit.RxJavaCallAdapterFactory;

import java.io.IOException;
import java.lang.Override;
import java.lang.Throwable;
import java.lang.Void;
import java.net.HttpURLConnection;


/**
 * Unit test case for AuthManager.
 */
public class AuthManagerTest {
    private AuthService authService;
    private MockWebServer server;
    private Gson gson;

    @Before
    public void setup() throws IOException {
        server = new MockWebServer();
        server.start();
        Retrofit retrofit = new Retrofit
                .Builder()
                .baseUrl(server.url("/"))
                .addConverterFactory(JacksonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .client(new OkHttpClient())
                .build();

        authService = retrofit.create(AuthService.class);
    }

    @Test
    public void logout_ok(){
        //Setup resonse.
        MockResponse response = new MockResponse()
                .setResponseCode(HttpURLConnection.HTTP_OK);
        server.enqueue(response);
        AuthManager authManager = new AuthManager(authService);
        TestSubscriber sub = new TestSubscriber();
        authManager.logout().subscribe(sub);
        sub.assertCompleted();
    }
}

最初谷歌搜索表明应该包括okio库。即使在包含`okio,库之后,我仍然遇到同样的异常。这是我的gradle文件。

dependencies {
   compile group: 'com.google.android.gms', name: 'play-services-analytics', version: '8.4.0'

   // HTTP libs
   compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
   compile 'com.squareup.okhttp:okhttp:2.7.1'
   compile 'com.squareup.okhttp:logging-interceptor:2.6.0'

   // Reactive libs
   compile 'io.reactivex:rxandroid:1.1.0'
   compile 'io.reactivex:rxjava:1.1.0'
   compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2'

   // JSON libs
   compile 'com.fasterxml.jackson.core:jackson-databind:2.7.0-rc2'
   compile 'com.fasterxml.jackson.core:jackson-core:2.7.0-rc2'
   compile 'com.squareup.retrofit:converter-jackson:2.0.0-beta2'

   // DI libs
   compile group: 'com.google.dagger', name: 'dagger', version: '2.0.2'
   apt group: 'com.google.dagger', name: 'dagger-compiler', version: '2.0.2'
   provided 'org.glassfish:javax.annotation:10.0-b28'

   // DB lib
   compile 'io.realm:realm-android:0.87.1'

   // Unit testing dependencies
   testCompile 'junit:junit:4.12'
   testCompile 'com.squareup.okio:okio:1.6.0'
   testCompile 'com.squareup.okhttp:mockwebserver:2.5.0'
   testCompile 'com.squareup.retrofit:retrofit-mock:2.0.0-beta2'
   testCompile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
}

EDIT1

当我运行以下命令时:

jar -tvf ~/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp/okhttp/2.5.0/4de2b4ed3445c37ec1720a7d214712e845a24636/okhttp-2.5.0.jar

我确实在jar中看到了这个类。

  995 Tue Aug 25 21:12:54 PDT 2015 com/squareup/okhttp/internal/framed/IncomingStreamHandler$1.class
   593 Tue Aug 25 21:12:54 PDT 2015 com/squareup/okhttp/internal/framed/IncomingStreamHandler.class

我仍然困惑为什么单元测试无法找到这个类,即使它在jar文件中。它看起来像Jar地狱问题。

EDIT2 : 这确实是Jar地狱的问题。 如果您注意到上面的gradle文件,我使用的是okhttp的2.7.1版本,但mockwebser使用的是2.5.0版本。当我使用2.7.1版本的mockwebserver时,问题得到解决。

1 个答案:

答案 0 :(得分:0)

在使用proguard混淆代码时,需要添加异常以避免来自proguard的类,方法或字段。您的大多数图书馆都处于危险区域的反射原因。您需要为每个使用例如RXJava,Dagger,Retrofit和GSON的库找到特定的proguard配置。

另一个解决方案是忘记预备或安全,就像避免整个改装包一样。