1. 概要

このチュートリアルでは、ApplicationRunnerまたはCommandLineRunnerのタイプのBeanがSpring Boot統合テスト中に実行されないようにする方法を示します。

2. アプリケーション例

サンプルアプリケーションは、コマンドラインランナー、アプリケーションランナー、およびタスクサービスBeanで構成されています。

コマンドラインランナーは、アプリケーションの起動時にタスクを実行するために、タスクサービスのexecuteメソッドを呼び出します。

@Component
public class CommandLineTaskExecutor implements CommandLineRunner {
    private TaskService taskService;

    public CommandLineTaskExecutor(TaskService taskService) {
        this.taskService = taskService;
    }

    @Override
    public void run(String... args) throws Exception {
        taskService.execute("command line runner task");
    }
}

同様に、アプリケーションランナーはタスクサービスと対話して別のタスクを実行します。

@Component
public class ApplicationRunnerTaskExecutor implements ApplicationRunner {
    private TaskService taskService;

    public ApplicationRunnerTaskExecutor(TaskService taskService) {
        this.taskService = taskService;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        taskService.execute("application runner task");
    }
}

最後に、タスクサービスは、クライアントのタスクを実行する責任があります。

@Service
public class TaskService {
    private static Logger logger = LoggerFactory.getLogger(TaskService.class);

    public void execute(String task) {
        logger.info("do " + task);
    }
}

また、すべてを機能させるSpring Bootアプリケーションクラスもあります。

@SpringBootApplication
public class ApplicationCommandLineRunnerApp {
    public static void main(String[] args) {
        SpringApplication.run(ApplicationCommandLineRunnerApp.class, args);
    }
}

3. 期待される動作のテスト

ApplicationRunnerTaskExecutorおよびCommandLineTaskExecutorは、SpringBootがアプリケーションコンテキストをロードした後に実行されます。

これは簡単なテストで確認できます。

@SpringBootTest
class RunApplicationIntegrationTest {
    @SpyBean
    ApplicationRunnerTaskExecutor applicationRunnerTaskExecutor;
    @SpyBean
    CommandLineTaskExecutor commandLineTaskExecutor;

    @Test
    void whenContextLoads_thenRunnersRun() throws Exception {
        verify(applicationRunnerTaskExecutor, times(1)).run(any());
        verify(commandLineTaskExecutor, times(1)).run(any());
    }
}

ご覧のとおり、 SpyBean アノテーションを使用して、 MockitospiesApplicationRunnerTaskExecutorおよびCommandLineTaskExecutorBeanに適用しています。 そうすることで、これらの各Beanのrunメソッドが1回呼び出されたことを確認できます。

次のセクションでは、SpringBoot統合テスト中にこのデフォルトの動作を防ぐためのさまざまな方法と手法について説明します。

4. スプリングプロファイルによる防止

これら2つが実行されないようにする方法の1つは、@Profileで注釈を付けることです。

@Profile("!test")
@Component
public class CommandLineTaskExecutor implements CommandLineRunner {
    // same as before
}
@Profile("!test")
@Component
public class ApplicationRunnerTaskExecutor implements ApplicationRunner {
    // same as before
}

上記の変更後、統合テストに進みます。

@ActiveProfiles("test")
@SpringBootTest
class RunApplicationWithTestProfileIntegrationTest {
    @Autowired
    private ApplicationContext context;

    @Test
    void whenContextLoads_thenRunnersAreNotLoaded() {
        assertNotNull(context.getBean(TaskService.class));
        assertThrows(NoSuchBeanDefinitionException.class, 
          () -> context.getBean(CommandLineTaskExecutor.class), 
          "CommandLineRunner should not be loaded during this integration test");
        assertThrows(NoSuchBeanDefinitionException.class, 
          () -> context.getBean(ApplicationRunnerTaskExecutor.class), 
          "ApplicationRunner should not be loaded during this integration test");
    }
}

ご覧のとおり、上記のテストクラスに@ActiveProfiles( “test”)アノテーションを付けました。つまり、@ Profile( “!test”)でアノテーションを付けたものはワイヤリングされません。結果として、どちらも CommandLineTaskExecutorBeanもApplicationRunnerTaskExecutorBeanもまったくロードされていません。

5. ConditionalOnPropertyアノテーションによる防止

または、プロパティごとに配線を構成してから、ConditionalOnPropertyアノテーションを使用することもできます。

@ConditionalOnProperty(
  prefix = "application.runner", 
  value = "enabled", 
  havingValue = "true", 
  matchIfMissing = true)
