Java

Testing Spring Boot Applications

Executive Summary

Testing Spring Boot applications mostly means ordinary JUnit 5 and Mockito. You test a service class with injected collaborators by constructing it directly and mocking its dependencies, with no container involved. Sometimes a test needs the real Spring context, including wiring, configuration, and the full bean graph. Then @SpringBootTest boots that context and lets you assert against it. Meanwhile, a narrower annotation, @WebMvcTest, boots only the web layer for controller-focused checks. Both annotations stay intentionally minimal here. After all, deep coverage of Spring’s test slices, Testcontainers-backed database tests, and detailed MockMvc assertions belongs in the Spring Boot course on this site.

What You Already Know Still Applies

A typical Spring Boot service class looks like this, and nothing about it is Spring-specific at the unit test level:

public class OrderService {
    private final OrderRepository repository;

    public OrderService(OrderRepository repository) {
        this.repository = repository;
    }

    public Order placeOrder(String sku, int quantity) {
        if (quantity <= 0) {
            throw new IllegalArgumentException("quantity must be positive");
        }
        return repository.save(new Order(sku, quantity));
    }
}

As a result, the test for this class needs no Spring annotations at all. Instead, construct the service with a mocked repository, exactly as the Mockito article teaches, and assert on the return value:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class OrderServiceTest {

    @Mock
    OrderRepository repository;

    @Test
    void placesAnOrderWithPositiveQuantity() {
        when(repository.save(any())).thenReturn(new Order("SKU-1", 3));

        var service = new OrderService(repository);
        var order = service.placeOrder("SKU-1", 3);

        assertEquals(3, order.quantity());
    }
}

Consequently, this test runs in milliseconds and loads no Spring container, because it tests Java logic, not Spring wiring. In practice, most of a healthy Spring Boot test suite looks exactly like this: plain JUnit 5 and Mockito. Only a small slice at the top needs the container. If plain unit testing or mocking feels unfamiliar, the JUnit 5 article and the Mockito article cover those fundamentals in full. So this article will not repeat them.

Testing Spring Boot Applications With the Real Context: @SpringBootTest

However, a plain unit test cannot answer some questions. Does the application context actually start? Are the beans wired correctly? Does a configuration property reach the bean that reads it? Those questions require Spring itself to run. For that reason, @SpringBootTest boots the full application context for exactly that purpose.

Here is the minimal shape, one test class that confirms the context loads and wires a bean as expected:

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.assertNotNull;

@SpringBootTest
class OrderServiceIntegrationTest {

    @Autowired
    private OrderService orderService;

    @Test
    void contextLoadsAndWiresOrderService() {
        assertNotNull(orderService);
    }
}

Running this test starts the entire Spring context the same way the application itself would. The only exception is a network listener, unless you configure one. In short, @SpringBootTest gives you confidence that wiring works. The cost is a test that takes seconds instead of milliseconds, because the container has real startup work to do.

A narrower annotation, @WebMvcTest, covers the common case of testing just the web layer. It loads only the controller infrastructure instead of the entire context. So it is worth knowing the name exists. However, its depth covers request mocking, status code assertions, and JSON body checks. That Spring MVC territory belongs with the rest of the framework’s testing support, not in a language course.

How Real Systems Do This

Production Spring Boot suites follow a pyramid. At the base sit hundreds of fast Mockito-based unit tests for business logic. Above them, a much smaller band of @SpringBootTest or slice tests covers wiring and configuration. Finally, an even smaller set of true end-to-end tests sits at the top. In my experience reviewing Spring Boot codebases, the slowest suites reach for @SpringBootTest on every test class. Instead, they should save it for the handful of cases that genuinely need the container.

Deep coverage of Spring Boot’s testing tools belongs in the Spring Boot course on this site. That includes Testcontainers for real databases in CI, @DataJpaTest and @WebMvcTest slices, and MockMvc’s full assertion API. Later, wiring that test suite into a pipeline, once you get there, follows the same CI mechanics covered in the GitHub Actions article.

