Showing posts with label argument matchers. Show all posts
Showing posts with label argument matchers. Show all posts

Saturday, July 24, 2010

How to use custom argument matchers using PowerMock

We have come a long way and most likely this will be the last post in the series of how-to do stuff using PowerMock's (Mockito api) - Mocks on Steroid!

Some of the posts in the how-to series are more exotic then the others, but if you want to experience the real power of PowerMock, have a look at testing the UN-testable code.

In the previous post, we saw how we could use various argument matches, in situation when we don't know exactly what argument will be passed. Mockito already has a rich set of matchers but, if you think that is not enough we can write our own Matchers.

Why would you need them? Good question. In most cases the build in matchers are enough, but we might need custom matches when we want to make sure that a certain property of a certain class is set to a certain value.

Well did you understand that above sentence? No? Even I didn't understand that :)

As people say

Picture says a thousand words

my version of the same quote is

Code says everything

So lets look at the code under test.

Look at the argument passed to calculateChargeAmount method.  ServiceA's calculateChargeAmount passes a new instance of Calender to this method.

Of-course by now you already know how to test such a code. But since this post is about custom argument matchers, we will try to write a test for this method using the custom argument matcher.

But how do we write a custom argument matcher?

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

Well, turns out Mockito has a class called ArgumentMatcher. To create a custom matcher we extend the class ArgumentMatcher and override the matches method which returns a boolean.

If the matches method returns
  • true: means that the argument passed matches the criteria
  • false: means that the argument passed does not match the criteria
Along with this we need to use an argument matcher called argThat provided by Mockito. This argument matcher takes in an instance of our custom matcher, which will in-turn decide whether the argument passed matches our criteria.

Lets say in our example, we just want to make sure that the Calendar instance passed to the calculateChargeAmount method represents a date in the future.

This is how we could make use of the custom matcher in this case

Thats it folks! This is how we write custom argument matcher using Mockito.

It has been a pleasure doing this how-to series. I hope you guys have liked reading it as much as I have liked writing about it!

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!