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

如何为REST客户端的WebTarget与Response编写Mock测试用例?

如何为REST客户端的WebTarget与Response编写Mock测试用例?

我来帮你搞定这个Mock测试的问题,你遇到的Authorization头对应的Builder返回null,本质是没正确处理链式调用的Mock逻辑——REST客户端的调用是链式的,每一步方法都会返回一个对象,Mockito需要你显式Mock每一步的返回值,不能只Mockrequest()这一步。

问题根源

你的代码里,WebTarget.request()返回Invocation.Builder,之后连续调用两次header(),而header()方法本身是链式返回自身的。如果只Mockrequest()的返回值,没Mockheader()的返回,那第一次调用header()就会返回null,后续的调用自然报错。

完整Mock测试示例

下面是针对你给出的代码的完整可运行测试用例,我会一步步拆解每个Mock点:

1. 声明需要Mock的对象

首先在测试类里声明所有需要Mock的依赖:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class) // JUnit 5初始化Mock,JUnit4用@RunWith(MockitoJUnitRunner.class)
public class RestClientTest {
    @Mock
    private Client clientLocal;
    @Mock
    private WebTarget mockWebTarget;
    @Mock
    private Invocation.Builder mockInvocationBuilder;
    @Mock
    private Response mockResponse;
    @Mock
    private Test mockTestEntity; // 你的Test实体类

2. 按调用顺序Mock每一步

在测试方法里,严格按照业务代码的调用顺序来Mock:

@Test
    void testRestClientCall() {
        // 1. Mock Client.target() 返回WebTarget
        when(clientLocal.target("/test/url")).thenReturn(mockWebTarget);

        // 2. Mock WebTarget.request() 返回Invocation.Builder
        when(mockWebTarget.request(MediaType.APPLICATION_JSON)).thenReturn(mockInvocationBuilder);

        // 3. 关键:Mock链式的header()方法,必须返回自身才能继续链式调用
        when(mockInvocationBuilder.header("Content-type", MediaType.APPLICATION_JSON))
                .thenReturn(mockInvocationBuilder);
        when(mockInvocationBuilder.header("Authorization", "Basic 234YML"))
                .thenReturn(mockInvocationBuilder);

        // 4. Mock post() 方法返回Response
        when(mockInvocationBuilder.post(Entity.entity("", MediaType.TEXT_PLAIN), Response.class))
                .thenReturn(mockResponse);

        // 5. Mock Response.readEntity() 返回你的Test实体
        when(mockResponse.readEntity(Test.class)).thenReturn(mockTestEntity);

        // ---------------------- 执行你的业务代码 ----------------------
        WebTarget resource = clientLocal.target("/test/url");
        Response response = resource.request(MediaType.APPLICATION_JSON)
                .header("Content-type", MediaType.APPLICATION_JSON)
                .header("Authorization", "Basic 234YML")
                .post(Entity.entity("", MediaType.TEXT_PLAIN), Response.class);
        Test responseEntity = response.readEntity(Test.class);

        // ---------------------- 验证调用是否符合预期 ----------------------
        verify(mockInvocationBuilder).header("Authorization", "Basic 234YML");
        verify(mockInvocationBuilder).post(Entity.entity("", MediaType.TEXT_PLAIN), Response.class);
        assert responseEntity == mockTestEntity;
    }
}

实用技巧

  • 如果你的Authorization token是动态生成的(不是固定的234YML),可以用anyString()来匹配参数,避免硬编码:
when(mockInvocationBuilder.header("Authorization", anyString()))
        .thenReturn(mockInvocationBuilder);
  • 如果你不需要验证具体的头参数,也可以用any()来匹配所有header()调用:
when(mockInvocationBuilder.header(anyString(), any()))
        .thenReturn(mockInvocationBuilder);
  • 记得在测试前确保所有Mock对象都被正确初始化,避免空指针。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:50:38