web-dev-qa-db-ja.com

Springテストで@EnableSchedulingを無効にする

単体テストを実行すると、スケジュールされたタスクが呼び出されます。メインのアプリ構成に@EnableSchedulingがあるために、この動作を防ぎたいと思います。

単体テストでこれを無効にするにはどうすればよいですか?

私はこれに遭遇しました question/answer これはプロファイルの設定を提案しますか?

私はそれについてどうやって行くのか分かりませんか?またはそれが過剰である場合?ユニットテスト用に個別のAppConfigurationを使用することを考えていましたが、それを行うときにコードを2回繰り返しているように感じますか?

@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

}

単体テストの例。

@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);
    }
}
42
Robbo_UK

プロファイルを使用したくない場合は、アプリケーションのスケジューリングを有効/無効にするフラグを追加できます

AppConfigurationにこれを追加してください

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

テストでは、このアノテーションを追加してスケジューリングを無効にします

@TestPropertySource(properties = "app.scheduling.enable=false")
40

別の方法は、イベントをスケジュールする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);
        }
    }
}

これは非常に単純で仕事をしているようですが、私はこれをあまりテストしていないか、レジストリから定義されたBeanを削除したり、PostProcessorの順序が問題にならないことを確認したりしないでください...

11
yankee

構成可能な遅延時間で@Scheduledアノテーションをパラメーター化しただけです。

@Scheduled(fixedRateString = "${timing.updateData}", initialDelayString = "${timing.initialDelay}")

私のテストapplication.yamlで:

timing:
    updateData: 60000
    initialDelay: 10000000000

メインのapplication.yaml:

timing:
    updateData: 60000
    initialDelay: 1

オフにするのではなく、このような長い遅延が発生するため、テストは実行前に長時間かかります。最もエレガントなソリューションではありませんが、間違いなく私が見つけた最も簡単なソリューションの1つです。

9
Laila Sharshar

各テストでは、使用するスプリング構成を定義します。現在、次のものがあります。

_@ContextConfiguration(classes={AppConfiguration.class})
_

一般的な方法は、通常のアプリケーションとテスト用に別々のスプリング構成を定義することです。

_AppConfiguration.Java 
TestConfiguration.Java
_

次に、テストでは、@ContextConfiguration(classes={TestConfiguration.class})を使用して、現在のTestConfigurationの代わりにAppConfigurationを単に参照します。

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

このようにして、本番コードとは異なる方法でテストの設定を構成できます。たとえば、通常のテストではなく、インメモリデータベースをテストに使用できます。

2
Vojtech Ruzicka

単体テスト中にスケジュールされたタスクを削除するメソッドを作成することで、この問題を解決できました。以下に例を示します。

    import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor;
    import org.springframework.context.ApplicationContext;

    public static void removeSchedulledTasks(ScheduledAnnotationBeanPostProcessor postProcessor, ApplicationContext appContext) {

    postProcessor.setApplicationContext(appContext);

    Iterator<ScheduledTask> iterator = postProcessor.getScheduledTasks().iterator();

    while(iterator.hasNext()) {

        ScheduledTask taskAtual = iterator.next();
        taskAtual.cancel();

    }

}

使用例:

import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.example.Utils;


@RunWith(SpringRunner.class)
@SpringBootTest
public class TestRemoveScheduller {


    @Autowired
    private ScheduledAnnotationBeanPostProcessor postProcessor;

    @Autowired
    private ApplicationContext appContext;


    @Before
    public void init(){

        //Some init variables

        //Remove schedulled tasks method
        Utils.removeSchedulledTasks(postProcessor, appContext);

    }

    //Some test methods

}

お役に立てれば。

1
Gladson Bruno