Saturday, July 17, 2010

How to use argument matchers using PowerMock

In my previous post we saw how we could suppress a field. In this post, we will write test case for a more common scenario.

Every time when we stubbed out a method or verified an invocation we have used actual arguments, for e.g.

Or

Notice the argument that we are passing to method2 is "some argument value".
By default PowerMock invokes the equals method on each argument to find whether the arguments match or not.

But what if we want to write the test for the below code

Code Under Test:

Well, looks pretty straight forward class to test. But wait, have a look at the arguments been passed to anotherBusinessProcess method.

The first argument is "Hello World" thats not the problem, the real challenge is the second argument "Another argument + Math.random()". Any one who has worked in Java for a day knows that Math.random() with generate a random number :) and since its "random" we cant determine what is the number till its generated!

So how do we stub the anotherBusinessProcess method on the ServiceB class.

How will we test it - How do they do it!:

Well in such cases where we don't know exactly what argument will be passed to a certain method (which we want to stub) we could use a feature of Mockito called Argument Matchers.

Mockito has a rich set of predefined argument matchers. As the name suggests, argument matchers job is to match the arguments! As in this case we don't know what is the exact argument passed to the anotherBusinessProcess, hence we might say that

"Stub the anotherBusinessProcess method on ServiceB when its invoked with argument Hello World and any string to return Success!"

If you read the statement above carefully, we want to make sure that, the first argument of anotherBusinessProcess method is "Hello World" but the second argument could be "any string". How do we do that? Using Mockito's argument matchers.

The syntax:

Notice that we are using two argument matchers in the above example
  • eq: used to say that the argument passed while invoking the method from the test code is equal to the argumnet passed to the eq method
  • anyString: Means, the argument is any valid string!
NOTE: The difference between the two lines in the above example. In the commented line we are not using the eq argument matcher. The rule is if you are using Mockito argument matcher for one argument you have to, have to, use it for all the other arguments as well.

Hence if you ran the test case using argument matcher for only one argument and passed actual value for the other then Mockito will throw following error

The error message is self explanatory and it give a right solution to the mistake! This is the Mockito's goodness, its extremely intuitive and gives us an awesome error messages!

Moving on, now that we know how to correctly stub anotherBusinessProcess method lets look at the whole test code

anyString does the job for us. But the problem is, it will match any string (well, that is exactly its job! which it does well BTW), what if we want to say that the second argument should startWith "Another argument "?

Mockito has a solution for this as well! Use the startsWith argument matcher.

here is the complete test code.

Mockito has lot of built in argument matchers that we could use, I strongly suggest looking at this link for more examples.

Other argument matchers that could be of interest.

  • isNull - Matches an argument that is null
  • isNotNull - Matches an argument that is not null
  • isA - Matches an argument that is A instance of the given Class
  • endsWith - String that ends with the given value
  • anyCollection - Matches any collection
  • anyMap - Matches any map
  • matches - Matches a regular expression
  • any - Matches any object.
Have some Fun!