Prevent Application / CommandLineRunner classes from executing during JUnit testing

SpringSpring Boot

Spring Problem Overview


If in your TestCase class there is this annotations:

@SpringApplicationConfiguration(classes = {Application.class})

this will cause the Application.class, implementing the CommandLineRunner interface, to run the required method

public void run(String... args) throws Exception

I still think this is, mostly, a not wanted behaviour, since in your test environment you may not want to launch the entire application.

I have in mind two solution to circumvent this problem:

  1. to remove the CommandLineRunner interface from my Application class
  2. to have a different context for testing

Both this solution requires lot of coding. Do you have a more convenient solution?

Spring Solutions


Solution 1 - Spring

Jan's solution can be achieved easier.

In your test class, activate the "test" profile:

@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("test")
public class MyFancyTest {}

In your CommandLineRunner set the profile to NOT test:

@Component
@Profile("!test")
public class JobCommandLineRunner implements CommandLineRunner {}

Then you don't have to manually set the profile in the Application.

Solution 2 - Spring

As mentioned in spring documentation http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html you can use @ContextConfiguration with a special initializer:

> ConfigFileApplicationContextInitializer is an ApplicationContextInitializer that can apply to your tests to load Spring Boot application.properties files. You can use this when you don’t need the full features provided by @SpringApplicationConfiguration.

In this example anyComponent is initialized and properties are injected, but run(args) methods won't be executed. (Application.class is my main spring entry point)

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Application.class, 
                      initializers = ConfigFileApplicationContextInitializer.class)
public class ExtractorTest {
    @Autowired
    AnyComponent anyComponent;
    
    @Test
    public void testAnyComponent() {
       anyComponent.anyMethod(anyArgument);
    }
}

Solution 3 - Spring

You can define a test configuration in the same package as your application that looks exactly the same, except that it excludes beans implementing CommandLineRunner. The key here is @ComponentScan.excludeFilters:

@Configuration
@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = CommandLineRunner.class))
@EnableAutoConfiguration
public class TestApplicationConfiguration {
}

Then, just replace the configuration on your test:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = TestApplicationConfiguration.class)
public class SomeApplicationTest {
    ...
}

No CommandLineRunner will be executed now, because they are not part of the configuration.

Solution 4 - Spring

I'm a bit late to the party, but a reasonable approach is to mark the bean with @ConditionalOnProperty, e.g.

@ConditionalOnProperty(prefix = "job.autorun", name = "enabled", havingValue = "true", matchIfMissing = true)
public CommandLineRunner myRunner() {...}

The following annotation will then disable it in tests:

@SpringBootTest(properties = {"job.autorun.enabled=false"})

Solution 5 - Spring

If you have a mocking framework installed (e.g. MockMVC) you can create a mock instance of the CommandLineRunner implementation, more or less disabling it:

@MockBean private TextProcessor myProcessor;

Solution 6 - Spring

Previous answers didn't work wor me. I ended up using different profiles - example for the init method in Spring Boot:

SpringApplication app = new SpringApplication(AppConfig.class);
app.setAdditionalProfiles("production");
app.run(args);

This is not executed during the tests so we're safe here.

All tests have their own profile "test" (which is useful in many other ways, too):

@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("test")
public class MyFancyTest {}

The command-line runner is annotated with the "production" profile so the tests ignore it:

@Component
@Profile("production")
public class JobCommandLineRunner implements CommandLineRunner {}

Solution 7 - Spring

I solve this by not implementing CommandLineRunner. Just get a bean from the context, and call a method on it, passing argv. That way you will get the same result, and the application won't start automatically when running the tests.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGorgia666View Question on Stackoverflow
Solution 1 - SpringMichael P.View Answer on Stackoverflow
Solution 2 - SpringjmgonetView Answer on Stackoverflow
Solution 3 - SpringBogdan CalmacView Answer on Stackoverflow
Solution 4 - SpringjihorView Answer on Stackoverflow
Solution 5 - SpringMcAvitiView Answer on Stackoverflow
Solution 6 - SpringJan PetzoldView Answer on Stackoverflow
Solution 7 - SpringDaniView Answer on Stackoverflow