8

I have a Java application that uses Spring's dependency injection. I want to mock out a bean, and verify that it receives certain method calls.

The problem is that Mockito does not reset the mock between tests, so I cannot correctly verify method calls on it.

My unit under test:

public class MyClass {
  @Resource
  SomeClientClass client;

  public void myMethod() {
    client.someMethod();
  }
}

The unit test class:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = UnitTestConfig.class)
public class MyClassTest {
  @Resource
  SomeClientClass client;

  @Test
  public void verifySomething() {
    // ...
    Mockito.verify(client).publish();
  }
}

Finally,

@Configuration
public class UnitTestConfig {
  @Bean
  SomeClientClass client() {
    return Mockito.mock(SomeClientClass.class);
  }
}

Though I could hack my way around this problem by manually resetting mocks between tests, I wonder if there's a cleaner / more idiomatic approach.

Raedwald
  • 46,613
  • 43
  • 151
  • 237
Philip
  • 1,532
  • 12
  • 23

2 Answers2

4

I had to add this at the start:

@BeforeEach
void setup() {
     Mockito.reset(...mockBeans);
     ...
}
  • [Mockito documentation](https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#17) suggest to avoid that if possible. However for some big integration tests this can work well. \ One more weak side of `Mockito.reset(...mockBeans);`, it resets specified mocks only. There no way to reset All. However [here workaround](https://stackoverflow.com/questions/48184291/mockito-get-all-mocked-objects) – vyacheslav.kislov Apr 01 '22 at 13:53
0

Author not explained why he needs it, I can put more details. Combining Spring's dependency injection with Mockito in this way not the best approach.

It leads to errors, because same Mocks will be reused between different tests! This means that verify() will work incorrectly. It will accumulate method invocations from different tests. For example you will get "Wanted 1 time:" - "But was 2 times".

Most generic solution for this in Mockito is using @InjectMocks. This annotation doing 2 important things:

  1. actually injecting all @Mock fields into class annotated with @InjectMocks
  2. resets each @Mock annotated class. (so, verify() will not accumulate invocations from different tests)

Code example:

@RunWith(MockitoJUnitRunner.class)
public class SomeSpringConverterTest {

@InjectMocks
private SomethingToJsonNodeSpringConverter someSpringConverter;
@Mock
private SomethingDatamodelService someDatamodelService;

@Test
public void convertOriginalContainerTest() {
    SomethingContainer someContainer = buildSomeContainer("aa", "bb");
    Mockito.when(someDatamodelService.getAttributes()).thenReturn(Arrays.asList("aa", "bb"));
    JsonNode node = someSpringConverter.convert(someContainer, JsonNode.class);
    Mockito.verify(someDatamodelService.getAttributes());
    assertTrue(node.get("aa") != null);
}

@Test
public void convertOriginalContainerTest() {
    SomethingContainer someContainer = buildSomeContainer("aa", "bb");
    Mockito.when(someDatamodelService.getAttributes()).thenReturn(Arrays.asList("aa", "bb"));
    JsonNode node = someSpringConverter.convert(someContainer, JsonNode.class);
    Mockito.verify(someDatamodelService.getAttributes());
    assertTrue(node.get("bb") != null);
}

}