SpringRunner vs. SpringExtension vs. @SpringBootTest

Last Updated:  March 20, 2025 | Published: March 24, 2025

Testing Spring Boot applications efficiently requires understanding the testing infrastructure Spring provides.

Three commonly used components – SpringRunner, SpringExtension, and @SpringBootTest – often cause confusion among developers. Many of us find ourselves stacking these annotations without fully grasping their distinct purposes and how they complement each other.

In this article, we’ll clarify the differences between these testing components, explore when to use each one, and demonstrate how they can work together. By the end, we’ll have a clear understanding of the Spring testing ecosystem and be able to write more effective tests for our Spring Boot applications.

The JUnit Evolution: SpringRunner vs. SpringExtension

The first point of confusion often stems from the relationship between SpringRunner and SpringExtension.

Let’s clarify this with some background and code examples.

SpringRunner – The JUnit 4 Approach

SpringRunner is a JUnit 4 test runner that bridges Spring’s testing capabilities with JUnit 4’s runner framework.

It’s an alias for SpringJUnit4ClassRunner and provides the core functionality needed to run tests that use Spring test features.

Here’s an example of a JUnit 4 test class using SpringRunner:

The @RunWith(SpringRunner.class) annotation tells JUnit 4 to use Spring’s testing support.

It’s responsible for creating the application context, enabling dependency injection, and managing test lifecycle events.

SpringExtension – The JUnit 5 Approach

With JUnit 5 (Jupiter), the extension model replaced the runner concept from JUnit 4. SpringExtension is Spring’s implementation of this new extension model, providing equivalent functionality to SpringRunner but for JUnit 5.

Here’s the same test written for JUnit 5 using SpringExtension:

The key difference is that we use @ExtendWith(SpringExtension.class) instead of @RunWith(SpringRunner.class). Both annotations fulfill the same purpose: integrating Spring’s testing infrastructure with the respective JUnit version.

Understanding @SpringBootTest

While SpringRunner and SpringExtension provide the integration between Spring and JUnit, @SpringBootTest defines what and how to test. It configures the Spring application context for our tests, loading the complete application configuration.

The @SpringBootTest annotation offers various properties to customize our test environment:

In this example:

  • We specify webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT to start the embedded server with a random port
  • We override a property with properties = {"spring.datasource.url=jdbc:h2:mem:testdb"}
  • We activate the “test” profile with @ActiveProfiles("test")

These configurations allow us to precisely control our test environment without changing our application code.

Combining the Components: Best Practices

Now that we understand each component individually, let’s explore how they work together and establish best practices for different testing scenarios.

JUnit 5 Simplified Configuration

In Spring Boot 2.2.0 and later with JUnit 5, the @SpringBootTest annotation includes @ExtendWith(SpringExtension.class) by default, allowing us to simplify our test code:

This simplified approach is recommended for JUnit 5 tests. However, if we’re using JUnit 4, we still need to explicitly include @RunWith(SpringRunner.class).

Choosing the Right Testing Scope

While @SpringBootTest loads the entire application context, sometimes we want more focused tests. Spring provides additional testing annotations for different scopes:

Web Layer Testing with MockMvc

@WebMvcTest focuses on testing the web layer only and implicitly includes SpringExtension. It’s faster than @SpringBootTest because it only loads the web-related components.

Data Layer Testing

@DataJpaTest focuses on testing JPA components, configuring an in-memory database and including only JPA-related beans. Like @WebMvcTest, it implicitly includes SpringExtension.

Summary

Understanding the differences between SpringRunner, SpringExtension, and @SpringBootTest helps us write more effective and efficient tests for our Spring Boot applications:

  • SpringRunner is for JUnit 4 and integrates Spring’s testing capabilities with JUnit’s runner model
  • SpringExtension is for JUnit 5 and provides equivalent functionality using Jupiter’s extension model
  • @SpringBootTest configures the application context for our tests and can be customized with various properties

With Spring Boot 2.2.0+ and JUnit 5, we can simplify our test classes by just using @SpringBootTest without explicitly adding @ExtendWith(SpringExtension.class). For JUnit 4, we still need @RunWith(SpringRunner.class).

By choosing the right testing scope – whether it’s a full application test with @SpringBootTest, a web layer test with @WebMvcTest, or a data layer test with @DataJpaTest – we can make our tests more focused, faster, and more maintainable.

Remember that the goal is to test our application effectively while keeping tests simple and readable. The Spring testing framework provides the tools we need to achieve this balance.

Joyful testing,

Philip

>