PowerMock java.lang.ClassCastException:sun.net.www.protocol.https.HttpsURLConnectionImpl无法强制转换为javax.net.ssl.HttpsURLConnection

时间:2015-07-01 09:29:21

标签: java powermock powermockito

我根据fiddle创建了一个模拟HttpsURLConnection

import java.net.URL;
import javax.net.ssl.HttpsURLConnection;

...

@RunWith(PowerMockRunner.class)
public class DialogTest {
    public void mockHttpsUrlConnectionExample() throws Exception
    {
        URL mockUrl = PowerMockito.mock(URL.class);
        PowerMockito.whenNew(URL.class).withAnyArguments().thenReturn(mockUrl);
        HttpsURLConnection mockUrlConnection = PowerMockito.mock(HttpsURLConnection.class);
        PowerMockito.when(mockUrl.openConnection()).thenReturn(mockUrlConnection);
        PowerMockito.when(mockUrlConnection.getResponseCode()).thenReturn(200);

        // Create and call my objects ...

    }
}

然而,当我使用它时,我发现了一个强制转换异常:

java.lang.ClassCastException: sun.net.www.protocol.https.HttpsURLConnectionImpl cannot be cast to javax.net.ssl.HttpsURLConnection

问题在于此代码:

import java.net.URL;
import javax.net.ssl.HttpsURLConnection;

...

private Boolean sendRequest(String endpoint, JSONObject requestData, Boolean throwOnAuthException) throws JSONException, IOException {
    this.responseData = null;

    try {
        String serviceURI = getServiceURI();
        String dialogUri = String.format("%s%s", serviceURI, endpoint);
        URL url = new URL(dialogUri);

        // Exception source is this cast
        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();

但是,当我查看源代码时,我发现sun.net.www.protocol.https.HttpsURLConnectionImpl实现了javax.net.ssl.HttpsURLConnection

有关如何解决此问题的任何建议?

1 个答案:

答案 0 :(得分:6)

常规类加载器与PowerMock之间的冲突

PowerMock的缺点是使用自定义类加载器。此类加载器可以以与默认类加载器不兼容的方式修改类型签名。

在某些情况下,通过反射实例化将导致默认类加载器用于加载类型。由于使用了不同的签名,该类加载器不会知道PowerMock已经加载了一个类型。结果可能是错误  应该实现强制转换类型的对象。

要避免此问题,请先停止PowerMock加载string name

要防止强制转换异常,请使用确保javax.net.ssl.HttpsURLConnection仅由一个类加载器加载。由于我无法停止使用常规类加载器,因此最好的方法是使用javax.net.ssl.HttpsURLConnection注释停止PowerMock加载器。例如。

@PowerMockIgnore

副作用是PowerMock无法再提供@PowerMockIgnore({"javax.net.ssl.*"}) @PrepareForTest(android.util.Log.class) public class DialogTest { ...

的版本

接下来,公开HttpsURLConnection构造,并替换模拟对象

为HttpsURLConnection引入工厂。例如。

HttpsURLConnection

创建用于HTTP请求的HttpsURLConnection对象的模拟,例如

public class HttpsUrlConnectionProvider {
    public HttpsURLConnection getHttpsURLConnection(String dialogUri) throws IOException {
        URL url = new URL(dialogUri);
        return (HttpsURLConnection) url.openConnection();
    }
}