You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为内部创建对象并传给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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 10:24:00