Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Different mocks are used for @Mock and @InjectMock in the same test class with JUnit 5 extension when using SpringExtension.class along with MockitoExtension.class #1912

Open
karthikairam opened this issue Apr 18, 2020 · 1 comment

Comments

@karthikairam
Copy link

I'm seeing this same bug when using SpringExtension.class along with MockitoExtension.class:

@ExtendWith({MockitoExtension.class, SpringExtension.class})
public class InjectMocksTest {
  static class TacticalStation {}

  static class SpaceShip {
    private final TacticalStation tacticalStation;

    public SpaceShip(final TacticalStation tacticalStation) {
      this.tacticalStation = tacticalStation;
    }

    public TacticalStation getTacticalStation() {
      return tacticalStation;
    }
  }

  @InjectMocks
  private SpaceShip spaceShip;

  @Mock
  private TacticalStation tacticalStation;

  @Test
  public void shouldInjectMocks() {
    assertThat(tacticalStation).isNotNull();
    assertThat(spaceShip.getTacticalStation()).isEqualTo(tacticalStation);
    //Bug ↑ - different mocks are use in @Mock and @InjectMock
  }
}

This is using Mockito 3.1.0, JUnit 5.6.0, and Spring Boot 5.3.0.RELEASE.

Yes I am also facing this issue. Mine is also exactly the same scenario. Below are my dependencies,
org.junit.jupiter:junit-jupiter-engine:5.6.0
org.springframework.boot:spring-boot-starter:2.2.6.RELEASE
org.springframework.boot:spring-boot-starter-test:2.2.6.RELEASE
org.mockito:mockito-junit-jupiter:3.1.0

Originally posted by @karthikaiselvan in #1346 (comment)

@andreisilviudragnea
Copy link
Contributor

andreisilviudragnea commented May 20, 2020

The reason why the test fails is that both MockitoTestExecutionListener from spring-boot-test and the MockitoExtension call MockitoAnnotations.init() on the test class instance.

Only the first init() call sets the value of the field spaceShip, with an object that refers the @Mock-annotated field tacticalStation injected by the first init() call.

The second init() call does not set another value for the spaceShip field, because this is how @InjectMocks works. If the field already has a value, it does not change it anymore. I found this behavior surprising myself and I believe this is a good reason why @InjectMocks should be avoided (#1518). However, the second init() call injects a new mock into the tacticalStation and thus the test fails.

As a side note, what are you trying to achieve by using both MockitoExtension and SpringExtension?

If you write a Mockito-strict unit test, just use MockitoExtension and you are done.

If you write a Mockito-strict Spring integration test, MockitoExtension is useless, because Spring integration tests do not have support for strict stubbing yet. It is a bit harder to implement, given the complexity added by Spring Application Context caching. I am working on a proposal in both Mockito and Spring Boot test for this to be implemented. For now, in the case of Spring integration tests, just use the @MockBean annotation from Spring Boot test to do your job.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants