如何正确实现RestTemplate单元测试的mock并优化硬编码问题
单元测试优化方案
核心优化点
1. 消除硬编码配置问题
你当前测试中写入真实URL、token属于不必要的依赖:单元测试的核心是校验CarService的业务流程正确性,不需要校验配置值本身的准确性,这类配置应该由业务代码通过@Value等注入方式从配置文件读取,测试侧不需要感知具体值。
优化方案:
- 用Mockito参数匹配器替换固定值匹配,避免硬编码URI、token
- 若需要校验请求参数特征(比如确实携带了Bearer token、请求路径符合规则),用
ArgumentCaptor捕获参数后做断言,不需要和固定值绑定
2. 初始化逻辑优化
- 测试桩数据(
carList、testCars)可以定义为静态常量,不需要在@Before/@BeforeAll中初始化,减少冗余代码 - 重复的Header、RequestEntity构造逻辑抽为公共方法,避免多测试方法重复编码
- 处理URI构造的受检异常,避免测试方法中冗余的异常声明
3. Mock逻辑简化
- 消除
when和verify阶段重复构造RequestEntity的冗余代码 - 非必要场景去掉
verifyNoMoreInteractions,避免后续新增逻辑时测试无谓失败
优化后代码示例
@RunWith(MockitoJUnitRunner.class) public class CarServiceTest { private static final List<Car> TEST_CAR_LIST = List.of(new Car("car1")); private static final Cars TEST_CARS = new Cars(TEST_CAR_LIST); @Mock private RestTemplate restTemplate; @InjectMocks private CarService carService; @Test public void test_getCars() throws URISyntaxException { // Mock返回逻辑,用参数匹配器不需要硬编码uri和token Mockito.when(restTemplate.exchange( any(RequestEntity.class), eq(Cars.class))) .thenReturn(new ResponseEntity<>(TEST_CARS, HttpStatus.OK)); Cars returnedCars = carService.getCars(); // 断言返回结果 Assert.assertEquals(TEST_CARS, returnedCars); // 捕获请求参数做特征校验(不需要校验具体值的话可以跳过) ArgumentCaptor<RequestEntity> requestCaptor = ArgumentCaptor.forClass(RequestEntity.class); verify(restTemplate).exchange(requestCaptor.capture(), eq(Cars.class)); RequestEntity actualRequest = requestCaptor.getValue(); // 校验请求是GET方法 Assert.assertEquals(HttpMethod.GET, actualRequest.getMethod()); // 校验header携带了Authorization Assert.assertNotNull(actualRequest.getHeaders().getFirst(HttpHeaders.AUTHORIZATION)); // 校验接受JSON返回 Assert.assertTrue(actualRequest.getHeaders().getAccept().contains(MediaType.APPLICATION_JSON)); } }
如果确实需要校验请求URI的正确性,可以在捕获参数后加URI路径断言,不需要硬编码完整路径。
内容的提问来源于stack exchange,提问作者jimmy
相关产品推荐
相关产品推荐

