11

Maybe this is a newbie question, but can't find the answer.

I need to stub a method with Mockito. If the method has "simple" arguments, then I can do it. For example, a find method with two parameters, car color and number of doors:

 when(carFinderMock.find(eq(Color.RED),anyInt())).thenReturn(Car1);
 when(carFinderMock.find(eq(Color.BLUE),anyInt())).thenReturn(Car2);
 when(carFinderMock.find(eq(Color.GREEN), eq(5))).thenReturn(Car3);

The problem is that the find argument is a complex object.

 mappingFilter = new MappingFilter();
 mappingFilter.setColor(eq(Color.RED));
 mappingFilter.setDoorNumber(anyInt());
 when(carFinderMock.find(mappingFilter)).thenReturn(Car1);

This code does not work. The error is "Invalid use of argument matchers! 1 matchers expected, 2 recorded".

Can't modify the "find" method, it needs to be a MappingFilter parameter.

I suppose that I have to do "something" to indicate Mockito that when the mappingFilter.getColor is RED, and mappingFilter.getDoorNumber is any, then it has to return Car1 (and the same for the other two sentences). But how?

Andres_age
  • 175
  • 1
  • 2
  • 9

3 Answers3

11

Use a Hamcrest matcher, as shown in the documentation:

when(carFinderMock.find(argThat(isRed()))).thenReturn(car1);

where isRed() is defined as

private Matcher<MappingFilter> isRed() {
    return new BaseMatcher<MappingFilter>() {
        // TODO implement abstract methods. matches() should check that the filter is RED.
    }
}
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
5

Since 2.1.0 Mockito has its own matcher mechanism build on top of org.mockito.ArgumentMatcher interface. This allows to avoid using Hamcrest. Usage is almost of same as with Hamcrest. Keep in mind that ArgumentMatcher is a functional interface and implementation of a matched can be expressed as a lambda expression.

private ArgumentMatcher<SomeObject> isYellow() {
    return argument -> argument.isYellow();
}

and then

when(mock.someMethod(argThat(isYellow()).thenReturn("Hurray");
1

You need to correctly implement equals() method of your MappingFilter. In equals() you should only compare color and not doorNumber .

In simplest form, it should look like this -

@Override
public boolean equals(Object obj) {
    MappingFilter other = (MappingFilter) obj;
    return other.getColor() == this.getColor();
}

Also, you should form your MappingFilter simply as below instead of using any matcher such as eq

 mappingFilter = new MappingFilter();
 mappingFilter.setColor(Color.RED);
 mappingFilter.setDoorNumber(10); //Any integer
Gopi
  • 10,073
  • 4
  • 31
  • 45
  • Thanks for your answer! Is it possible to do it without implementing the equals method? For example, the filter has 20 fields and I only want to test when color and door number have the specified value, and in another piece of code when the color and car type have the specified value (without comparing the door number), etc. – Andres_age Feb 28 '13 at 16:30
  • Well, alternatively, as pointed by @JB Nizet, that seems to be the way to do it. – Gopi Feb 28 '13 at 16:35