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

Spring单元测试JMockit报missing invocation缺失调用错误

问题根因

测试报错的核心原因是测试执行流程根本没有走到Controller里调用skillRepository.findAllById和job.setSkills的else分支,两个配置的预期调用自然不会触发,具体触发点有两个:

  1. 你没有为Mock的employerRepository.findById()方法配置返回值,JMockit默认对返回Optional类型的Mock方法返回空Optional,执行到if(result.isEmpty())判断时会直接进入该分支返回,不会走到后续else逻辑。
  2. 反射调用Controller方法时传入的skills参数类型错误:方法要求入参是List<Integer>,你实际传入的是new ArrayList<Skill>(),且传入的employerId为0,和Mock逻辑不匹配,进一步导致流程偏离预期分支。
修复方案

按以下步骤调整测试代码即可:

  • 为employerRepository.findById配置Mock返回值,返回包含Employer实例的非空Optional,保证流程进入else块
  • 修正传入Controller的skills参数,改为元素为Integer、长度大于1的列表,避免触发前置if判断的提前返回
  • 为skillRepository.findAllById配置Mock返回值,避免返回null导致逻辑异常
  • 保证传入的employerId和Mock配置的入参匹配
修复后测试代码示例
@Test
public void testProcessAddJobFormHandlesSkillsProperly (
        @Mocked SkillRepository skillRepository,
        @Mocked EmployerRepository employerRepository,
        @Mocked JobRepository jobRepository,
        @Mocked Job job,
        @Mocked Errors errors,
        @Mocked Employer testEmployer)
        throws Exception {
    Class homeControllerClass = getClassByName("controllers.HomeController");
    Method processAddJobFormMethod = homeControllerClass.getMethod("processAddJobForm", Job.class, Errors.class, Model.class, int.class, List.class);

    // 测试数据准备
    int testEmployerId = 1;
    List<Integer> testSkillIds = Arrays.asList(1,2);
    List<Skill> testSkillObjs = new ArrayList<>();

    new Expectations() {{
        // 配置employerRepository返回非空Optional,保证进入else分支
        employerRepository.findById(testEmployerId);
        result = Optional.of(testEmployer);
        // 配置skillRepository返回值
        skillRepository.findAllById((List<Integer>) any);
        result = testSkillObjs;
        // 预期调用
        job.setSkills((List<Skill>) any);
    }};

    Model model = new ExtendedModelMap();
    HomeController homeController = new HomeController();

    // 注入Mock的Repository
    Field skillRepositoryField = homeControllerClass.getDeclaredField("skillRepository");
    skillRepositoryField.setAccessible(true);
    skillRepositoryField.set(homeController, skillRepository);

    Field employerRepositoryField = homeControllerClass.getDeclaredField("employerRepository");
    employerRepositoryField.setAccessible(true);
    employerRepositoryField.set(homeController, employerRepository);

    Field jobRepositoryField = homeControllerClass.getDeclaredField("jobRepository");
    jobRepositoryField.setAccessible(true);
    jobRepositoryField.set(homeController, jobRepository);

    // 修正入参:传入正确类型的skills列表、匹配的employerId,errors默认hasErrors返回false不会触发前置分支
    processAddJobFormMethod.invoke(homeController,  job, errors, model, testEmployerId, testSkillIds);
}

补充说明:你Controller里的前置判断逻辑有小缺陷,当前只判断了skills.size()==1的场景,当skills长度为0(用户没选任何技能)时会直接走到持久化逻辑,建议调整为skills.size() < 1覆盖空选择场景,不过这个不影响当前测试通过。

内容的提问来源于stack exchange,提问作者Kang_the_Conqueror

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 01:57:26