skip to content

What is @MockitoSpyBean and how does it differ from @MockitoBean?

level: juniorimportance: must knowfreq 72%

answer

  1. Spy = partial mock, real methods run
  2. Wraps real bean, not empty mock
  3. @MockitoBean = full mock, defaults
  4. Spring Boot 3.4 replaced @SpyBean
  5. Stub selectively, verify() interactions

basics

~20 s

@MockitoSpyBean wraps a real Spring bean in a Mockito spy: real methods run by default, but you can stub or verify them. @MockitoBean replaces the bean with a full mock whose methods do nothing until stubbed.

solid answer

~40 s

Both are Spring Boot 3.4+ test annotations (successors to @SpyBean/@MockBean) that swap a bean in the ApplicationContext. @MockitoSpyBean creates a partial mock: it wraps the actual bean instance, so unstubbed methods execute the real code, while you can still selectively stub methods and verify() interactions. @MockitoBean installs a complete mock: every method returns a default (null/0/empty) unless you stub it, and the real implementation never runs. Use a spy when you want real behavior but need to observe or override one method; use a mock when you want to eliminate the collaborator entirely. Both trigger a context cache miss, so overusing them slows the suite. The field type must match the target bean, and by default matching is by type (optionally by name).

code

java · 16 lines
java
@SpringBootTest
class OrderServiceTest {

    @MockitoSpyBean
    private InventoryService inventory; // real bean, wrapped in a spy

    @Autowired
    private OrderService orderService;

    @Test
    void reservesStockUsingRealLogic() {
        // real reserve(...) runs unless stubbed
        orderService.placeOrder("sku-1", 2);
        verify(inventory).reserve("sku-1", 2); // observe the real collaboration
    }
}

go deeper

for a junior

Must know spy = real methods run, mock = defaults; and that it's a Spring test annotation.

for a middle

Should also know the @SpyBean→@MockitoSpyBean rename and by-type matching.

for a senior

Explains context-cache impact and when a spy beats a mock architecturally.

for a principal

Frames spy usage as a testing-strategy smell to minimize; prefers real collaborators or seams.

**@MockitoSpyBean** is a Spring Boot test annotation (introduced in Spring Boot 3.4 / Spring Framework 6.2, replacing the older `@SpyBean`) that you place on a field in a test class. When the test's `ApplicationContext` is built, Spring finds the real bean of that type, wraps it in a **Mockito spy**, and replaces the original bean in the context with the spy. **What a spy is:** A Mockito spy is a *partial mock*. It delegates to the real object's methods by default — so calling a method actually runs the production code — but you can (a) **stub** specific methods to override their behavior and (b) **verify** that methods were called. This contrasts with a full mock (`@MockitoBean`), where every method returns a type default (null, 0, false, empty collection) until you stub it, and the real code never executes. **Key terms:** - *Stub:* pre-programming a method's return value/behavior, e.g. `when(spy.foo()).thenReturn(x)`. - *Verify:* asserting a method was invoked, e.g. `verify(spy).foo()`. - *Partial mock:* real behavior except where explicitly stubbed. **How Spring wires it:** The spy is a genuine bean in the context, so any other bean that `@Autowired`s that type receives the spy. That is what makes it useful — you can observe or tweak how the rest of the application uses the collaborator. **Difference from @MockitoBean:** | | @MockitoSpyBean | @MockitoBean | |---|---|---| | Underlying object | wraps the **real** bean | brand-new **empty** mock | | Unstubbed method | runs real code | returns default value | | Typical use | observe/partially override real behavior | fully isolate a collaborator | **Selection/matching:** By default the target bean is matched **by type**. If several beans of that type exist, you disambiguate with the annotation's `name` attribute (the bean name). The annotated field's declared type must be assignable to the bean. **Cost gotcha:** Both annotations mutate the context, so Spring caches a *separate* context for each unique combination. Overusing them causes context-cache misses and slower tests. **When to use a spy over a mock:** when the collaborator's real behavior is mostly what you want (e.g. a real service hitting an in-memory DB) but you need to stub one flaky/slow method or count how often a method fired.

  • Which annotation did @MockitoSpyBean replace, and when?
    It replaced @SpyBean, as of Spring Boot 3.4 / Spring Framework 6.2. The old @SpyBean lived in spring-boot-test; the new one is part of the core spring-test module (org.springframework.test.context.bean.override.mockito).
  • If you inject an @MockitoSpyBean but never stub anything, what happens when its methods are called?
    The real method executes normally, because a spy delegates to the underlying real object by default. You still gain the ability to verify() those calls afterwards.

saying these in an interview costs you the question

  • Saying a spy returns null/defaults for unstubbed methods (that's a mock)
  • Claiming @MockitoSpyBean creates a brand-new object rather than wrapping the real bean
  • Thinking it's the same as plain Mockito.spy() with no Spring context involvement

context