MockitoBean in Spring Boot Tests - Complete Guide

Unit testing with Mockito in Spring Boot

Isolate layers in Spring Boot tests using MockitoBean

1️⃣ Introduction

MockitoBean registers a Mockito mock in the Spring ApplicationContext, replacing a real bean for the duration of a test. This enables isolation of layers (e.g., mocking a service when testing a controller) while still leveraging Spring’s test support.

  • Isolates the unit under test while leveraging Spring configuration
  • Works with @WebMvcTest, @DataJpaTest, and @SpringBootTest
  • Supports stubbing, verifications, and interaction testing

2️⃣ When to use MockitoBean vs @Mock vs @SpyBean

  • MockitoBean: Register a Mockito mock in the Spring context, replacing an existing bean. Use in slice tests or full context tests.
  • @Mock: Plain Mockito mock, not managed by Spring; great for pure unit tests without Spring test context.
  • @SpyBean: Wraps an existing Spring bean with a Mockito spy, calling real methods unless stubbed.
  • Prefer MockitoBean when you need Spring to autowire the mock into other beans under test.
  • Prefer @Mock for fast, framework-free unit tests of a class in isolation.

3️⃣ Controller slice test with @WebMvcTest + MockitoBean

@RestController
@RequestMapping("/api/books")
class BookController {
    private final BookService bookService;

    BookController(BookService bookService) {
        this.bookService = bookService;
    }

    @GetMapping("/{id}")
    public ResponseEntity<BookDto> get(@PathVariable Long id) {
        return ResponseEntity.ok(bookService.getById(id));
    }
}

interface BookService {
    BookDto getById(Long id);
}

@WebMvcTest(BookController.class)
class BookControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockitoBean
    private BookService bookService; // replaces real bean in the context

    @Test
    void should_return_book_by_id() throws Exception {
        BookDto stub = new BookDto(1L, "DDD");
        Mockito.when(bookService.getById(1L)).thenReturn(stub);

        mockMvc.perform(MockMvcRequestBuilders.get("/api/books/1"))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.id").value(1))
               .andExpect(jsonPath("$.title").value("DDD"));

        Mockito.verify(bookService).getById(1L);
    }
}

4️⃣ @SpringBootTest with MockitoBean (replace repository)

In a full context test you can replace expensive/external dependencies with MockitoBean while keeping the rest real.

@SpringBootTest
class BookServiceTest {

    @Autowired
    private BookServiceImpl bookService; // real service under test

    @MockitoBean
    private BookRepository bookRepository; // mock replaces real repository bean

    @Test
    void findById_returns_book() {
        Book entity = new Book(1L, "Clean Code");
        Mockito.when(bookRepository.findById(1L)).thenReturn(Optional.of(entity));

        BookDto dto = bookService.getById(1L);

        assertEquals(1L, dto.getId());
        assertEquals("Clean Code", dto.getTitle());
        Mockito.verify(bookRepository).findById(1L);
    }
}

5️⃣ Mocking external clients (e.g., RestTemplate/WebClient)

@Service
class CurrencyService {
    private final RestTemplate restTemplate;

    CurrencyService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    BigDecimal rate(String from, String to) {
        ResponseEntity<BigDecimal> resp = restTemplate.getForEntity(
                "/rates?from=" + from + "&to=" + to, BigDecimal.class);
        return resp.getBody();
    }
}

@SpringBootTest
class CurrencyServiceTest {

    @Autowired
    private CurrencyService currencyService;

    @MockitoBean
    private RestTemplate restTemplate;

    @Test
    void rate_returns_stubbed_value() {
        Mockito.when(restTemplate.getForEntity(Mockito.anyString(), Mockito.eq(BigDecimal.class)))
               .thenReturn(ResponseEntity.ok(new BigDecimal("1.10")));

        assertEquals(new BigDecimal("1.10"), currencyService.rate("USD", "EUR"));
    }
}

6️⃣ Using @SpyBean to partially mock real beans

@SpyBean wraps the actual Spring bean, invoking real methods unless stubbed. Useful for verifying interactions or overriding specific methods.

@SpringBootTest
class PricingServiceTest {

    @SpyBean
    private DiscountCalculator discountCalculator; // real bean, spied

    @Autowired
    private PricingService pricingService;

    @Test
    void calculates_total_with_spy_override() {
        Mockito.doReturn(new BigDecimal("0.20"))
               .when(discountCalculator).currentDiscount();

        BigDecimal total = pricingService.totalFor(100);

        Mockito.verify(discountCalculator).currentDiscount();
        assertEquals(new BigDecimal("80.00"), total);
    }
}

7️⃣ Common Issues & Debugging 🐞

Common Issues and Solutions

Issue Solution
Mock not injected Ensure the bean type and qualifier match; use MockitoBean(name="...") if necessary.
Multiple beans of same type Disambiguate with @Qualifier or primary bean; mock by name.
NullPointerException in test Verify you used @WebMvcTest/@SpringBootTest and autowired collaborators correctly.
NoSuchBeanDefinition for mock Declare MockitoBean on the test class (not inside a nested config).
Stubs not applied Call stubbing before invoking the SUT; avoid final methods unless using mock-maker-inline.

8️⃣ Best Practices & Pro Tips 🚀

  • Mock across architectural boundaries (e.g., mock service in controller tests).
  • Keep tests focused: one behavior per test with clear arrange-act-assert.
  • Prefer constructor injection in production code to simplify wiring and testing.
  • Verify interactions only when they are part of the behavior contract.
  • Use @SpyBean sparingly—prefer pure mocks or pure unit tests.
  • Avoid overspecification: don’t verify every trivial call.
  • Consider mockito-inline dependency to mock finals if needed.

9️⃣ Q&A / Frequently Asked Questions

@Mock is a Mockito mock created in plain unit tests. MockitoBean registers the mock as a Spring bean, replacing the real bean in the application context for the test.

Yes. Slice tests support MockitoBean to replace collaborators not included in the slice, or to decouple expensive integrations.

Add the Mockito inline mock maker (org.mockito:mockito-inline) to allow mocking final classes/methods.

🔟 Read Next 📖

1️⃣1️⃣ Conclusion

MockitoBean is the go-to tool for isolating layers in Spring Boot tests while still benefiting from Spring’s context and autowiring. Use it to replace expensive or external collaborators, keep tests focused, and combine with @SpyBean when partial mocking is justified.