Explain Codes LogoExplain Codes Logo

Difference between @Mock, @MockBean and Mockito.mock()

java
mockito
unit-testing
spring-testing
Nikita BarsukovbyNikita Barsukov·Feb 4, 2025
TLDR

@Mock is the tool of choice for unit tests without Spring context:

@Mock MyService myServiceMock; // Who needs a spring when you have a mock?

@MockBean is your friend in integration tests dealing with Spring context beans:

@MockBean MyService myServiceMock; // A mock undercover in Spring's world!

Use Mockito.mock() for crafting mock objects manually in any scenario:

MyService myServiceMock = Mockito.mock(MyService.class); // I like to mock it, mock it!

@Mock for pure Mockito tests, @MockBean within Spring tests, Mockito.mock() for fine control.

Mockito: A snowflake in the Java ecosystem

The Mockito framework provides for the creation of mock objects, promoting isolated and controlled environments for your tests. By mocking dependencies, you ensure stability and predictability, key to effective and reliable tests.

@Mock: The lone wolf

@Mock is a way to birth mock objects for unit tests with no Spring context intervention.

  • Readability: @Mock boosts code comprehensibility.
  • Functionality: @Mock and Mockito.mock() are virtually indistinguishable in functionality. The former just prefers cosying up with annotations.

To enable: Use MockitoAnnotations.initMocks(this) in your setup method, or opt for @RunWith(MockitoJUnitRunner.class).

@MockBean: The team player

@MockBean is custom-built for tests involving Spring context. It seamlessly interchanges the bean in the Spring application context with a mock.

  • Integration Testing: Great for Spring Boot tests that need to play with Spring features but keep certain beans as mocks.
  • Replacement: It substitutes existing beans, or introduces new mock beans, in the Spring context without batting an eyelid.
  • @WebMvcTest friendly: It plays well with @WebMvcTest, making a dream team for mocking web layer dependencies.

Using @MockBean means a fresh mock instance for every test, and integration with Spring's cache when state retention is a must!

Mockito.mock(): The DIY expert

The Mockito.mock() method provides the blueprint to create mocks manually. This comes in handy when you prefer more control or when Mockito annotations sound like Greek and Latin.

  • Flexibility: Offers customizable behavior through method chaining.
  • Immediate Creation: No extra setup steps or context loading needed.

Choosing your mock knight

These scenarios help you decide the best tool for the job:

  • Just JUnit unit tests: Choose @Mock for a streamlined, straightforward approach.
  • Spring context-loaded tests with bean replacements: Use @MockBean to work with Spring TestContext framework.
  • Dynamic behavior scenarios or non annotation-based setups: Mockito.mock() grants fine-grain control.

Mind your test architecture

Remember: speed and simplicity make @Mock and Mockito.mock() attractive for bypassing Spring overhead. If Spring's dependency injection catches your fancy, @MockBean is your guy! Annotations make @Mock and @MockBean more legible in your test code.

The real-world comparison

Behold the mock lifecycle

Understanding the lifecycle of each approach allows you to anticipate test behavior and streamline the testing process:

  • @Mock lives and dies with each test run, starting afresh.
  • @MockBean manipulates the Spring context, potentially influencing other tests if the context wanders off to cache land.
  • Mockito.mock() follows a manual lifecycle that you control through your code.

Tread carefully with potential pitfalls

Regardless of the rooting approach, be cautious of common pitfalls that can tarnish your tests credibility:

  • Initialization Woes: Ensure mocks are up and running before the test execution starts.
  • Side Effects: Using @MockBean can affect other tests due to Spring's penchant for context caching.
  • Over-mocking: Mock external dependencies, not the class you're testing.

Mocking for clarity and resilience

Strategically applying each mock type will not only make your "mockery" more resilient but also communicate their intention clearly:

  • @Mock is your declaration of intent for non-Spring-bound tests.
  • @MockBean signals that a test operates amidst the Spring ecosystem.
  • Mockito.mock() is your flag of customization or non-standard setup.