Decision Framework

  1. Is the code plain Java logic with injected dependencies? Test it with JUnit 5 and Mockito, no Spring annotation needed.
  2. Do you need to confirm the application context actually starts and wires correctly? Reach for @SpringBootTest, sparingly.
  3. Are you testing only controller behavior, request mapping, and serialization? @WebMvcTest is the narrower, faster option. Its depth lives in the Spring Boot course.
  4. Does the test need a real database or external system? That is Testcontainers territory, deferred to the Spring Boot course.
  5. Is your suite slow? Count how many tests use @SpringBootTest, because that count is usually the answer.

When NOT to Use This

  • Do not reach for @SpringBootTest to test a service’s branching logic. Instead, a plain Mockito test proves the same thing in a fraction of the time.
  • Do not use @SpringBootTest as a substitute for understanding dependency injection. If the wiring fails, fix the configuration, not the test.
  • Do not try to assert detailed HTTP behavior with @SpringBootTest alone. That depth belongs to @WebMvcTest and MockMvc, which the Spring Boot course covers.

Common Mistakes

  • Annotating every test class with @SpringBootTest out of habit. That turns a fast suite into a slow one for no benefit.
  • Skipping plain Mockito tests entirely and relying only on context-loaded tests, which hides logic bugs behind a slow, broad test.
  • Forgetting that @SpringBootTest loads real configuration. So a missing property or misconfigured bean fails the test for reasons unrelated to the code under test.
  • Mixing @Mock-based unit tests and @SpringBootTest in the same class, which muddies what the test is actually verifying.
  • Assuming @WebMvcTest loads the full context, when it loads only the web layer and expects you to mock the rest.

Key Takeaways

  • You test most Spring Boot business logic with plain JUnit 5 and Mockito, as Part 7 of this course taught.
  • @SpringBootTest boots the real application context, useful for confirming wiring, at the cost of slower tests.
  • @WebMvcTest narrows the scope to the web layer, but its full usage is Spring MVC territory.
  • Overall, a healthy suite is mostly fast unit tests with a small number of context-loaded tests at the top.
  • Testcontainers, slice tests, and MockMvc depth are deliberately out of scope here. Instead, you will find them in the Spring Boot course on this site.

FAQ

Do I need Spring-specific tests for every class in a Spring Boot application?

No. Plain service and logic classes are tested with ordinary JUnit 5 and Mockito, the same way as any other Java class. Only the layer that depends on Spring’s wiring or configuration needs a Spring-aware test.

What does @SpringBootTest actually do?

It boots the full Spring application context for the test, the same context your application builds at startup. So you can verify that beans wire correctly and configuration is read as expected.

What is the difference between @SpringBootTest and @WebMvcTest?

@SpringBootTest loads the entire application context. @WebMvcTest loads only the web layer infrastructure for controller-focused tests, which makes it faster but narrower in scope.

Should I use Mockito inside a @SpringBootTest?

Yes, Spring Boot supports replacing beans with mocks inside a context-loaded test. However, that combination and its configuration details are part of the deeper Spring testing material, not this course.

Where can I learn Testcontainers and deeper Spring Boot testing?

Deep coverage of Testcontainers, test slices, and MockMvc belongs in the Spring Boot course on this site. That course builds directly on the fundamentals taught here.

Conclusion

Testing Spring Boot applications starts with skills you already have: JUnit 5 assertions and Mockito doubles applied to plain Java logic. Meanwhile, @SpringBootTest and @WebMvcTest exist for the smaller slice of tests that genuinely need the container. That is as far as this course goes on purpose.

Keep the pyramid honest. Most tests should run without Spring in the room, and the few that need it should earn that cost.

Last updated on 12 September 2026.

Share this article

Leave a Reply

Your email address will not be published. Required fields are marked *