如何为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; } }
实用技巧
- 如果你的
Authorizationtoken是动态生成的(不是固定的234YML),可以用anyString()来匹配参数,避免硬编码:
when(mockInvocationBuilder.header("Authorization", anyString())) .thenReturn(mockInvocationBuilder);
- 如果你不需要验证具体的头参数,也可以用
any()来匹配所有header()调用:
when(mockInvocationBuilder.header(anyString(), any())) .thenReturn(mockInvocationBuilder);
- 记得在测试前确保所有Mock对象都被正确初始化,避免空指针。
内容的提问来源于stack exchange,提问作者Jav
相关产品推荐
相关产品推荐

