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

JUnit测试RestTemplate时Mock失效连接真实URL问题求助

问题分析

你的测试代码Mock了RestTemplate但未生效,核心原因是业务类TestRestTemplate的RestTemplate是在自身构造函数中直接new出来的,测试类中@Mock的实例和业务类里的实例完全独立,Mock配置无法覆盖真实实例,代码依然会发起实际HTTP请求,导致连接超时。

解决方案

以下两种方案均可解决问题,核心思路是让业务类的RestTemplate实例支持外部注入,测试时传入Mock对象。

方案1:构造函数注入RestTemplate

修改业务类,通过构造函数传入RestTemplate,同时保留无参构造函数兼容原有运行方式:

public class TestRestTemplate {
    private final RestTemplate restTemplate;

    // 带参数构造函数,用于测试注入Mock实例
    public TestRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    // 无参构造函数,保持原有独立程序运行逻辑
    public TestRestTemplate() {
        this(new RestTemplate());
    }

    public void identifyInvoiceCategory(final Properties properties) throws Throwable {
        final ResponseEntity<SearchResponse> exchange = restTemplate.exchange(
                properties.getProperty("ENDPOINT"), HttpMethod.GET,
                new HttpEntity<>(createSearchRequest(), createHttpHeader()), SearchResponse.class);

        final SearchResponse searchResponse = exchange.getBody();
        searchResponse.getEndIndex();
    }

    private SearchRequest createSearchRequest() throws Throwable {
        final SearchRequest searchRequest = new SearchRequest();
        return searchRequest;
    }

    private HttpHeaders createHttpHeader() {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        return httpHeaders;
    }
}

修改测试类,传入Mock的RestTemplate并构造有效响应(避免getBody()时NPE):

@RunWith(MockitoJUnitRunner.class)
public class TestRest {
    @Mock
    private RestTemplate restTemplate;

    @Test
    public void testIdentifyInvoiceCategoryValid() throws Throwable {
        // 构造Mock响应数据
        SearchResponse mockResponse = new SearchResponse();
        mockResponse.setEndIndex(10); // 根据实际类的属性设置有效值
        ResponseEntity<SearchResponse> responseEntity = new ResponseEntity<>(mockResponse, HttpStatus.OK);

        // 配置Mock行为
        Mockito.when(restTemplate.exchange(
                ArgumentMatchers.anyString(), 
                ArgumentMatchers.eq(HttpMethod.GET),
                ArgumentMatchers.any(HttpEntity.class), 
                ArgumentMatchers.<Class<SearchResponse>>any())
        ).thenReturn(responseEntity);

        // 传入Mock实例创建业务类对象
        TestRestTemplate testInstance = new TestRestTemplate(restTemplate);
        testInstance.identifyInvoiceCategory(createProperties());
    }

    private Properties createProperties() {
        final Properties properties = new Properties();
        properties.setProperty("ENDPOINT", "http://www.test.com");
        return properties;
    }
}

方案2:Setter方法注入RestTemplate

如果不想修改构造函数,可添加Setter方法实现注入:

业务类添加Setter:

public class TestRestTemplate {
    private RestTemplate restTemplate;

    public TestRestTemplate() {
        restTemplate = new RestTemplate();
    }

    // 添加Setter用于测试注入Mock实例
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    // 其余业务方法不变...
}

测试类修改为通过Setter注入Mock:

@RunWith(MockitoJUnitRunner.class)
public class TestRest {
    @Mock
    private RestTemplate restTemplate;

    @Test
    public void testIdentifyInvoiceCategoryValid() throws Throwable {
        // 构造Mock响应数据
        SearchResponse mockResponse = new SearchResponse();
        mockResponse.setEndIndex(10);
        ResponseEntity<SearchResponse> responseEntity = new ResponseEntity<>(mockResponse, HttpStatus.OK);

        // 配置Mock行为
        Mockito.when(restTemplate.exchange(
                ArgumentMatchers.anyString(), 
                ArgumentMatchers.eq(HttpMethod.GET),
                ArgumentMatchers.any(HttpEntity.class), 
                ArgumentMatchers.<Class<SearchResponse>>any())
        ).thenReturn(responseEntity);

        TestRestTemplate testInstance = new TestRestTemplate();
        // 注入Mock实例
        testInstance.setRestTemplate(restTemplate);
        testInstance.identifyInvoiceCategory(createProperties());
    }

    private Properties createProperties() {
        final Properties properties = new Properties();
        properties.setProperty("ENDPOINT", "http://www.test.com");
        return properties;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 12:52:50