CommandLineRunners are ordinary beans with one exception:
After the application context is loaded, spring boot finds among all its beans the beans that implement this interface and calls their run method automatically.
Now, I would like you to ask to do the following:
- Remove
ContextConfiguration from the test and place a breakpoint in constructor of MyRunner. The test should look like this:
@RunWith(SpringRunner.class) // if you're on junit 4, adjust for junit 5 if you need @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) public class MyTest { @Autowired private MyRunner myRunner; @Test public void testMe() { System.out.println("hello"); } }
- Run the test and make sure that myRunner is loaded and its
run method is called - Now mock this class with MockBean annotation:
@RunWith(SpringRunner.class) // if you're on junit 4, adjust for junit 5 if you need @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) public class MyTest { @MockBean private MyRunner myRunner; @Test public void testMe() { System.out.println("hello"); } }
Run the test. Make sure that run method is not running. Your Application Context now should contain a mock implementation of your component.
If the above works, then the problem is with TestConfig and ContextConfiguration annotation. In general when you run without ContextConfiguration you give spring boot test engine a freedom to mimic the application context started as if its a real application (with autoconfigurations, property resolution, recursive bean scanning and so forth). However if you put ContextConfiguration, spring boot test doesn't work like this - instead it only loads the beans that you've specified in that configuration. No Autoconfigurations, no recursive bean scanning happens for example.
Update
Based on OP's comment:
It looks like the MyRunner gets loaded when you put @ContextConfiguration because of component scanning. Since you have an annotation @Component placed on MyRunner class it can be discovered by Spring boot engine.
In fact there is a "dangerous" mix of two types of beans definitions here: 1. The beans defined with @Bean in @Configuration annotation 2. The beans found during component scanning.
Here is the question for you: If you don't want to mimic the application startup process and instead prefer to load only specific beans, why do you use @SpringBootTest at all? Maybe you can achieve the goal with:
@RunWith(SpringRunner.class) @ContextConfiguration(YourConfig.class) public class MyTest { ... }
MyRunnergets injected and runs like on application startup, and for whatever reason mocking that class doesn't override it.