Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring @MockitoBean override: a mock can remove advice from the tested bean

Last updated: 5 Oct 20264 min read
tutorial
IntermediateBy AITrove Editorial

Replace a collaborator for a boundary test, but keep the advised service real when verifying transactions, caching or method security.

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

Java
@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.

spring
spring-boot
testing
mockito-bean-proxy-caveat
Storage details