模拟HTTPSURLConnection类会抛出java.lang.AbstractMethodError

时间:2017-04-14 11:50:24

标签: java junit mockito httpurlconnection powermockito

我想嘲笑以下几行

static void processRemoteToLocal(String srcUrl, String destFile) {

        URL fileUrl = new URL(srcUrl);

        HttpsURLConnection.setDefaultSSLSocketFactory(Foo.getSslContext().getSocketFactory());

        HttpsURLConnection.setDefaultHostnameVerifier(Foo.getHostnameVerifier());

        HttpsURLConnection connection = (HttpsURLConnection) fileUrl.openConnection();

    }

对于上面的代码,我使用PowerMockito更新了我的测试类,如下所示

@Test
@PrepareForTest({Foo.class,SSLSocketFactory.class})
public void shouldSetTestMockServeField() throws Exception {

    HostnameVerifier hnameMock = PowerMockito.mock(HostnameVerifier.class);
    SSLSocketFactory mockSocFac = PowerMockito.mock(SSLSocketFactory.class);
    HttpsURLConnection huc = PowerMockito.mock(HttpsURLConnection.class);
    Foo mockCert = PowerMockito.mock(Foo.class);
    SSLContext sslMock = PowerMockito.mock(SSLContext.class);

    final SSLSocketFactory sslFac = null;

    URL u = PowerMockito.mock(URL.class);
    String url = "https://localhost";
    PowerMockito.whenNew(URL.class).withArguments(url).thenReturn(u);

    PowerMockito.mockStatic(Foo.class);
    Mockito.when(Foo.getSslContext()).thenReturn(sslMock);
    Mockito.when(sslMock.getSocketFactory()).thenReturn(mockSocFac);

这会在最后一行给出错误java.lang.NullPointerException。

有人可以建议如何解决它吗?

1 个答案:

答案 0 :(得分:1)

我已经使用java 7,JUnit 4.12,Mockito 1.10.19和PowerMock 1.6.3进行了测试

我创建了一个包含您要模拟的代码的类:

public class HttpTest {

    static void processRemoteToLocal(String srcUrl, String destFile) throws Exception {
        URL fileUrl = new URL(srcUrl);

        HttpsURLConnection.setDefaultSSLSocketFactory(Foo.getSslContext().getSocketFactory());

        HttpsURLConnection.setDefaultHostnameVerifier(Foo.getHostnameVerifier());

        HttpsURLConnection connection = (HttpsURLConnection) fileUrl.openConnection();
    }
}

我还根据您上面的评论创建了课程Foo

public class Foo {
    // I'm just returning something, not sure how your implementation is (and it doesn't make difference because you'll mock it anyway)
    public static SSLContext getSslContext() {
        try {
            return SSLContext.getDefault();
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }

    // I'm just returning something, not sure how your implementation is (and it doesn't make difference because you'll mock it anyway)
    public static HostnameVerifier getHostnameVerifier() {
        return new HostnameVerifier() {

            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }
        };
    }
}

由于您想在processRemoteToLocal方法中模拟代码,因此您只需要模拟以下内容:

  • URL构造函数
  • Foo方法:getSslContext()getHostnameVerifier()
  • URL.openConnection()方法

所以你的测试类将是这样的:

// RunWith needed for powermock
@RunWith(PowerMockRunner.class)
@PrepareForTest({ HttpTest.class, Foo.class, SSLContext.class, URL.class })
public class MyTestClass {

    @Test
    public void shouldSetTestMockServeField() throws Exception {
        URL u = PowerMockito.mock(URL.class);
        String url = "https://localhost";
        // mock URL constructor
        PowerMockito.whenNew(URL.class).withArguments(Matchers.anyString()).thenReturn(u);
        // mock openConnection() method
        HttpsURLConnection huc = Mockito.mock(HttpsURLConnection.class);
        Mockito.when(u.openConnection()).thenReturn(huc);

        // create mocks for Foo class
        HostnameVerifier hnameMock = Mockito.mock(HostnameVerifier.class);
        SSLContext context = PowerMockito.mock(SSLContext.class);
        SSLSocketFactory mockSocFac = Mockito.mock(SSLSocketFactory.class);
        Mockito.when(context.getSocketFactory()).thenReturn(mockSocFac);

        // mock Foo static methods to return mocks created above
        PowerMockito.mockStatic(Foo.class);
        Mockito.when(Foo.getHostnameVerifier()).thenReturn(hnameMock);
        Mockito.when(Foo.getSslContext()).thenReturn(context);

        // call static method, code will use mocked objects
        // Foo static methods will return mocked SSLContext and HostnameVerifier created above
        // URL.openConnecton will return mocked HttpsURLConnection
        HttpTest.processRemoteToLocal(url, "/test.out");

        // do the assertions you need
    }
}