Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simulation of Service using Mockito 2 leads to stubbing error

I try to simulate the behaviour of a class, using Mockito. This worked using Mockito 1.x. Migrating to JUnit 5 and Mockito 2 it seems not to work anymore.

@ExtendWith(MockitoExtension.class) public class MockitoExample {    static abstract class TestClass {     public abstract int booleanMethod(boolean arg);   }    @Mock   TestClass testClass;    @BeforeEach   public void beforeEach() {     when(testClass.booleanMethod(eq(true))).thenReturn(1);     when(testClass.booleanMethod(eq(false))).thenReturn(2);   }    @Test   public void test() {     assertEquals(1,testClass.booleanMethod(true));     assertEquals(2,testClass.booleanMethod(false));   } } 

The expectation is, that the mocked TestClass shows the behaviour as tested in the test-method.

The error I get is:

org.mockito.exceptions.misusing.PotentialStubbingProblem:     Strict stubbing argument mismatch. Please check:    - this invocation of 'booleanMethod' method:       testClass.booleanMethod(false);       -> at org.oneandone.ejbcdiunit.mockito_example.MockitoExample.beforeEach(MockitoExample.java:30)    - has following stubbing(s) with different arguments:       1. testClass.booleanMethod(false);         -> at org.oneandone.ejbcdiunit.mockito_example.MockitoExample.beforeEach(MockitoExample.java:29)   Typically, stubbing argument mismatch indicates user mistake when writing tests.   Mockito fails early so that you can debug potential problem easily.   However, there are legit scenarios when this exception generates false negative signal:     - stubbing the same method multiple times using 'given().will()' or 'when().then()' API       Please use 'will().given()' or 'doReturn().when()' API for stubbing.     - stubbed method is intentionally invoked with different arguments by code under test       Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).   For more information see javadoc for PotentialStubbingProblem class. 

In both cases, the argument false seems to be matched, though I clearly matched with true.

Is that a bug in Mockito 2.17 or a misunderstanding. How should/can I use Mockito 2.x to simulate calls with different boolean arguments?

The example can also be found on github. But surefire will start the test only using

mvn test -Dtest=MockitoExample 

Executing the test using Mockito 2.21 leads to the same results.

like image 710
aschoerk Avatar asked Sep 02 '18 17:09

aschoerk


2 Answers

Since Mockito 2.20 it is also possible, to add lenient() locally

@ExtendWith(MockitoExtension.class) public class MockitoExample {    static abstract class TestClass {     public abstract int booleanMethod(boolean arg);   }    @Mock   TestClass testClass;    @BeforeEach   public void beforeEach() {     lenient().when(testClass.booleanMethod(eq(true))).thenReturn(1);     lenient().when(testClass.booleanMethod(eq(false))).thenReturn(2);   }    @Test   public void test() {     assertEquals(1,testClass.booleanMethod(true));     assertEquals(2,testClass.booleanMethod(false));   } } 
like image 155
aschoerk Avatar answered Sep 19 '22 14:09

aschoerk


With strict stubs (the default behavior of Mockito) calling several whens on the same method will reset that mock. The solution is to call when once and have the logic in an Answer:

@BeforeEach public void beforeEach() {     when(testClass.booleanMethod(anyBoolean())).thenAnswer(invocationOnMock -> {         if ((boolean) invocationOnMock.getArguments()[0]) {             return 1;         }         return 2;     }); } 

Alternatively, you can use lenient mocking, but that's not always a good idea - lenient mocking allows redundant stubbing, and makes it easier for you to make mistakes in your test, which may lead to unnoticed bugs in the "production" code:

@ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) public class MockitoExample { 
like image 28
Mureinik Avatar answered Sep 21 '22 14:09

Mureinik