如何在SpringBootTest中为Mock对象设置默认行为并按需覆盖?
在@SpringBootTest中实现Mock对象默认行为+部分测试覆盖
完全可以为Mock对象设置默认行为,并在指定测试中覆盖,你遇到的测试套件下覆盖失效问题,主要是测试上下文复用导致Mock状态残留,以及ParameterizedTypeReference的匹配逻辑问题,以下是具体解决方案:
问题分析
- 上下文复用残留状态:Spring Boot测试套件默认会复用上下文,前一个测试修改的Mock存根会保留到下一个测试,导致覆盖逻辑失效。
- ParameterizedTypeReference匹配失败:
new ParameterizedTypeReference<Map<String, String>>()每次创建的实例是全新的,Mockito.eq()无法识别为同一个参数,导致存根覆盖不生效。
解决步骤
1. 测试后强制重置Mock状态
在基类中添加@AfterEach方法,重置所有Mock对象,确保每个测试方法都从默认行为开始:
@Disabled public abstract class RestApiBaseTest extends AbstractSpringBootTest { // ... 已有代码 @AfterEach public void resetMocks() { Mockito.reset(apiRestTemplate, apiProperties); } }
2. 修复ParameterizedTypeReference的匹配逻辑
将eq(new ParameterizedTypeReference<>())替换为更可靠的匹配方式:
方式一:宽松匹配(适用于不关心具体泛型类型的场景)
// 基类默认行为 ResponseEntity r = new ResponseEntity(new HashMap<String, String>(), HttpStatus.ACCEPTED); Mockito.when(apiProperties.getUrl()).thenReturn("http://localhost:8080/test"); Mockito.when(apiRestTemplate.exchange(any(), any(ParameterizedTypeReference.class))) .thenReturn(r); // 测试方法中的覆盖 Mockito.when(apiRestTemplate.exchange(any(), any(ParameterizedTypeReference.class))) .thenThrow(apiErrorException);
方式二:精确匹配泛型类型
如果需要严格匹配Map<String,String>类型,使用自定义参数匹配器:
// 基类中定义匹配器 ArgumentMatcher<ParameterizedTypeReference<?>> stringMapMatcher = ref -> { Type type = ref.getType(); return type instanceof ParameterizedType && ((ParameterizedType) type).getRawType().equals(Map.class) && Arrays.equals(((ParameterizedType) type).getActualTypeArguments(), new Type[]{String.class, String.class}); }; // 基类默认存根 Mockito.when(apiRestTemplate.exchange(any(), argThat(stringMapMatcher))) .thenReturn(r); // 测试方法覆盖 Mockito.when(apiRestTemplate.exchange(any(), argThat(stringMapMatcher))) .thenThrow(apiErrorException);
3. 可选:禁用上下文复用(开销较大)
如果上述方法无效,可以在测试类上添加@DirtiesContext,强制每个测试后重建上下文,但会增加测试运行时间:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ActiveProfiles("IC") @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) public class CreationTest extends RestApiBaseTest { // ... 测试方法 }
内容的提问来源于stack exchange,提问作者krakig
相关产品推荐
相关产品推荐

