Integrating Spring Boot With JUnit 5 For Reliable Testing
A well-tested Spring Boot application gives development teams confidence when adding features, changing database mappings, or connecting external services. JUnit 5 provides the modern testing platform, while Spring Boot supplies focused test slices and application context support for checking individual classes and complete request flows.
For Australian teams, this matters when an application handles GST calculations, Australian postcodes, local payment providers, or customers across Sydney, Melbourne, Perth and Brisbane. A dependable test suite helps prevent small changes from becoming production incidents during a busy release cycle or an after-hours deployment.
Configure JUnit 5 In A Spring Boot Project
Spring Boot projects created with Maven generally include spring-boot-starter-test, which brings JUnit Jupiter, Mockito, AssertJ and Spring’s testing utilities into the test classpath.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
A basic unit test does not need to start Spring. Use JUnit 5 with Mockito to test business logic quickly and isolate dependencies such as repositories or REST clients.
@ExtendWith(MockitoExtension.class)
class InvoiceServiceTest {
@Mock
private InvoiceRepository repository;
@InjectMocks
private InvoiceService service;
@Test
void calculatesGstForAustralianInvoice() {
Invoice invoice = service.createInvoice(new BigDecimal("110.00"));
assertThat(invoice.gst()).isEqualByComparingTo("10.00");
}
}
Write Focused Unit Tests With Jupiter
JUnit 5 supports readable lifecycle methods, parameterised tests, nested test classes and clear assertions. @BeforeEach is useful for common setup, while @DisplayName can make CI reports easier to understand when a build runs overnight in AEST.
Parameterised tests are particularly useful for validation rules. An Australian application might accept a six-digit postcode but reject values outside the expected range.
@ParameterizedTest
@ValueSource(strings = {"2000", "3000", "4000", "6000"})
void acceptsAustralianPostcodes(String postcode) {
assertThat(postcodeValidator.isValid(postcode)).isTrue();
}
Keep unit tests independent from the Spring container where possible. Mock external systems such as Australia Post, Tyro Payments or an authentication provider, then verify the interaction and the returned business result. This keeps feedback fast for developers working from Sydney to Perth, where time-zone differences can make long feedback cycles especially inconvenient.
Use Spring Boot Test Slices For Integration Checks
Integration tests should load the smallest realistic part of the application. @WebMvcTest is designed for controllers and MVC configuration, while @DataJpaTest focuses on repositories, entity mappings and database queries.
@WebMvcTest(OrderController.class)
class OrderControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private OrderService orderService;
@Test
void returnsOrderForAuthenticatedCustomer() throws Exception {
mockMvc.perform(get("/api/orders/42")
.with(user("customer@example.com")))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(42));
}
}
For a full application context, use @SpringBootTest. Add @AutoConfigureMockMvc when testing HTTP endpoints without starting a real server. This approach checks component scanning, security configuration, serialisation, validation and service wiring together.
Test Databases Transactions And External APIs
A repository integration test should use a database environment that resembles production. H2 can be convenient, but PostgreSQL or MySQL through Testcontainers often exposes differences in SQL syntax, indexes and transaction behaviour before deployment.
@DataJpaTest commonly wraps each test in a transaction and rolls it back afterwards. That makes tests isolated, although explicit cleanup may still be required for asynchronous jobs or database features that operate outside the test transaction.
External APIs require a different boundary. Use WireMock or MockWebServer to return successful responses, timeouts and malformed payloads. For an Australian checkout flow, test GST-inclusive prices, Australian Eastern and Western time zones, failed card authorisation and payment callbacks from a provider such as Afterpay or Tyro without contacting the live service.
Organise A Maintainable Test Strategy
A practical test suite has many fast unit tests, a smaller set of Spring slice tests and a limited number of full integration tests. Name methods according to behaviour, such as rejectsExpiredRefreshToken or storesOrderWithGstAmount, rather than implementation details.
Use profiles and test properties to keep credentials out of source control. A test profile can replace real email, payment and identity services with local fakes. It is also useful for applications that must meet Australian Privacy Act expectations, because test data should avoid real customer names, addresses and Medicare or identity details.
Testing Practices Worth Applying
- Use
@ExtendWith(MockitoExtension.class)for isolated service and domain tests. - Prefer
@WebMvcTestand@DataJpaTestbefore reaching for@SpringBootTest. - Cover Australian formats such as postcodes,
dd/MM/yyyydates, GST and AUD currency. - Run database integration tests with Testcontainers when production uses a specific database engine.
- Mock payment gateways, email providers and authentication services at the network boundary.
- Execute tests in CI on every pull request and record failures with enough context to reproduce them.
JUnit 5 and Spring Boot work best when each test has a clear responsibility. Unit tests protect business rules, slice tests verify framework integration, and full integration tests confirm that the application behaves correctly across controllers, services, persistence and security. This layered approach supports reliable releases for Australian products, whether the team is building a Melbourne booking platform, a Brisbane online store or a national SaaS service.