Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Multiple ArgumentMatchers on the same mock

Tags:

java

mockito

I am trying to do this using Mockito on a Mock:
When Mock.someMethod(..) is called with argument1 --> return result1
When Mock.someMethod(..) is called with argument2 --> return result2
When Mock.someMethod(..) is called with argument3 --> return result3

    when(mock.method(Matchers.argThat(new MyMatcher1() {

        @Override
        public boolean matches(Object arg0) {
                   // comparision logic
        }
    }))).thenReturn(result1);

    when(mock.method(Matchers.argThat(new MyMatcher2() {

        @Override
        public boolean matches(Object arg0) {
                   // comparision logic
        }
    }))).thenReturn(result2);

    when(mock.method(Matchers.argThat(new MyMatcher3() {

        @Override
        public boolean matches(Object arg0) {
                   // comparision logic
        }
    }))).thenReturn(result3);

But Mockito stubs the first one correctly, but on the second one it throws NullPointer exception as it for some reason tries to run the Matcher with null agrument. I am not sure if it is supported.

If this is not the correct way, how to achieve this with Mockito? Thanks.

like image 740
endless Avatar asked Dec 12 '12 19:12

endless


People also ask

What can I use instead of Mockito matchers?

org. mockito. Matchers is deprecated, ArgumentMatchers should be used instead.

What is argThat in Mockito?

The argThat argument matcher in Mockito lets you create advanced argument matchers that run a function on passed arguments, and checks if the function returns true . If you have a complicated class that can't be easily checked using . equals() , a custom matcher can be a useful tool.


2 Answers

Instead of writing

when(mock.method(Matchers.argThat(new MyMatcher1() {
    @Override
    public boolean matches(Object arg0) {
           // comparison logic
    }
}))).thenReturn(result1);

Try this.

doReturn(result1).when(mock).method(Matchers.argThat(new MyMatcher1() {

    @Override
    public boolean matches(Object arg0) {
               // comparison logic
    }
}));

and similarly for result2 and result3.

This is described at http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#12, but in my opinion, the documentation is unclear about the fact that this construction is actually needed in this case. I will talk to the rest of the Mockito team about improving the documentation here.

Good luck.

like image 109
Dawood ibn Kareem Avatar answered Sep 23 '22 06:09

Dawood ibn Kareem


As a rule of thumb, if a test fails, you should be able to pinpoint what is wrong with the unit under test. Avoid writing custom matchers specifically for one test. If a method needs to return more than one value, it is usually sufficient to simply stub the method by returning the values in the order the test predicts.

e.g.

when(mock.method(any(Object.class))).thenReturn(result1, result2, result3);

This will return result 1 one the first invocation, result2 on the second and so on.

There are obviously scenarios where this is insufficient, but more often than not, the simpler test is the better one.

like image 37
bowmore Avatar answered Sep 19 '22 06:09

bowmore