You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mockito测试报错:SSLConnectionSocketFactory无法返回,仅用MockitoExtension求解

问题与解决方案

问题

编写了执行HTTP POST操作的Java代码,其中PostUtility类的getSocketFactory方法返回SSLSocketFactory。使用MockitoExtension编写单元测试时出现错误:提示“SSLConnectionSocketFactory$MockitoMock$xxx无法被getSocketFactory()返回,该方法应返回SSLSocketFactory”。要求仅用MockitoExtension解决,不使用PowerMockito。

业务代码

public Response postResponse(
        @NonNull final String payload,
        @NonNull final String endpoint,
        @NonNull final ContentType contentType,
        @NonNull final String clientCertificate
) {
    SSLConnectionSocketFactory sslConnectionSocketFactory;
    if (StringUtils.isNotEmpty(clientCertificate)) {
        // Client certificate is present, thus using TLS
        sslConnectionSocketFactory =
                new SSLConnectionSocketFactory(postUtility
                        .getSocketFactory(clientCertificate),
                        NoopHostnameVerifier.INSTANCE);
    } else {
        SSLContext sslcontext = SSLContext.getInstance("TLS");
        sslcontext.init(null, null, new java.security.SecureRandom());

        sslConnectionSocketFactory = new SSLConnectionSocketFactory(
                sslcontext,
                new String[]{"TLSv1"}, //{ "TLS10" },
                null,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());
    }

    HttpPost httpPost = new HttpPost(endpoint);
    httpPost.setHeader("Content-Type", contentType.getMimeType());

    httpPost.setEntity(
            EntityBuilder.create()
                    .setText(payload)
                    .setContentType(contentType)
                    .build()
    );

    try (
            CloseableHttpClient httpclient = HttpClients.custom()
                    .setSSLContext(SSLContext.getDefault())
                    .setSSLSocketFactory(sslConnectionSocketFactory)
                    .build();
            CloseableHttpResponse response = httpclient.execute(httpPost)
    ) {
        return Response.status(response.getStatusLine().getStatusCode()).build();
    } catch (Exception ex) {
        log.error("Unable to send response", ex);
        return Response.serverError().build();
    }
}

原测试代码(存在错误)

@Mock
private PostUtility postUtility;

@Mock
private SSLConnectionSocketFactory sslConnectionSocketFactory;

@Mock
private SSLSocketFactory sslSocketFactory;

@Mock
private CloseableHttpClient httpclient;

@Mock
private CloseableHttpResponse httpResponse;

@Mock
private StatusLine statusLine;

@Test
public void testPostResponse() throws Exception {
    when(postUtility.getSocketFactory(clientCertificate))
            .thenReturn(sslSocketFactory);
    when(new SSLConnectionSocketFactory(postUtility.getSocketFactory(clientCertificate), NoopHostnameVerifier.INSTANCE))
            .thenReturn(sslConnectionSocketFactory);

    when(httpResponse.getStatusLine()).thenReturn(statusLine);
    when(statusLine.getStatusCode()).thenReturn(200);
    when(httpclient.execute(any(HttpPost.class))).thenReturn(httpResponse);


    Response response = className.postResponse("testPayLoad","testEndPoint",ContentType.TEXT_XML, "testclientCertificate");

    assertEquals(200, response.getStatus(), "Response status code should be 200");
}

错误原因

原测试代码中when(new SSLConnectionSocketFactory(...)).thenReturn(...)是无效操作——Mockito无法直接mock构造方法的调用,这行代码会导致类型匹配错误;同时业务代码中是直接新建SSLConnectionSocketFactory实例,无法直接mock该对象。

修复方案

关键修复点

  1. 删除mock构造方法的错误代码,改用Mockito的静态mock能力控制HttpClients的创建流程
  2. 确保PostUtility.getSocketFactory返回的mock对象类型与方法声明一致(SSLSocketFactory)
  3. mockHttpClientBuilder的链式调用,让其最终返回预先定义好的CloseableHttpClient mock对象

修正后的测试代码

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertEquals;

@ExtendWith(MockitoExtension.class)
public class YourServiceTest { // 替换为实际测试类名

    @Mock
    private PostUtility postUtility;

    @Mock
    private SSLSocketFactory sslSocketFactory;

    @Mock
    private CloseableHttpClient httpclient;

    @Mock
    private CloseableHttpResponse httpResponse;

    @Mock
    private StatusLine statusLine;

    @Mock
    private HttpClientBuilder httpClientBuilder;

    private static final String TEST_CERT = "testclientCertificate";

    @Test
    public void testPostResponse() throws Exception {
        // 1. Mock PostUtility返回正确的SSLSocketFactory
        when(postUtility.getSocketFactory(TEST_CERT))
                .thenReturn(sslSocketFactory);

        // 2. 静态mock HttpClients.custom(),返回我们的HttpClientBuilder mock
        try (MockedStatic<HttpClients> mockedHttpClients = mockStatic(HttpClients.class)) {
            mockedHttpClients.when(HttpClients::custom).thenReturn(httpClientBuilder);

            // 3. Mock HttpClientBuilder的链式调用,保证每个set方法返回自身,最终build返回mock的client
            when(httpClientBuilder.setSSLContext(any(SSLContext.class))).thenReturn(httpClientBuilder);
            when(httpClientBuilder.setSSLSocketFactory(any(SSLConnectionSocketFactory.class))).thenReturn(httpClientBuilder);
            when(httpClientBuilder.build()).thenReturn(httpclient);

            // 4. Mock HttpClient执行结果
            when(httpclient.execute(any(HttpPost.class))).thenReturn(httpResponse);
            when(httpResponse.getStatusLine()).thenReturn(statusLine);
            when(statusLine.getStatusCode()).thenReturn(200);

            // 执行测试方法(替换为实际业务类的实例化方式)
            YourService service = new YourService(postUtility);
            Response response = service.postResponse("testPayLoad", "testEndPoint", ContentType.TEXT_XML, TEST_CERT);

            // 断言结果
            assertEquals(200, response.getStatus(), "响应状态码应为200");

            // 验证关键调用
            verify(postUtility).getSocketFactory(TEST_CERT);
            mockedHttpClients.verify(HttpClients::custom);
            verify(httpClientBuilder).setSSLSocketFactory(any(SSLConnectionSocketFactory.class));
            verify(httpclient).execute(any(HttpPost.class));
        }
    }
}

依赖要求

确保测试依赖中引入mockito-inline(用于支持静态mock),Maven依赖示例:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>4.11.0</version> <!-- 使用最新稳定版本 -->
    <scope>test</scope>
</dependency>

内容的提问来源于stack exchange,提问作者snigdha singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 12:21:07