春季最高

通过参考资料,开始使用Spring 5和Spring Boot 2学习的春天课程:

> >学习春天

1.概述

在本教程中,我们将展示如何防止类型为ApplicationRunnerCommandLineRunner在Spring Boot集成测试期间运行。

2.示例应用程序

我们的示例应用程序由命令行运行程序、应用程序运行程序和任务服务bean组成。

命令行运行程序调用任务服务的执行方法,以便在应用程序启动时执行任务:

@Component public class CommandLineTaskExecutor implements CommandLineRunner {private TaskService TaskService;public CommandLineTaskExecutor(TaskService TaskService) {this。taskService = taskService;} @Override public void run(String…taskService. args)抛出异常。执行(“命令行运行器任务”);}}

以同样的方式,应用程序运行程序与任务服务交互以执行另一个任务:

@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。执行(“应用程序跑任务”);}}

最后,任务服务负责执行客户端的任务:

@Service public class TaskService {private static Logger Logger = LoggerFactory.getLogger(TaskService.class);public void execute(String task) {log .info("do " + task);}}

而且,我们也有一个Spring Boot应用程序类,使它所有工作:

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

3.测试预期行为

ApplicationRunnerTaskExecutorCommandLineTaskExecutor在Spring Boot加载应用程序上下文后运行。

我们可以用一个简单的测试来验证这一点:

@SpringBootTest class RunApplicationIntegrationTest {@SpyBean ApplicationRunnerTaskExecutor ApplicationRunnerTaskExecutor;@SpyBean CommandLineTaskExecutor CommandLineTaskExecutor;@Test void whenContextLoads_thenRunnersRun() throws Exception {verify(applicationRunnerTaskExecutor, times(1)).run(any());验证(commandLineTaskExecutor,乘以(1).run (());}}

如我们所见,我们使用SpyBean注释应用5间谍ApplicationRunnerTaskExecutorCommandLineTaskExecutorbean。通过这样做,我们可以验证运行每个豆子的方法被调用一次。

在下一节中,我们将看到在Spring Boot集成测试期间防止这种默认行为的各种方法和技术。

4.通过Spring配置文件的预防

阻止这两个程序运行的一种方法是用@Profile:

@Profile("!test") @Component public class CommandLineTaskExecutor implements CommandLineRunner{//和前面一样}
@Profile("!test") @Component public class ApplicationRunnerTaskExecutor implements ApplicationRunner{//和前面一样}

在进行了上述修改之后,我们继续进行集成测试:

@ActiveProfiles("test") @SpringBootTest class RunApplicationWithTestProfileIntegrationTest {@Autowired private ApplicationContext context;@Test void whenContextLoads_thenRunnersAreNotLoaded() {assertnotull (context.getBean(TaskService.class));assertThrows(NoSuchBeanDefinitionException.class, () -> context.getBean(CommandLineTaskExecutor.class), "CommandLineRunner不应该被加载在这个集成测试");assertThrows(NoSuchBeanDefinitionException.class, () -> context.getBean(ApplicationRunnerTaskExecutor.class), "ApplicationRunner不应该在这个集成测试期间被加载");}}

正如我们看到的,我们将上面的测试类注释为@ActiveProfiles(“测试”)注释,这意味着它不会连接那些被注释的对象@Profile(“!测试”)结果,两者都没有CommandLineTaskExecutor豆也ApplicationRunnerTaskExecutor豆子是装载的。

5.预防通过ConditionalOnProperty注释

或者,我们可以通过属性配置它们的连接,然后使用ConditionalOnProperty注释:

@ConditionalOnProperty(prefix = "application.runner", value = "enabled", havingValue = "true", matchIfMissing = true)
@ConditionalOnProperty(prefix = "command.line.runner", value = "enabled", havingValue = "true", matchIfMissing = true) @Component public class CommandLineTaskExecutor implements CommandLineRunner{//和前面一样}

正如我们看到的,ApplicationRunnerTaskExecutorCommandLineTaskExecutor默认启用,我们可以禁用它们,如果我们设置以下属性:

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

在我们的测试中,我们将这些属性设置为,既不ApplicationRunnerTaskExecutor也没有CommandLineTaskExecutorbean被加载到应用程序上下文中:

@SpringBootTest(properties = {"command.line.runner.enabled=false", "application.runner.enabled=false"}) class RunApplicationWithTestPropertiesIntegrationTest{//与之前相同}

现在,尽管上述技术帮助我们实现了我们的目标,但在某些情况下,我们希望测试所有Spring bean都已正确加载和连接。

例如,我们可能想要测试TaskService正确地将Bean注入CommandLineTaskExecutor,但我们仍然不想要它运行方法在我们的测试期间执行。所以,让我们看看最后一节,它解释了我们如何实现这一点。

6.通过不引导整个容器来预防

在这里,我们将描述如何预防CommandLineTaskExecutorApplicationRunnerTaskExecutor通过不引导整个应用程序容器来执行bean。

在前几节中,我们使用@SpringBootTest注释,这导致在集成测试期间启动整个容器。@SpringBootTest包括两个元注释与最后一个解决方案相关的:

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

好吧,如果在我们的测试期间不需要引导整个容器,那么就不希望使用@BootstrapWith

相反,我们可以用@ContextConfiguration:

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

@ContextConfiguration,我们决定如何为集成测试加载和配置应用程序上下文。通过设置ContextConfiguration属性时,我们声明Spring Boot应该使用ApplicationCommandLineRunnerApp类装入应用程序上下文。通过将初始化式定义为ConfigDataApplicationContextInitializer,应用程序加载其属性

我们仍然需要@ExtendWith (SpringExtension.class)因为它将Spring TestContext框架集成到JUnit 5的Jupiter编程模型中。

由于上述原因,Spring Boot应用程序上下文加载应用程序的组件和属性,而不执行CommandLineTaskExecutor或者是ApplicationRunnerTaskExecutor豆:

@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = {ApplicationCommandLineRunnerApp.class}, initializers = ConfigDataApplicationContextInitializer.class)公共类LoadSpringContextIntegrationTest {@SpyBean TaskService TaskService;@SpyBean CommandLineRunner CommandLineRunner;@SpyBean ApplicationRunner ApplicationRunner;@Test void whenContextLoads_thenRunnersDoNotRun() throws Exception {assertNotNull(taskService);assertNotNull (commandLineRunner);assertNotNull (applicationRunner);验证(taskService,乘以(0)). execute (());验证(commandLineRunner,乘以(0)).run (());验证(applicationRunner,乘以(0)).run (());}}

同时,我们必须记住这一点ConfigDataApplicationContextInitializer,当单独使用时,不提供支持@ value (“${...}”)注入。如果我们想要支持它,我们必须配置一个PropertySourcesPlaceholderConfigurer

7.结论

在本文中,我们展示了防止执行ApplicationRunnerCommandLineRunnerSpring Boot集成测试期间的bean。

与往常一样,代码是可用的在GitHub

春天底

开始使用Spring 5和Spring Boot 2,通过学习的春天课程:

> >这门课程
对这篇文章的评论关闭!