JUnit testing
Spring Boot
ApplicationRunner
CommandLineRunner
unit testing

Prevent Application / CommandLineRunner classes from executing during JUnit testing

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

In Spring Boot applications, the CommandLineRunner and ApplicationRunner interfaces are used to execute specific code after the application context is loaded. While these are useful for initializing data or performing any startup logic, they can be intrusive during JUnit testing as they might add overhead or complicate test scenarios. In this article, we will explore strategies to prevent these classes from executing during JUnit testing.

Understanding CommandLineRunner and ApplicationRunner

Before delving into the solutions, let's briefly explore what these interfaces do:

  • CommandLineRunner: This is a functional interface in Spring Boot used to execute code after application startup. It provides a run method that accepts an array of String arguments.
  • ApplicationRunner: Similar to CommandLineRunner, but it provides access to the ApplicationArguments interface, which gives a richer access to application arguments, including options and non-option arguments.

Example of CommandLineRunner

java
1import org.springframework.boot.CommandLineRunner;
2import org.springframework.stereotype.Component;
3
4@Component
5public class StartupRunner implements CommandLineRunner {
6    @Override
7    public void run(String... args) throws Exception {
8        System.out.println("Executing startup logic!");
9    }
10}

Why Prevent Execution During Testing?

When executing unit tests, especially those focused on specific application logic, running startup code can lead to undesired side effects such as modifying the state, making external HTTP requests, or simply making the test slower. Therefore, it's often desirable to prevent such execution during tests.

Strategies To Prevent Execution

1. Profile Based Exclusion

Use Spring Profiles to conditionally include or exclude components. By default, exclude the CommandLineRunner component in a test profile.

java
1import org.springframework.context.annotation.Profile;
2import org.springframework.stereotype.Component;
3
4@Profile("!test")
5@Component
6public class StartupRunner implements CommandLineRunner {
7    @Override
8    public void run(String... args) throws Exception {
9        System.out.println("Executing startup logic!");
10    }
11}

By activating a test profile during tests, the StartupRunner will be excluded.

2. Conditional Bean

Utilize conditional beans to selectively load beans based on the presence of specific properties or profiles.

java
1import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
2import org.springframework.stereotype.Component;
3
4@ConditionalOnProperty(name = "app.startup.runner.enabled", havingValue = "true", matchIfMissing = true)
5@Component
6public class StartupRunner implements CommandLineRunner {
7    @Override
8    public void run(String... args) throws Exception {
9        System.out.println("Executing startup logic!");
10    }
11}

You can then disable it in your application-test.properties file:

 
app.startup.runner.enabled=false

3. Mock Configuration in Test

Create a separate test configuration class that mocks or removes these components when running tests.

java
1import org.springframework.boot.test.context.TestConfiguration;
2import org.springframework.context.annotation.Bean;
3
4@TestConfiguration
5public class TestConfig {
6
7    @Bean
8    public CommandLineRunner commandLineRunner() {
9        return args -> System.out.println("Mock Runner - Does not execute startup logic.");
10    }
11}

Include this configuration in your tests:

java
1@ExtendWith(SpringExtension.class)
2@SpringBootTest
3@Import(TestConfig.class)
4public class YourTest {
5    // Test code here
6}

Summary of Key Strategies

StrategyDescriptionProsCons
Profile Based ExclusionUse a test profile to exclude startup logicSimple to implementRequires profile management
Conditional BeanConditional loading based on property configurationFlexibleAdds complexity
Mock Configuration in TestProvide alternate mock implementations during testsFine-grained controlRequires additional boilerplate

Additional Considerations

  • Efficiency: Using profiles and conditions is efficient and adds minimal overhead to your test setup.
  • Complexity Management: Too many conditions may complicate configuration management, so balance between configurability and simplicity is key.
  • Documentation: Document your configurations to ensure developers understand test configurations and bean loading logic.

Incorporating these strategies ensures that your test suites remain focused, reliable, and unaffected by non-essential startup logic. By doing so, you can achieve better isolation, making your tests faster and more meaningful.


Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.