在Spring Tests上禁用@EnableScheduling

Rob*_*_UK 45 junit spring unit-testing junit4 springjunit4classrunner

当我运行我的单元测试时,它会调用我的计划任务.我想防止这种行为,这是由我@EnableScheduling在主应用程序配置上的事实引起的.

如何在单元测试中禁用此功能?

我遇到过这个问题/答案,建议设置个人资料?

不确定我会怎么做?或者如果它有点矫枉过正?我正在考虑为我的单元测试使用单独的AppConfiguration,但是当我这样做时,感觉就像是重复代码两次?

@Configuration
@EnableJpaRepositories(AppConfiguration.DAO_PACKAGE)
@EnableTransactionManagement
@EnableScheduling
@ComponentScan({AppConfiguration.SERVICE_PACKAGE,
                AppConfiguration.DAO_PACKAGE,
                AppConfiguration.CLIENT_PACKAGE,
                AppConfiguration.SCHEDULE_PACKAGE})
public class AppConfiguration {

    static final    String MAIN_PACKAGE             = "com.etc.app-name";
    static final    String DAO_PACKAGE              = "com.etc.app-name.dao";
    private static  final  String ENTITIES_PACKAGE  = "com.etc.app-name.entity";
    static final    String SERVICE_PACKAGE          = "com.etc.app-name.service";
    static final    String CLIENT_PACKAGE           = "com.etc.app-name.client";
    static final    String SCHEDULE_PACKAGE         = "com.etc.app-name.scheduling";


    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
       // stripped code for question readability
    }

    // more app config code below etc

}
Run Code Online (Sandbox Code Playgroud)

单元测试示例.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={AppConfiguration.class})
@Transactional
@TransactionConfiguration(defaultRollback = true)
@WebAppConfiguration
public class ExampleDaoTest {

    @Autowired
    ExampleDao exampleDao;

    @Test
    public void testExampleDao() {
        List<Example> items = exampleDao.findAll();
        Assert.assertTrue(items.size()>0);
    }
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*vic 43

如果您不想使用配置文件,则可以添加将启用/禁用应用程序调度的标志

在你的AppConfiguration添加中

  @ConditionalOnProperty(
     value = "app.scheduling.enable", havingValue = "true", matchIfMissing = true
  )
  @Configuration
  @EnableScheduling
  public static class SchedulingConfiguration {
  }
Run Code Online (Sandbox Code Playgroud)

并在您的测试中添加此注释以禁用调度

@TestPropertySource(properties = "app.scheduling.enable=false")
Run Code Online (Sandbox Code Playgroud)

  • 此外,您可以在测试的应用程序属性中设置“app.scheduling.enable=false”,这样您就无需为每个测试添加 TestPropertySource 注释。 (4认同)
  • 请注意,外部组件可能会自动启用调度(请参阅Spring Framework中的HystrixStreamAutoConfiguration和MetricExportAutoConfiguration).因此,如果您尝试在指定`@ EnableScheduling`的`@Configuration`类上使用`@ConditionalOnProperty`或`@ Profile`,那么由于外部组件,无论如何都会启用调度.请参阅/sf/answers/3274837471/ (3认同)
  • 不知何故它杀死了我的弹簧靴配置 (2认同)
  • 如果它杀死整个应用程序,请使用“@ConditionalOnProperty(value = "app.scheduling.enable", ... )”注释包含“@Scheduled”的特定bean,而不是具有“@EnableScheduling”注释的bean。 (2认同)

小智 17

使用 Spring Boot 和 cron 表达式,您可以启用或禁用调度。例如,您可以定义一个测试 application.yml 并设置

scheduler:
  cron-expr: '-'
Run Code Online (Sandbox Code Playgroud)

另请参阅使用 '-' 禁用调度。在您的调度程序类中,您可以传递表达式。

@Scheduled(cron = "${scheduler.cron-expr}")
Run Code Online (Sandbox Code Playgroud)

  • 这应该是新接受的答案;它比这里列出的其他所有东西都要好得多 (2认同)

yan*_*kee 12

另一种方法是取消注册调度事件的bean后处理器.这可以通过简单地将以下类放在测试的类路径上来完成:

public class UnregisterScheduledProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) throws BeansException {
        for (String beanName : beanFactory.getBeanNamesForType(ScheduledAnnotationBeanPostProcessor.class)) {
            ((DefaultListableBeanFactory)beanFactory).removeBeanDefinition(beanName);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然这很简单并且似乎可以完成这项工作,但要注意我没有对此进行过多测试或检查从注册表中删除已定义的bean或确保PostProcessors的排序不会成为问题的可能影响......

  • 只是为了提供一些反馈 - 我只是尝试了这种方法,它似乎工作得很好. (2认同)
  • 我已经尝试了@ vojtech-ruzicka和@lolotron的答案以及[此类似问题]的其他答案(/sf/ask/2815885621/)同样我必须补充一点,只有@yankee的答案对我有用.在他的示例`UnregisterScheduledProcessor`类中使用`@Configuration`注释,以便Spring在我的测试中自动加载它.到目前为止,我还没有遇到任何问题. (2认同)
  • 这对我来说是最好的解决方案,因为我不想仅仅为了测试而修改现有的生产代码。我只是将它作为 Spring @Component 添加到我的测试类路径中,到目前为止它正在工作,很好的解决方案! (2认同)

Sha*_*iul 9

使用@MockBean.

@RunWith(SpringRunner.class)
@SpringBootTest
@MockBean(MyScheduledClass.class)
public class MyTest {
Run Code Online (Sandbox Code Playgroud)

这最终将取代活动的预定作业或创建一个模拟作业。

从文档

模拟可以通过类型或通过 {@link #name() bean name} 注册。任何在上下文中定义的相同类型的现有单个 bean 都将被模拟替换,如果没有定义现有 bean,将添加一个新 bean。

  • 非常好,最佳答案 (2认同)
  • 这是迄今为止最好的、恕我直言最干净的答案。无论如何,我总是将调度分成一个薄的单独层(即,一个额外的 bean)来分离关注点,所以@PrasanthRajendran 评论不适用于我。 (2认同)

小智 8

我只是通过可配置的延迟时间参数化了我的@Scheduled注释:

@Scheduled(fixedRateString = "${timing.updateData}", initialDelayString = "${timing.initialDelay}")
Run Code Online (Sandbox Code Playgroud)

在我的测试application.yaml中:

timing:
    updateData: 60000
    initialDelay: 10000000000
Run Code Online (Sandbox Code Playgroud)

主要的应用程序.yaml:

timing:
    updateData: 60000
    initialDelay: 1
Run Code Online (Sandbox Code Playgroud)

它并没有关闭它,而是造成如此长的延迟,测试将在它运行之前完成.不是最优雅的解决方案,但绝对是我发现的最简单的解决方案之一.

  • 这不是一个干净的解决方案。但它确实发挥了作用。为这个不同的角度投赞成票 (2认同)

小智 5

发现添加了

app.scheduling.enable=false

在测试 application.properties 中

@ConditionalOnProperty(value = "app.scheduling.enable", havingValue = "true", matchIfMissing = true)
@EnableScheduling
Run Code Online (Sandbox Code Playgroud)

Marko Vranjkovic 的答案一样调度配置类注释适用于所有测试,而无需对每个测试进行注释!