Before going into detail regarding the different ways of stubbing method calls, we have to define the concept of argument matchers. When passing arguments to the mock's methods during the stubbing process, Mockito verifies argument values using the equals()
method. In other words, when calling the following code:
Person smith = new Person(); given(taxFactorFetcher.getTaxFactorFor(smith).willReturn(10);
Mockito will check whether the person passed as an argument to the getTaxFactorFor(...)
method equals to our person (in this case, Mr. Smith). If that is the case, only then will Mockito return 10
as the output of the getTaxFactorFor(...)
method.
There are cases where you want to perform more complex verification of the passed argument. Mockito already gives you quite a few predefined argument matchers and also provides you with the integration with Hamcrest to create custom argument matchers (check Chapter 7, Verifying Behavior with Object Matchers, for more details on Hamcrest).
Let's take a look at the existing Mockito argument matchers that are present in the Matchers
class:
any
prefix are any()
, any(Person.class)
, anyDouble()
, anyList()
, and so on.That
suffix are argThat(...)
, booleanThat(...)
, doubleThat(...)
, and so on. You can provide a custom Hamcrest matcher that matches the argument of the given type.startsWith(...)
and endsWith(...)
argument matchers are used for string comparison.eq(...)
argument matcher checks for equality.isNotNull()
, isNull()
, and notNull()
argument matchers provide verification against null values.refEq(...)
argument matcher is used for reflection-equal verification (checks via reflection whether two objects are equal).There is also the AdditionalMatchers
class that contains some matchers, but it's better that you don't use it since it's only there to maintain compatibility with EasyMock.
Since using argument matchers is pretty straightforward, intuitive, and we have already been profiting from them throughout the book, we'll skip the business context of the test and move through a quick syntax example to a reminder regarding common mistakes while using argument matching.
To use Mockito's argument matchers, you have to ensure that when calling any method on a mock, you pass a matcher from the Matchers
class instead of passing an argument.
Let's take a look at a couple of snippets that show us some of the possible matchers that Mockito has in the Matchers
class in the example of a method that takes two parameters: an object of the Person
type and a string:
/* match the method for any person and for the city of Warsaw */ given(irsDataFetcher.isIrsApplicable(any(Person.class), eq("Warsaw"))).willReturn(true); /* match the method for any person and for the city starting with 'W' */ given(irsDataFetcher.isIrsApplicable(any(Person.class), startsWith("W"))).willReturn(true); /* match the method for any Person and for the city ending with 'w' */ given(irsDataFetcher.isIrsApplicable(any(Person.class), endsWith("w"))).willReturn(true); /* match the method for any person and for any city */ given(irsDataFetcher.isIrsApplicable(any(Person.class), anyString())).willReturn(true); /* match the method for a person that equals another person and for any city */ given(irsDataFetcher.isIrsApplicable(refEq(new Person()), anyString())).willReturn(true); /* match the method for the same reference of the person and for any city */ given(irsDataFetcher.isIrsApplicable(same(person), anyString())).willReturn(true); /* match the method for a person called Lewandowski and for any city (using Hamcrest matcher) */ given(irsDataFetcher.isIrsApplicable(argThat(new ArgumentMatcher<Person>() { @Override public boolean matches(Object argument) { return "Lewandowski".equalsIgnoreCase(((Person)argument).getName()); } }), anyString())).willReturn(true);
All of the methods of the Matchers
class return dummy values so that the code gets compiled. Internally, Mockito places a matcher on a stack for further verification when a method gets executed on a mock or a method verification takes place.
One of the most common mistakes when using argument matchers is that people tend to forget that if you are using a matcher for at least one argument, then you have to provide matchers for all of the arguments. In other words, the following example will result in InvalidUseOfMatchersException
(notice that there is an any(...)
matcher for the first argument and no matcher for the second argument):
given(irsDataFetcher.isIrsApplicable(any(Person.class), "Warsaw")).willReturn(true);
The following code will work like a charm (notice the any(...)
and eq(...)
matchers):
given(irsDataFetcher.isIrsApplicable(any(Person.class), eq("Warsaw"))).willReturn(true);
3.145.18.101