The @SpringBootTest annotation in Spring Boot allows us to create integration tests by loading the entire application context. It acts as a bridge between the application configuration and the test framework so that tests can verify the behavior of your application in an environment similar to production.
Unlike unit testing, which isolates individual components, @SpringBootTest enables integration testing to ensure that the interaction between components is working as expected.
1. @SpringBootTest Annotation
By default, @SpringBootTest loads the entire Spring context, including configurations, beans, and dependencies. This ensures that the application behaves as it would in a production-like environment. We can fine-tune the context loading using profiles or specific configurations (e.g., application-test.yml for integration testing).
The @SpringBootTest annotation provides the following features over and above the regular Spring TestContext provided by ‘@ContextConfiguration(classes=…)‘ annotation in spring-test.
- Automatically searches for a @SpringBootConfiguration when nested @Configuration class is not used, and no explicit classes are specified.
- Allows custom environment properties to be defined using the properties attribute.
- Provides support for different webEnvironment modes, including the ability to start a fully running web server listening on a defined or random port.
- Registers a TestRestTemplate and/or WebTestClient bean for use in web tests using a fully running web server.
1.1. Using the webEnvironment Attribute
The webEnvironment attribute controls the type of web environment used during testing. It determines whether a full-fledged web server is started or if a mock environment is used.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
The webEnvironment environment supports the following four values:
Attribute | Description |
---|---|
MOCK | Default mode where no server is started. Ideal for controller-level tests using MockMvc. |
RANDOM_PORT | Starts the application on a random port. Useful for avoiding conflicts during parallel testing. |
DEFINED_PORT | Starts the server on a predefined port specified in application.properties. |
NONE | Prevents the server and web context from starting. Used for non-web application (e.g., batch processing or messaging systems) tests. |
1.2. Managing Database State During Tests
When testing with real databases, use @Transactional to ensure each test starts with a clean slate. This annotation rolls back database changes after each test, preventing interference between tests.
In the following example, the @Transactional on test methods will cause the transaction to be rolled back after the test is complete. This ensures that the database remains in the same state before the test execution.
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@Transactional
public class MyServiceTest {
@Autowired
private MyService myService;
@Test
public void testMyServiceMethod() {
// ... your test logic ...
myService.doSomething();
// ... assertions ...
}
}
If we need to perform database setup for the tests (e.g., inserting test data), we might need to consider using @BeforeEach or @BeforeAll methods with @Transactional disabled to avoid rollbacks that would interfere with subsequent tests.
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class MyServiceTest {
@Autowired
private MyService myService;
@Autowired
private MyRepository myRepository;
@BeforeEach
public void setUp() {
myRepository.save(new MyEntity());
}
@Test
@Transactional
public void testMyServiceMethod() {
// ... your test logic ...
myService.doSomething();
// ... assertions ...
}
}
2. Using @SpringBootTest
Under the hood, @SpringBootTest tries to mimic the processes added by the Spring Boot framework for creating the context, e.g., it decides what to scan based on package structures, loads external configurations from predefined locations, optionally runs auto-configuration starters, and so on.
As we can see, @SpringBootTest annotation starts and configures almost the whole application before the test begins. We should use @SpringBootTest to write integration tests that use the application processes and external dependencies.
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class SpringBootDemoApplicationTests
{
@LocalServerPort
int randomServerPort;
//---- tests -----
}
2.1. Testing a REST API Endpoint with @SpringBootTest
The following code demonstrates a simple JUnit 5 test to test a REST API.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ApiIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void testGetEndpoint() {
ResponseEntity<String> response = restTemplate.getForEntity("/api/items", String.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
}
}
2.2. Testing a Service Layer with Mock Dependencies
The following code demonstrates a simple test for a service class with mocked dependencies.
@SpringBootTest
class ServiceLayerTest {
@MockBean
private SomeRepository repository;
@Autowired
private SomeService service;
@Test
void testServiceMethod() {
when(repository.findById(1L)).thenReturn(Optional.of(new Item("Mock Item")));
Item result = service.getItemById(1L);
assertEquals("Mock Item", result.getName());
}
}
2.3. Testing Data Persistence with an Embedded Database
The following code demonstrates a simple test for a repository class that interacts with a real database.
@SpringBootTest
class RepositoryTest {
@Autowired
private ItemRepository repository;
@Test
@Transactional
void testSaveAndFind() {
Item item = repository.save(new Item("Test Item"));
Optional<Item> fetchedItem = repository.findById(item.getId());
assertTrue(fetchedItem.isPresent());
assertEquals("Test Item", fetchedItem.get().getName());
}
}
3. Loading Application Context Partially
By default, @SpringBootTest annotation loads the whole application, but it is better to limit application context only to a set of spring components that participate in the test scenario.
3.1. Using classes Attribute
The ‘classes‘ attribute specifies the annotated classes to use for loading an ApplicationContext.
@SpringBootTest(classes = {EmployeeRepository.class, EmployeeService.class})
public class SpringBootDemoApplicationTests {
@Autowired
private EmployeeService employeeService;
//---- tests -----
}
3.2. Test Slice Annotations
If we are writing unit tests, then it’s always better not to use @SpringBootTest annotation. Rather, use the specialized spring boot test annotations, which test a particular slice of the application.
These annotations disable full auto-configuration and instead apply only configuration relevant to specific layers of the codebase.
Some of these annotations are given below:
Annotation | Description | Key Features |
---|---|---|
@WebFluxTest | Used for typical Spring WebFlux tests, focusing only on Spring WebFlux components. | – Works with @RunWith(SpringRunner.class). – Auto-configures a WebTestClient. – Excludes other Spring components for focused testing. |
@JdbcTest | Used for testing JDBC-based components. | – Configures an embedded in-memory database. – Configures JdbcTemplate. – Tests are transactional and roll back at the end. |
@DataMongoTest | Used for testing MongoDB components. | – Uses an embedded MongoDB (if driver is available). – Configures MongoTemplate. – Scans @Document classes. – Configures Spring Data MongoDB repositories. |
@DataRedisTest | Used for testing Redis applications. | – Scans for @RedisHash classes. – Configures Spring Data Redis repositories. |
@DataLdapTest | Used for testing LDAP applications. | – Configures an in-memory LDAP (if available). – Configures LdapTemplate. – Scans for @Entry classes. – Configures Spring Data LDAP repositories. |
@RestClientTest | Used for testing REST clients. | – Auto-configures dependencies like Jackson, GSON, and Jsonb. – Configures RestTemplateBuilder. – Adds support for MockRestServiceServer by default. |
@JooqTest | Used for testing jOOQ-based components. | – Specifically designed for testing jOOQ components. – Scans and configures relevant jOOQ-related beans. |
4. Conclusion
As discussed above, use the @SpringBootTest annotation for writing the integration tests in a spring boot application. By default, it scans and loads the whole application context and all spring boot-related auto-configurations.
If we are targeting to write unit tests and want to test few specific sections of the application, we shall use the specialized ‘*…Test’ annotations as discussed later in the tutorial.
Drop me your questions about how to do integration testing in Spring Boot in the comments.
Happy Learning !!
Comments