如何为内部创建对象并传给mock的方法编写JUnit 5单元测试
场景说明
你要测试的方法会在内部构造QueryFiltersConfig实例,再传入Mock对象certificateRepository的findWithFilters方法,JUnit 5 + Mockito场景下有以下几种实现方案:
方案1:直接使用参数匹配器存根
不需要校验内部构造的Config参数
如果你的测试重点在方法的后续转换逻辑,不需要验证QueryFiltersConfig构造是否正确,可以直接用any()匹配器存根:
// 初始化模拟返回的实体列表 List<GiftCertificate> mockCertificates = List.of(new GiftCertificate()); // 存根repository方法,匹配任意QueryFiltersConfig参数 Mockito.when(certificateRepository.findWithFilters(Mockito.any(QueryFiltersConfig.class))) .thenReturn(mockCertificates);
需要校验Config构造结果
如果需要验证方法内部构造的QueryFiltersConfig符合预期,可以用argThat自定义匹配逻辑:
// 示例测试场景:传入tagName为"holiday",校验构造的config是否正确设置了tag Mockito.when(certificateRepository.findWithFilters(Mockito.argThat(config -> "holiday".equals(config.getTag()) // 还可以补充其他属性校验逻辑,比如排序规则、搜索关键词 ))).thenReturn(mockCertificates);
方案2:使用参数捕获器(更推荐)
如果既要存根返回值,又要事后断言Config的构造是否完全符合预期,用ArgumentCaptor是更清晰的实现:
// 1. 声明参数捕获器 @Captor private ArgumentCaptor<QueryFiltersConfig> configCaptor; // 2. 先存根repository方法,用any匹配 Mockito.when(certificateRepository.findWithFilters(Mockito.any(QueryFiltersConfig.class))) .thenReturn(mockCertificates); // 3. 执行被测方法 List<GiftCertificateDto> result = testInstance.fetchCertificatesWithFilters( Optional.of("holiday"), Optional.of(List.of("name:asc")), Optional.of("gift") ); // 4. 捕获传入的config,断言属性符合预期 Mockito.verify(certificateRepository).findWithFilters(configCaptor.capture()); QueryFiltersConfig actualConfig = configCaptor.getValue(); Assertions.assertEquals("holiday", actualConfig.getTag()); Assertions.assertEquals("gift", actualConfig.getSearchPattern()); // 补充其他属性的断言逻辑
更优的代码优化方案
如果要进一步提升可测试性,可以把QueryFiltersConfig的构造逻辑抽成单独的包级私有方法:
// 原业务类中新增抽离的构造方法 QueryFiltersConfig buildFilterConfig(Optional<String> tagName, Optional<List<String>> sortTypes, Optional<String> searchPattern) { QueryFiltersConfig.Builder filterConfigBuilder = QueryFiltersConfig.builder(); tagName.ifPresent(filterConfigBuilder::withTag); addSortsToConfig(sortTypes, filterConfigBuilder); searchPattern.ifPresent(filterConfigBuilder::withSearchPattern); return filterConfigBuilder.build(); } // 原业务方法简化为 @Override public List<GiftCertificateDto> fetchCertificatesWithFilters(Optional<String> tagName, Optional<List<String>> sortTypes, Optional<String> searchPattern) { QueryFiltersConfig config = buildFilterConfig(tagName, sortTypes, searchPattern); return certificateRepository.findWithFilters(config).stream() .map(dtoTranslator::giftCertificateToDto).collect(Collectors.toList()); }
改造后你可以单独写用例测试buildFilterConfig的构造逻辑,主流程测试直接mock该方法返回指定Config即可,测试逻辑拆分更清晰。
内容的提问来源于stack exchange,提问作者Herman Shpryhau
相关产品推荐
相关产品推荐

