@MockitoBean
Replaces a bean in the test's application context with a Mockito mock, so a test controls what a collaborator returns and verifies what was called.
@MockitoBean(name = "", reset = MockReset.AFTER)- Added in Spring Boot Spring Framework 6.2
Parameters
| Parameter | Type | Description |
|---|---|---|
$name / valueoptional | String= "" | Name of the bean to override. Empty means select by the field's type (and qualifiers). |
$typesoptional | Class<?>[]= {} | Only on the class: the types to mock when no field is used. |
$resetoptional | MockReset= AFTER | BEFORE, AFTER or NONE: when Mockito state is reset relative to each test. |
$answersoptional | org.mockito.Answers= RETURNS_DEFAULTS | Default answer for unstubbed calls. |
$extraInterfacesoptional | Class<?>[]= {} | Extra interfaces the mock implements. |
$serializableoptional | boolean= false | Whether the mock is serialisable. |
$enforceOverrideoptional | boolean= false | true fails when no matching bean exists instead of creating one. |
$contextNameoptional | String= "" | In a context hierarchy, the name of the context whose bean is overridden. |
Return value
n/aOverrides a bean in the test ApplicationContext with a Mockito mock and injects that mock into the annotated field.
Errors
Context startup fails if the target is ambiguous (several beans of the type and no name or qualifier), or if enforceOverride is true and no bean matches.
@MockitoBean comes from Spring Framework's test module, not from Spring Boot. Put it on a field of a test class and the matching bean in the application context is replaced with a Mockito mock; the same mock is injected into the field so you can stub and verify it. It works in any Spring test: @SpringBootTest, @WebMvcTest, @DataJpaTest and plain @SpringJUnitConfig.
Spring Boot's own @MockBean and @SpyBean do not exist in Spring Boot 4. Replace them with @MockitoBean and @MockitoSpyBean from org.springframework.test.context.bean.override.mockito.
How the bean is found
By default the field's type picks the bean. If two beans have that type, name the one to replace with @MockitoBean("primaryGateway") or add a @Qualifier to the field. If no bean of the type exists, a mock is created and registered. To fail instead, which catches a test that mocks something the application no longer has, set enforceOverride = true.
On the class, @MockitoBean(types = {AuditLog.class, Clock.class}) mocks several beans you need to satisfy dependencies but never stub. Fields are better when you stub or verify.
Where it may go
Only in test classes, including their superclasses and the enclosing classes of @Nested tests. Unlike @MockBean, it is not supported on fields of @Configuration or @TestConfiguration classes. Move those fields into a shared base test class.
Reset and caching
The default reset = MockReset.AFTER clears stubs and recorded calls after each test, so stubbing does not leak between tests. The cost is in context caching: the set of overridden beans is part of the context's cache key. Ten test classes that each mock a different combination of beans start ten application contexts. In a @WebMvcTest slice that is cheap; in @SpringBootTest it can turn a two-minute build into ten. Agree on a common set of mocks in a base class for full-context tests.
When not to use it
If the class under test takes its dependencies through the constructor, a unit test with new CheckoutService(mock(PaymentGateway.class), ...) is faster and needs no Spring. Reach for @MockitoBean when Spring must build the object graph, such as a controller in a slice or a service reached through an HTTP request.
Example
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.never;
import java.math.BigDecimal;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.stereotype.Service;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
interface PaymentGateway {
boolean charge(String customerId, BigDecimal amount);
}
interface ReceiptMailer {
void send(String customerId, BigDecimal amount);
}
class PaymentDeclinedException extends RuntimeException {
PaymentDeclinedException(String customerId) {
super("Payment declined for " + customerId);
}
}
class CheckoutService {
private final PaymentGateway payments;
private final ReceiptMailer mailer;
CheckoutService(PaymentGateway payments, ReceiptMailer mailer) {
this.payments = payments;
this.mailer = mailer;
}
void checkout(String customerId, BigDecimal amount) {
if (!payments.charge(customerId, amount)) {
throw new PaymentDeclinedException(customerId);
}
mailer.send(customerId, amount);
}
}
(webEnvironment = SpringBootTest.WebEnvironment.NONE)
class CheckoutServiceTest {
// Both beans in the context are replaced by Mockito mocks.
PaymentGateway payments;
ReceiptMailer mailer;
CheckoutService checkout;
void declinedPaymentSendsNoReceipt() {
given(payments.charge(any(), any())).willReturn(false);
assertThatThrownBy(() -> checkout.checkout("c-17", new BigDecimal("40.00")))
.isInstanceOf(PaymentDeclinedException.class);
then(mailer).should(never()).send(any(), any());
}
}
When to use it
- Make a payment gateway decline a charge to check that no receipt email is sent.
- Supply a stubbed service to a controller in a @WebMvcTest so each test chooses the service's answer.
- Replace a client for a third-party API in a @SpringBootTest so the suite never calls the real service.
Frequently asked questions
What replaces @MockBean in Spring Boot 4?
@MockitoBean from org.springframework.test.context.bean.override.mockito, part of spring-test. @SpyBean becomes @MockitoSpyBean. Spring Boot's org.springframework.boot.test.mock.mockito package is gone.
Why does my suite get slower when I add @MockitoBean?
Each distinct set of overridden beans is a separate cached application context. Adding a different mock to one @SpringBootTest class forces a fresh start for that class. Share the same mocks across classes with a base class.
Can I put @MockitoBean in a @TestConfiguration class?
No. It is only processed on test classes, their superclasses and enclosing classes. Declare the fields in a base test class instead, or define a @Bean that returns Mockito.mock(...) in the configuration.
More examples
Mocking types at class level
The controller needs an <code>AuditLog</code> but the test has nothing to say about it, so it is mocked on the class with <code>types</code> and stays out of the way. <code>StockService</code> is a field because the test stubs it. Unstubbed mock methods return defaults (0, false, null), which is why the audit call is harmless here.
import static org.mockito.BDDMockito.given;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
interface StockService {
int available(String sku);
}
interface AuditLog {
void record(String event);
}
@RestController
class StockController {
private final StockService stock;
private final AuditLog audit;
StockController(StockService stock, AuditLog audit) {
this.stock = stock;
this.audit = audit;
}
@GetMapping("/api/stock/lamp")
int lamp() {
audit.record("stock read");
return stock.available("LAMP-01");
}
}
// Class-level form: mocks the types the controller needs but this test never stubs.
@WebMvcTest(StockController.class)
@MockitoBean(types = AuditLog.class)
class StockControllerTest {
@Autowired
MockMvcTester mvc;
@MockitoBean
StockService stock;
@Test
void returnsAvailableStock() {
given(stock.available("LAMP-01")).willReturn(12);
mvc.get().uri("/api/stock/lamp")
.assertThat()
.hasStatusOk()
.hasBodyTextEqualTo("12");
}
}
Spying on a real bean with @MockitoSpyBean
A spy wraps the real bean: calls run the real code, and Mockito records them for verification. Use it when the real behaviour is fine but you need to prove an interaction happened, such as a cache being consulted. Stub a spy with <code>willReturn(...).given(spy).method()</code>, because <code>given(spy.method())</code> calls the real method first.
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.then;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
@Component
class ExchangeRates {
private final Map<String, Double> rates = new HashMap<>(Map.of("EUR", 1.17, "USD", 1.27));
double rate(String currency) {
return rates.get(currency);
}
}
@Service
class PriceConverter {
private final ExchangeRates rates;
PriceConverter(ExchangeRates rates) {
this.rates = rates;
}
long convert(long pence, String currency) {
return Math.round(pence * rates.rate(currency));
}
}
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
class PriceConverterTest {
// The real bean, wrapped so calls can be verified.
@MockitoSpyBean
ExchangeRates rates;
@Autowired
PriceConverter converter;
@Test
void looksUpTheRateOnce() {
assertThat(converter.convert(1000, "EUR")).isEqualTo(1170);
then(rates).should().rate("EUR");
}
}
Migrating from @MockBean and @SpyBean
Most migrations are an import change. The real work is mocks declared in shared <code>@TestConfiguration</code> classes, which are not supported and must move to a base test class. Check the defaults too: a mock is still created when no bean of that type exists unless you turn on <code>enforceOverride</code>.
Spring Boot 3 (no longer compiles on Spring Boot 4)
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
@MockBean PaymentGateway payments;
@SpyBean ExchangeRates rates;
Spring Framework 7 / Spring Boot 4
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
@MockitoBean PaymentGateway payments;
@MockitoSpyBean ExchangeRates rates;
Things that change
- Fields only in test classes (and their superclasses or enclosing classes);
@MockBean fields in @Configuration or @TestConfiguration classes must move
to the test class or a shared base class.
- As with @MockBean, a mock is created when no bean of that type exists;
set enforceOverride = true to fail instead, which catches stale mocks.
- Mocks are reset after each test (reset = MockReset.AFTER), as before.
Discussion