@Component
public class ApplicationRunnerTaskExecutor implements ApplicationRunner {
    // same as before
}
@ConditionalOnProperty(
  prefix = "command.line.runner", 
  value = "enabled", 
  havingValue = "true", 
  matchIfMissing = true)
@Component
public class CommandLineTaskExecutor implements CommandLineRunner {
    // same as before
}

ご覧のとおり、ApplicationRunnerTaskExecutorとCommandLineTaskExecutorはデフォルトで有効になっています。次のプロパティをfalseに設定すると、これらを無効にできます。

  • command.line.runner.enabled
  • application.runner.enabled

したがって、このテストでは、これらのプロパティをfalseに設定し、ApplicationRunnerTaskExecutorBeanもCommandLineTaskExecutorBeanもアプリケーションコンテキストにロードされません

@SpringBootTest(properties = { 
  "command.line.runner.enabled=false", 
  "application.runner.enabled=false" })
class RunApplicationWithTestPropertiesIntegrationTest {
    // same as before
}

さて、上記のテクニックは私たちの目標を達成するのに役立ちますが、すべてのSpringBeanが正しくロードおよび配線されていることをテストしたい場合があります。

たとえば、 TaskService beanがCommandLineTaskExecutor、に正しく注入されていることをテストしたいが、それでもrunメソッドを実行したくない場合があります。テスト中。  それでは、それを実現する方法を説明する最後のセクションを見てみましょう。

6. コンテナ全体をブートストラップしないことによる防止

ここでは、アプリケーションコンテナ全体をブートストラップしないことで、CommandLineTaskExecutorおよびApplicationRunnerTaskExecutorBeanが実行されないようにする方法について説明します。

前のセクションでは、 @SpringBootTest アノテーションを使用しました。これにより、統合テスト中にコンテナー全体がブートストラップされました。 @SpringBootTest には、この最後のソリューションに関連する2つのメタアノテーションが含まれています。

@BootstrapWith(SpringBootTestContextBootstrapper.class)
@ExtendWith(SpringExtension.class)

テスト中にコンテナ全体をブートストラップする必要がない場合は、@BootstrapWithを使用しないでください。

代わりに、それを@ContextConfigurationに置き換えることができます。

@ContextConfiguration(classes = {ApplicationCommandLineRunnerApp.class},
  initializers = ConfigDataApplicationContextInitializer.class)

@ContextConfigurationを使用して、統合テスト用のアプリケーションコンテキストをロードおよび構成する方法を決定します。 ContextConfigurationクラスプロパティを設定することにより、SpringBootがApplicationCommandLineRunnerAppクラスを使用してアプリケーションコンテキストをロードする必要があることを宣言します。 イニシャライザをConfigDataApplicationContextInitializerとして定義することにより、アプリケーションはそのプロパティをロードします。

Spring TestContextFrameworkをJUnit5のJupiterプログラミングモデルに統合するため、 @ExtendWith(SpringExtension.class)が必要です。

上記の結果として、 Spring Bootアプリケーションコンテキストは、CommandLineTaskExecutorまたはApplicationRunnerTaskExecutor Beans:を実行せずに、アプリケーションのコンポーネントとプロパティをロードします。

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = { ApplicationCommandLineRunnerApp.class }, 
  initializers = ConfigDataApplicationContextInitializer.class)
public class LoadSpringContextIntegrationTest {
    @SpyBean
    TaskService taskService;

    @SpyBean
    CommandLineRunner commandLineRunner;

    @SpyBean
    ApplicationRunner applicationRunner;

    @Test
    void whenContextLoads_thenRunnersDoNotRun() throws Exception {
        assertNotNull(taskService);
        assertNotNull(commandLineRunner);
        assertNotNull(applicationRunner);

        verify(taskService, times(0)).execute(any());
        verify(commandLineRunner, times(0)).run(any());
        verify(applicationRunner, times(0)).run(any());
    }
}

また、私たちはそれを覚えておく必要があります ConfigDataApplicationContextInitializerを単独で使用する場合、@ Value(“ $ {…}”)インジェクションはサポートされません。 それをサポートしたい場合は、を構成する必要があります PropertySourcesPlaceholderConfigurer

7. 結論

この記事では、SpringBoot統合テスト中にApplicationRunnerおよびCommandLineRunnerBeanの実行を防ぐさまざまな方法を示しました。

いつものように、コードはGitHubから入手できます。