SpringBootTest Vs WebMvcTest DataJpaTest service unit tests, what is the best?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
There is no single "best" Spring Boot test annotation for every case. The right choice depends on which layer you want to verify and how much of the application context you actually need.
Use @SpringBootTest for Full Integration
@SpringBootTest starts a full Spring application context. That makes it the broadest and heaviest option. Use it when the behavior depends on multiple layers working together, such as controllers, services, repositories, configuration, and external integrations.
This style gives realistic coverage, but it is slower because Spring builds most of the app. If every test uses @SpringBootTest, your suite becomes expensive and harder to maintain.
Use @WebMvcTest for Controller Behavior
@WebMvcTest loads the MVC layer, not the full app. It is designed for controller testing: request mapping, validation, serialization, status codes, and response bodies.
This test is faster because it isolates the web layer. The service is mocked, so the test tells you whether the controller behaves correctly, not whether the whole system works end to end.
Use @DataJpaTest for Repositories
@DataJpaTest focuses on persistence. It configures JPA components and usually runs with an embedded database unless you override that behavior.
This is the right place to test custom queries, entity mappings, and repository behavior. It is much narrower than @SpringBootTest, which is why it is usually faster and easier to debug.
Service Tests Are Often Plain Unit Tests
For service logic, the best default is often not a Spring test at all. If the service mostly coordinates collaborators, instantiate it directly and mock its dependencies.
This kind of test is fast and precise. It verifies business rules without paying for Spring startup. That is usually the best place for core service logic.
Build a Testing Pyramid, Not a Single Strategy
The practical answer is usually:
- many plain unit tests for services and utility classes
- targeted
@WebMvcTesttests for controllers - targeted
@DataJpaTesttests for repository behavior - fewer
@SpringBootTesttests for full integration scenarios
That balance gives you both speed and confidence. If you push everything into full-context tests, the suite becomes slower than necessary. If you use only unit tests, you miss wiring problems between layers.
How to Choose Quickly
Ask one question: what am I trying to prove
If the answer is "my controller returns the right HTTP response," use @WebMvcTest. If it is "my query works," use @DataJpaTest. If it is "this business rule is correct," use a plain unit test. If it is "the whole flow works together," use @SpringBootTest.
That framing is more useful than asking which annotation is universally best, because each one is designed for a different boundary.
Common Pitfalls
- Using
@SpringBootTestfor simple business-rule tests. That makes the suite slower with no real benefit. - Expecting
@WebMvcTestto load repositories and services automatically. It only loads the web slice, so collaborators usually need mocks. - Testing JPA queries in a plain unit test. Repository behavior should be exercised in a data-layer test.
- Mixing too many concerns into one test class. A controller test should not also be a persistence test.
- Calling everything a unit test. Full-context Spring tests are integration tests, and treating them as unit tests hides their real cost.
Summary
- '
@SpringBootTestis for full integration and costs the most.' - '
@WebMvcTestis for controller and HTTP behavior.' - '
@DataJpaTestis for repositories, mappings, and queries.' - Service logic is often best tested with plain unit tests and mocked dependencies.
- The strongest test strategy mixes narrow fast tests with a smaller number of broad integration tests.

