Mocking Beans with @MockBean
Mocking Beans with @MockBean
Every Spring Boot application is a graph of collaborating beans. When you write a slice test — a @WebMvcTest for a controller, for example — Spring wires only a portion of that graph. The beans your slice does not load (services, repositories, external clients) still appear as dependencies. @MockBean solves exactly this problem: it registers a Mockito mock as a Spring bean inside the test application context, satisfying the dependency without loading the real implementation.
How @MockBean Differs from @Mock
Mockito's @Mock (or Mockito.mock()) creates a mock object that lives entirely outside the Spring context. You wire it into your subject manually, usually through a constructor or a setter. That works fine for pure unit tests where you construct the class yourself.
@MockBean, by contrast, tells Spring's test support to replace (or create) a bean of the given type in the ApplicationContext. Any other bean that has that type injected will receive the mock automatically — no manual wiring needed. Mockito still creates the underlying mock, so all the familiar when(…).thenReturn(…) and verify(…) APIs work exactly as you would expect.
@Mock for plain unit tests (no Spring context). Use @MockBean whenever you need Spring to wire collaborators for you — inside @WebMvcTest, @DataJpaTest, or @SpringBootTest slices.
A Realistic Example: Controller Slice with a Mocked Service
Suppose you have an OrderController that delegates to an OrderService. Loading the real OrderService would pull in a JPA repository, a database connection, and possibly an email client. None of that belongs in a controller test. Here is the full pattern:
Notice three things: the annotation is on the field, not on a parameter; the mock is reset automatically before each test method; and given(…).willReturn(…) (BDD-style) and when(…).thenReturn(…) (classic style) are interchangeable — pick one and stay consistent.
@MockBean Inside @SpringBootTest
You can also use @MockBean in a full @SpringBootTest when you want to load the entire context but isolate one expensive collaborator — an external payment gateway or an email-sending service, for instance.
@MockBean annotations forces Spring to build a new ApplicationContext. If ten test classes each mock a different set of beans, you get ten contexts and your build slows dramatically. Group tests that need the same mocks into the same class, or consider a shared base class that declares the common @MockBean fields.
Stubbing Behaviour and Verifying Interactions
The mock produced by @MockBean is a standard Mockito mock. By default every method returns a "zero value" (null for objects, 0 for numbers, an empty collection for collection return types when using RETURNS_EMPTY settings). Stub only what the test actually exercises:
@SpyBean — When You Need the Real Implementation
Sometimes you want the real bean but need to stub or verify one specific method. @SpyBean wraps the real Spring bean in a Mockito spy. All methods execute normally unless you stub them with doReturn(…).when(spy).method(). Use it sparingly — a spy that stubs most of its methods is really just a mock in disguise and signals a design smell.
@MockBean is what Spring injects; a bare Mockito.mock() floating in the test class will never be wired anywhere and stubs on it will silently have no effect.
Context Caching and Performance Impact
Spring Test caches application contexts by their configuration key. @MockBean participates in that key. Practical guidelines to keep the build fast:
- Declare all
@MockBean/@SpyBeanfields in a shared abstract base class that your slice tests extend. All subclasses share one context. - Prefer
@WebMvcTestslices over full@SpringBootTestwhen you only need the web layer — slice contexts are much cheaper to start. - Use
@MockBeanonly for beans the class under test actually depends on. Mocking beans that are not needed "just in case" pollutes the key and fragments the cache.
Summary
@MockBean is the bridge between Mockito's mocking power and Spring's dependency injection. It registers a mock as a first-class Spring bean, allowing slice and integration tests to isolate expensive or external collaborators without losing the benefit of the full wiring framework. Remember: use @Mock for pure unit tests, @MockBean when Spring must wire the mock, and plan your test class groupings carefully to preserve context caching and keep your build fast.