【问题标题】:Mockito Spy quartz MethodInvokingJobDetailFactoryBean target job bean failedMockito Spyquartz MethodInvokingJobDetailFactoryBean 目标作业 bean 失败
【发布时间】:2022-09-27 22:03:53
【问题描述】:

Spring 6、Quartz 和基于 SimpleTrigger 的计划任务。

@Component
@Slf4j
public class Greeting {

    public void sayHello() {
        log.debug(\"Hello at {}:\", LocalDateTime.now());
    }
}

石英配置:


@Configuration
class QuartzConfig{
    @Bean
    MethodInvokingJobDetailFactoryBean greetingJobDetailFactoryBean() {
        var jobFactory = new MethodInvokingJobDetailFactoryBean();
        jobFactory.setTargetBeanName(\"greeting\");
        jobFactory.setTargetMethod(\"sayHello\");
        return jobFactory;
    }

    @Bean
    public SimpleTriggerFactoryBean simpleTriggerFactoryBean() {
        SimpleTriggerFactoryBean simpleTrigger = new SimpleTriggerFactoryBean();
        simpleTrigger.setJobDetail(greetingJobDetailFactoryBean().getObject());
        simpleTrigger.setStartDelay(1_000);
        simpleTrigger.setRepeatInterval(5_000);
        return simpleTrigger;
    }

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
        var factory = new SchedulerFactoryBean();
        factory.setTriggers(
                simpleTriggerFactoryBean().getObject(),
                cronTriggerFactoryBean().getObject()
        );
        return factory;
    }

我尝试使用等待来检查调用。


@SpringJUnitConfig(value = {
        QuartzConfig.class,
        Greeting.class
})
public class GreetingTest {

    @Autowired
    Greeting greeting;

    Greeting greetingSpy;

    @BeforeEach
    public void setUp() {
        this.greetingSpy = spy(greeting);
    }

    @Test
    public void whenWaitTenSecond_thenScheduledIsCalledAtLeastTenTimes() {
        await()
                .atMost(Duration.ofSeconds(10))
                .untilAsserted(() -> verify(greetingSpy, atLeast(1)).sayHello());
    }
}

运行测试,它失败了。

org.awaitility.core.ConditionTimeoutException: Assertion condition defined as a com.example.demo.GreetingTest 
Wanted but not invoked:
greeting.sayHello();
-> at com.example.demo.GreetingTest.lambda$whenWaitTenSecond_thenScheduledIsCalledAtLeastTenTimes$0(GreetingTest.java:36)
Actually, there were zero interactions with this mock.
 within 10 seconds.

在jobDetailFactorBean中,我使用jobFactory.setTargetBeanName(\"greeting\");在这里设置目标bean,它应该直接传递Greeting bean。

更新:自己解决了,检查here。

    标签: spring mockito awaitility


    【解决方案1】:

    您正在创建一个不会与实际代码交互的间谍:

        @BeforeEach
        public void setUp() {
            this.greetingSpy = spy(greeting);
        }
    

    这必须作为 bean 注入 Spring 上下文并在使用 greeting 的任何地方使用。 Spring 实际上提供了这样的功能:@SpyBean。

    而不是自动装配 greeting 并用不与上下文中的任何内容交互的间谍包装它,而是将 @Autowired 替换为 @SpyBean 注释。因此,将在 Spring 上下文中创建和注入一个 spy bean:

        @SpyBean
        Greeting greeting;
    

    我在GitHub repository 中创建了一个提交,您可以在其中看到整个代码——测试通过了。我不得不将 cronTriggerFactoryBean() 方法添加到配置中,因为您的问题中省略了它。


    如果您不能使用 Spring Boot,您可以使用配置在 Spring 上下文中自己创建间谍:

    static class Config {
    
        @Bean
        @Primary
        Greeting greeting() {
            return spy(new Greeting());
        }
    }
    

    多亏了当您注入 bean 时,可以使用 Mockito 对其进行操作(请记住在 @SpringJUnitConfig 注释中包含 Config 类)。

    我创建了另一个提交 in the GitHub repository - 测试通过了。你可以在那里看到整个代码。

    【讨论】:

    • 我在这里不使用 Spring Boot。我很了解 Spring Boot 中的 MockBean 和 SpyBean。
    • 我编辑了答案并为此案例添加了解决方案。
    • 已经自己解决了,请查看the tests。顺便说一句,您的 spy bean 不会 spy 目标 bean。
    • 如果答案是问题的正确解决方案,请接受它。在这种情况下无需监视特定实例,因为仅验证调用次数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-15
    • 1970-01-01
    • 2019-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多