The Ultimate Guide to @Mock, @InjectMocks and @MockBean in Spring Boot Testing

🎯 The Ultimate Guide to @Mock, @InjectMocks and @MockBean in Spring Boot Testing

✅ By the end, you’ll know exactly when to use each, how they work under the hood, and what you’re truly testing.

🚀 Why do we need mocks?

When writing unit tests, you want to test your business logic in isolation, without hitting:

  • real databases
  • HTTP calls
  • or heavy Spring context.

Mocks allow us to fake out dependencies, so we focus purely on what the class itself does.

⚙ The three key annotations

Annotation Where to use it What it does
@Mock In pure unit tests Creates a fake (mock) object of your dependency.
@InjectMocks In pure unit tests Creates an instance of your class under test and injects the mocks automatically.
@MockBean In Spring Boot tests (@SpringBootTest) Replaces a Spring Bean in the application context with a mock.

🔍 The difference, with a story

👇 Example scenario

Imagine we have:

  • OrderService that depends on OrderRepository.
  • OrderController that depends on OrderService.

OrderController → OrderService → OrderRepository

🧪 Unit testing OrderService

We want to test just the logic inside OrderService, no Spring, no HTTP.


@ExtendWith(MockitoExtension.class)
class OrderServiceTest {

    @Mock
    private OrderRepository orderRepository; // creates a fake object

    @InjectMocks
    private OrderService orderService; // real service, gets mock injected

    @Test
    void testGetOrder() {
        when(orderRepository.findById(1))
            .thenReturn(Optional.of(new Order(1, "Laptop")));

        Order result = orderService.getOrder(1);

        assertEquals("Laptop", result.getName());
        verify(orderRepository).findById(1);
    }
}

What exactly are we testing?

  • That OrderService correctly calls orderRepository.findById()
  • Returns the right order
  • Nothing to do with Spring or HTTP.

🚀 Spring Boot test with @MockBean

Now we want to test that Spring wiring works, i.e.

  • OrderController calls OrderService
  • OrderService calls OrderRepository
  • but we still don’t want to hit a real DB.

    
    @SpringBootTest
    class OrderControllerTest {
    
        @Autowired
        private OrderController orderController; // real bean from Spring
    
        @MockBean
        private OrderRepository orderRepository; // replaces real bean with mock
    
        @Test
        void testGetOrder() {
            when(orderRepository.findById(1))
                .thenReturn(Optional.of(new Order(1, "Laptop")));
    
            Order result = orderController.getOrder(1);
    
            assertEquals("Laptop", result.getName());
            verify(orderRepository).findById(1);
        }
    }
    

    What exactly are we testing?

    • That Spring autowires everything properly.
    • That controller → service → repository chain works.

    🌐 Testing the HTTP endpoint

    Finally, test the actual HTTP API, still with mocked repository.

    
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    @AutoConfigureMockMvc
    class OrderControllerHttpTest {
    
        @Autowired
        private MockMvc mockMvc;
    
        @MockBean
        private OrderRepository orderRepository;
    
        @Test
        void testGetOrderHttp() throws Exception {
            when(orderRepository.findById(1))
                .thenReturn(Optional.of(new Order(1, "Laptop")));
    
            mockMvc.perform(get("/orders/1"))
                   .andExpect(status().isOk())
                   .andExpect(jsonPath("$.name").value("Laptop"));
        }
    }
    

    Now we’re testing:

    • The entire Spring Boot stack
    • JSON serialization
    • Correct HTTP status codes.

    📝 So when do I use what?

    You want to test… Use this Why
    Only class logic, very fast, no Spring @Mock + @InjectMocks Let Mockito build your class & inject fakes
    Wiring inside Spring context, no HTTP @SpringBootTest + @MockBean Spring loads beans & you replace dependencies
    The full HTTP REST endpoint @SpringBootTest + @AutoConfigureMockMvc + @MockBean Test full HTTP layer with JSON

    🔍 Under the hood: how does @InjectMocks work?

    
    @InjectMocks
    private OrderService orderService;
    
    @Mock
    private OrderRepository orderRepository;
    

    Mockito sees that OrderService needs OrderRepository and automatically injects it, either via constructor or field. ✅

    🥇 Key takeaways

    • ✅ Use @Mock + @InjectMocks for fast, isolated Java logic tests, no Spring needed.
    • ✅ Use @MockBean to replace beans in Spring context when testing controllers or services inside a Spring Boot app.
    • ✅ Always clearly decide: “Am I testing pure logic or Spring wiring or HTTP layer?”

    🎉 Hope this clears it up once and for all.

    If you liked it, drop a ⭐ or share it with your team — so everyone stops being confused by @Mock, @InjectMocks, and @MockBean forever!

Leave a Reply

Your email address will not be published. Required fields are marked *