単体テストを実行すると、スケジュールされたタスクが呼び出されます。メインのアプリ構成に@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);
}
}
プロファイルを使用したくない場合は、アプリケーションのスケジューリングを有効/無効にするフラグを追加できます
AppConfiguration
にこれを追加してください
@ConditionalOnProperty(
value = "app.scheduling.enable", havingValue = "true", matchIfMissing = true
)
@Configuration
@EnableScheduling
public static class SchedulingConfiguration {
}
テストでは、このアノテーションを追加してスケジューリングを無効にします
@TestPropertySource(properties = "app.scheduling.enable=false")
別の方法は、イベントをスケジュールする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の順序が問題にならないことを確認したりしないでください...
構成可能な遅延時間で@Scheduledアノテーションをパラメーター化しただけです。
@Scheduled(fixedRateString = "${timing.updateData}", initialDelayString = "${timing.initialDelay}")
私のテストapplication.yamlで:
timing:
updateData: 60000
initialDelay: 10000000000
メインのapplication.yaml:
timing:
updateData: 60000
initialDelay: 1
オフにするのではなく、このような長い遅延が発生するため、テストは実行前に長時間かかります。最もエレガントなソリューションではありませんが、間違いなく私が見つけた最も簡単なソリューションの1つです。
各テストでは、使用するスプリング構成を定義します。現在、次のものがあります。
_@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
_
このようにして、本番コードとは異なる方法でテストの設定を構成できます。たとえば、通常のテストではなく、インメモリデータベースをテストに使用できます。
単体テスト中にスケジュールされたタスクを削除するメソッドを作成することで、この問題を解決できました。以下に例を示します。
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
}
お役に立てれば。