编写JUnit测试遇匹配器错误,求教Mock内部创建的RestTemplate
JUnit测试问题解决:"0 matchers expected, 1 recorded"错误及Mock RestTemplate方案
一、错误原因分析
"0 matchers expected, 1 recorded"错误是因为在真实方法调用中使用了Mockito匹配器(如any())。比如你的getTest方法里idmService.get(endPoint, any(), true),any()这类匹配器只能用于Mockito的when()/verify()方法,不能作为真实方法的参数传递。
二、代码重构:让RestTemplate可Mock
你的exchange方法里直接new RestTemplate(...),这种局部创建的对象无法被Mock,必须通过依赖注入将RestTemplate注入到类中,才能进行测试。重构后的TestServiceImpl:
@Service public class TestServiceImpl implements TestService { // 注入RestTemplate,替代方法内new的方式 private final RestTemplate restTemplate; // 构造方法注入(推荐方式,符合依赖注入原则) public TestServiceImpl(RestTemplate restTemplate) { this.restTemplate = restTemplate; // 配置HttpComponentsClientHttpRequestFactory this.restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory()); } @Override public Object get(String endpoint, ParameterizedTypeReference reference, boolean useToken) { // 补全原代码缺失的userId参数 ResponseEntity response = exchange(HttpMethod.GET, endpoint, null, reference, useToken, "defaultUserId"); return response.getBody(); } @Override public ResponseEntity<Object> exchange(HttpMethod httpMethod, String endpoint, @Nullable Object body, ParameterizedTypeReference<Object> reference, boolean useToken, String userId) { try { HttpHeaders headers = new HttpHeaders(); // 这里可以添加headers的业务逻辑(比如token处理) ResponseEntity<Object> response = restTemplate.exchange(endpoint, httpMethod, new HttpEntity<>(body, headers), reference); return response; } catch (Exception e) { e.printStackTrace(); // 返回错误响应,避免返回null return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } }
三、正确编写测试用例
1. get方法测试(Mock本类的exchange方法)
get方法依赖本类的exchange方法,用Mockito Spy可以保留真实类的逻辑,同时Mockexchange方法的返回,验证get方法的正确性:
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.core.ParameterizedTypeReference; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.doReturn; import static org.mockito.ArgumentMatchers.*; @ExtendWith(MockitoExtension.class) public class TestServiceImplTest { @Spy @InjectMocks private TestServiceImpl testService; // Spy对象:保留真实逻辑,可Mock指定方法 @Mock private RestTemplate restTemplate; // 注入依赖,满足构造方法要求 @Test public void getTest() { // 准备测试数据 String endpoint = "/api/test"; ParameterizedTypeReference<Object> typeRef = new ParameterizedTypeReference<>() {}; ResponseEntity<Object> mockResponse = ResponseEntity.ok("mockGetBody"); // Mock exchange方法的返回 doReturn(mockResponse) .when(testService) .exchange(eq(HttpMethod.GET), eq(endpoint), isNull(), eq(typeRef), eq(true), eq("defaultUserId")); // 调用get方法 Object result = testService.get(endpoint, typeRef, true); // 验证结果 assertEquals("mockGetBody", result); } }
2. exchange方法测试(Mock RestTemplate的exchange方法)
测试exchange方法时,Mock注入的RestTemplate,验证它是否被正确调用,并返回预期结果:
@Test public void exchangeTest() { // 准备测试数据 String endpoint = "/api/exchange"; HttpMethod httpMethod = HttpMethod.POST; Object body = new Object(); ParameterizedTypeReference<Object> typeRef = new ParameterizedTypeReference<>() {}; boolean useToken = true; String userId = "testUserId"; ResponseEntity<Object> mockResponse = ResponseEntity.ok("mockExchangeBody"); // Mock RestTemplate的exchange方法 doReturn(mockResponse) .when(restTemplate) .exchange(eq(endpoint), eq(httpMethod), any(HttpEntity.class), eq(typeRef)); // 调用exchange方法 ResponseEntity<Object> result = testService.exchange(httpMethod, endpoint, body, typeRef, useToken, userId); // 验证结果 assertEquals("mockExchangeBody", result.getBody()); // 可选:验证RestTemplate的exchange方法是否被调用一次 // verify(restTemplate, times(1)).exchange(eq(endpoint), eq(httpMethod), any(HttpEntity.class), eq(typeRef)); }
四、关键注意事项
- 禁止在真实方法调用中使用Mockito匹配器(如
any()、eq()),匹配器仅用于Mockito的when()/verify()方法。 - 避免在方法内直接创建依赖对象(如
new RestTemplate()),通过依赖注入管理依赖,便于测试和维护。 - 使用
@Spy时,确保被Mock的方法是非final的,否则Mockito无法进行Mock操作。
内容的提问来源于stack exchange,提问作者Arvind Reddy
相关产品推荐
相关产品推荐

