@WebMvcTest中排除Bean:主类依赖MyService时的测试简化问询
@MockBean for MyService When Using @WebMvcTest Problem Context
You have a main application class that implements CommandLineRunner and injects MyService:
@SpringBootApplication public class MyMain implements CommandLineRunner { @Autowired private MyService myService; public static void main(String[] args) { SpringApplication.run(MyMain.class, args); } @Override public void run(String... args) { myService.doSomething(); } }
When testing your @RestController classes with @WebMvcTest, you're forced to add @MockBean private MyService myService; to every test class because Spring tries to initialize MyMain (and its dependencies) as part of the test context.
Solution 1: Separate CommandLineRunner Logic from the Main Class (Best Practice)
The cleanest approach is to move the startup logic into a dedicated CommandLineRunner bean instead of attaching it to your main application class. This keeps your main class lean and ensures @WebMvcTest doesn't pull in unnecessary dependencies.
Updated Main Class:
@SpringBootApplication public class MyMain { public static void main(String[] args) { SpringApplication.run(MyMain.class, args); } }
New Dedicated CommandLineRunner Bean:
@Component public class MyStartupRunner implements CommandLineRunner { @Autowired private MyService myService; @Override public void run(String... args) { myService.doSomething(); } }
By default, @WebMvcTest doesn't load CommandLineRunner beans, so your controller tests won't require a mock for MyService anymore.
Solution 2: Exclude Unneeded Beans Directly in @WebMvcTest
If you prefer to keep the CommandLineRunner in your main class, you can use the excludeFilters attribute of @WebMvcTest to exclude either the main class itself or all CommandLineRunner implementations.
Option A: Exclude the Main Class
@WebMvcTest( controllers = YourRestController.class, excludeFilters = @ComponentScan.Filter( type = FilterType.ASSIGNABLE_TYPE, classes = MyMain.class ) ) public class YourRestControllerTest { // Your test code here, no need for @MockBean(MyService.class) }
Option B: Exclude All CommandLineRunner Beans
@WebMvcTest( controllers = YourRestController.class, excludeFilters = @ComponentScan.Filter( type = FilterType.ASSIGNABLE_TYPE, classes = CommandLineRunner.class ) ) public class YourRestControllerTest { // Your test code here }
Note: This will exclude all CommandLineRunner beans in your application, so use this only if you don't need any of them loaded during controller tests.
Why This Works
@WebMvcTest is designed to load only the beans required for testing Spring MVC controllers (like @RestController, @ControllerAdvice, etc.). However, since your main class is annotated with @SpringBootApplication, it's scanned by default, and its dependencies (like MyService) are pulled into the test context. By either separating the startup logic or excluding the problematic bean, you prevent that dependency from being required in your controller tests.
内容的提问来源于stack exchange,提问作者Iker Aguayo

