Replace a collaborator for a boundary test, but keep the advised service real when verifying transactions, caching or method security.
Spring @MockitoBean override: a mock can remove advice from the tested bean
Choose which bean is under test
@MockitoBean replaces a bean in the Spring test context. The replacement is a Mockito object, not the original advised service. A controller test may safely mock a receipt service while checking request validation and response mapping. A test that claims to verify @Transactional, @Cacheable or @PreAuthorize on that same mocked service is empty: the method body and its advice have been removed. Proxy mechanics] still matter in the real service.
Keep the seam narrow
Mock an external gateway or a downstream collaborator, then invoke the real Spring-managed service when testing service advice. Use a spy only with care: a spy can retain an advised proxy shape, but stubbing and verification around proxies are easy to misunderstand. An integration test with a real repository is stronger evidence for rollback] than verification that a mock repository method was called.
Check the override itself
If several beans share a type, qualify the intended replacement explicitly; a test can fail at context startup or replace an unintended bean. Count distinct override combinations across classes because each can alter context caching]. State in the test name what remains real and what has been substituted.
Implementation contract
@SpringBootTest
class ReceiptServiceAdviceTest {
@Autowired ReceiptWriteService realService;
@Autowired ReceiptRepository receipts;
@MockitoBean PaymentGateway paymentGateway;
@Test void failedChargeLeavesNoReceipt() {
String externalKey = "rejected-" + UUID.randomUUID();
when(paymentGateway.charge(any())).thenThrow(
new PaymentDeclinedException("declined"));
assertThatThrownBy(() -> realService.accept(
new ReceiptCommand(externalKey, 4700)))
.isInstanceOf(PaymentDeclinedException.class);
assertThat(receipts.existsByExternalKey(externalKey)).isFalse();
}
}Cost and verification
A mock keeps the test local and fast, but replacing a bean changes the graph and may create another cached context. A database assertion costs more than mock verification and is warranted when the claim is about committed or rolled-back state.
Common Mistakes
- Do not mock the service whose transaction or authorization advice you claim to test.
- Do not assume a Mockito interaction proves durable database state.
- Do not leave bean selection ambiguous when several candidates share a type.
Read next
Spring AOP proxies: self-invocation bypasses proxy advice, Spring command rollback test: inspect state after an injected failure, Spring TestContext cache: keep equivalent tests on one context shape, Spring method security: authorization advice runs through the bean proxy, Spring ApplicationContextRunner: check conditional assembly in isolation.
