wahyu eko hadi saputro
wahyu eko hadi saputro

Reputation: 427

Mockito, how to mock call by reference method on same class

Why I can not mock callRefMethod method (call method by reference) on below code? The problem is real method of callRefMethod always being called.

public class ManageUserService {

    public void callRefMethod(List<String> lsStr, boolean flag){
        if (flag){
            lsStr.add("one");
            lsStr.add("two");
        }
 
    }

    public void methodA(){
        List<String> lsStr = new ArrayList<>();
        lsStr.add("zero");
        this.callRefMethod(lsStr, true);
        for(String str : lsStr){
            System.out.println(str);
        }
    }
}

Unit tests:

public class ManageUserServiceTest {

    @InjectMocks
    private ManageUserService manageUserService;
  
    private AutoCloseable closeable;

    @BeforeEach
    public void init() {
        closeable = MockitoAnnotations.openMocks(this);
    }

    @AfterEach
    void closeService() throws Exception {
        closeable.close();
    }

    @Test
    void methodATest(){
        List<String> lsData = new ArrayList<>();
        lsData.add("start");
        ManageUserService manageUserServiceA = new ManageUserService();
        ManageUserService userSpy = spy(manageUserServiceA);
        doNothing().when(userSpy).callRefMethod(lsData, true);
        userSpy.methodA();
        verify(userSpy).callRefMethod(ArgumentMatchers.any(ArrayList.class), ArgumentMatchers.any(Boolean.class));
    }
}

The result :

zero
one
two

Upvotes: 1

Views: 350

Answers (2)

wahyu eko hadi saputro
wahyu eko hadi saputro

Reputation: 427

ok i did it by using : where manageUserServiceOne is spy of ManageUserService class

 void methodATest(){
        List<String> lsData = new ArrayList<>();
        lsData.add("start");
        doAnswer((invocation) -> {
            System.out.println(invocation.getArgument(0).toString());
            List<String> lsModify = invocation.getArgument(0);
            lsModify.add("mockA");
            lsModify.add("mockB");
            return null;
        }).when(manageUserServiceOne).callRefMethod(anyList(), anyBoolean());
        manageUserServiceOne.methodA();
        verify(manageUserServiceOne).callRefMethod(ArgumentMatchers.any(ArrayList.class), ArgumentMatchers.any(Boolean.class));
    }

Upvotes: 0

Jonasz
Jonasz

Reputation: 1802

The problem is the difference between the list you're creating in the test method, which is used to match the expected parameters when "doing nothing":

List<String> lsData = new ArrayList<>();
lsData.add("start");
...
doNothing().when(userSpy).callRefMethod(lsData, true);

and the list created in the tested method, passed to the spy object:

List<String> lsStr = new ArrayList<>();
lsStr.add("zero");
this.callRefMethod(lsStr, true);

You're telling Mockito to doNothing if the list is: ["start"], but such list is never passed to the callRefMethod. ["zero"] is passed there, which does not match the expected params, so actual method is called.

Mockito uses equals to compare the actual argument with an expected parameter value - see: the documentation. To work around that ArgumentMatchers can be used.

You can either fix the value added to the list in the test or match the expected parameter in a less strict way (e.g. using anyList() matcher).

Upvotes: 1

Related Questions