Integration Testing with @SpringBootTest and JUnit 5

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.

Spring boot modules

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
MOCKDefault mode where no server is started. Ideal for controller-level tests using MockMvc.
RANDOM_PORTStarts the application on a random port. Useful for avoiding conflicts during parallel testing.
DEFINED_PORTStarts the server on a predefined port specified in application.properties.
NONEPrevents 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:

AnnotationDescriptionKey Features
@WebFluxTestUsed 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.
@JdbcTestUsed for testing JDBC-based components.– Configures an embedded in-memory database.
– Configures JdbcTemplate.
– Tests are transactional and roll back at the end.
@DataMongoTestUsed for testing MongoDB components.– Uses an embedded MongoDB (if driver is available).
– Configures MongoTemplate.
– Scans @Document classes.
– Configures Spring Data MongoDB repositories.
@DataRedisTestUsed for testing Redis applications.– Scans for @RedisHash classes.
– Configures Spring Data Redis repositories.
@DataLdapTestUsed for testing LDAP applications.– Configures an in-memory LDAP (if available).
– Configures LdapTemplate.
– Scans for @Entry classes.
– Configures Spring Data LDAP repositories.
@RestClientTestUsed for testing REST clients.– Auto-configures dependencies like Jackson, GSON, and Jsonb.
– Configures RestTemplateBuilder.
– Adds support for MockRestServiceServer by default.
@JooqTestUsed 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 !!

Ref: @SpringBootTest Spring Docs

Weekly Newsletter

Stay Up-to-Date with Our Weekly Updates. Right into Your Inbox.

Comments

Subscribe
Notify of
0 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.