Lesson 16 / 25
Pitfall: Beans Declared on the Main Class
Why the first test run failed.
Slices still load the main configuration class
Test slices use the @SpringBootApplication class as their configuration, so @Bean methods declared on it are loaded in every slice. In the first version of the demo, a CommandLineRunner @Bean that seeded data lived in the main class: the web slice failed to start (no repository bean exists in a web slice) and the repository test saw the three seeded products in addition to its own. Moving the seeder into its own @Component, which slices filter out, fixed both: all 4 tests passed. Keep the main class minimal.
The first test run, before the fix
I ran mvn test on the first version; these lines are copied from that run (trimmed).
mvn test
Output:
[ERROR] ProductRepositoryTest.derivedQueryFiltersAndSorts:22 Expecting actual: ["Notebook", "Notebook", "Fountain pen", "Pen"] to contain exactly (and in same order): ["Notebook", "Pen"] [ERROR] ProductControllerTest.returnsProduct » IllegalState Failed to load ApplicationContext ... [ERROR] Tests run: 4, Failures: 1, Errors: 3, Skipped: 0
The fix: a separate seeding component
This file is from a demo "shop" service generated by start.spring.io for Spring Boot 4.1.1 and Java 21 (Temurin 21.0.12), built with Maven 3.9.16; the project compiled and its tests passed. The seeder is now a @Component implementing CommandLineRunner; slices exclude it.
package com.example.shop;
import java.math.BigDecimal;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component // a separate component, so test slices such as @WebMvcTest do not load it
public class DataSeeder implements CommandLineRunner {
private final ProductRepository repo;
public DataSeeder(ProductRepository repo) {
this.repo = repo;
}
@Override
public void run(String... args) {
repo.save(new Product("Notebook", new BigDecimal("120.00")));
repo.save(new Product("Fountain pen", new BigDecimal("899.00")));
repo.save(new Product("Desk lamp", new BigDecimal("1499.00")));
}
}Quick check: Why did moving the seeder out of the main class fix the slice tests?
- The main class cannot have methods
- Components run faster
- Slices load @Bean methods on the main class but filter out ordinary @Component classes
- CommandLineRunner is deprecated
Answer
Slices load @Bean methods on the main class but filter out ordinary @Component classes — Keep the @SpringBootApplication class minimal.