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.

How to fix the OutOfMemoryError when writing tests with PowerMock - Part - 2

In my previous post we had a look at How to fix the OutOfMemoryError when writing tests with PowerMock

Looks like, the method I described in that post does not work on all machine or environments.

In one of the environment whose configuration is:
  • Windows 7 64 Bit
  • 4 GB RAM DDR3
  • Intel Core i7 processor
  • JDK 6 64 Bit  
  • PowerMock 1.3.7  
it seemed to work for some time, but as soon as we wrote a few more tests using PowerMock (Mockito api), the OutOfMemoryError re-appeared.

Now that's annoying, what the hell is wrong now!  Well as I said in the previous post memory leaks are hard to find and fix!

But we need a solution now!  Can't wait till PowerMock 1.4 version is released.  Hence, I was on a mission to fix the issue and get all my tests running by hook or crook!

In the process I found that, running the tests on a 32 bit machine had no problems what so ever!  Surprise, Surprise!

Investigated a little further, found that when tests are run on a machine with 64 bit OS but 32 bit JDK they all pass.  That was the moment of Truth!

These are the steps I followed to fix the OutOfMemoryError:
  • Installed the JDK 6 32 bit on my machine
  • Updated the JAVA_HOME environment variable
  • Added the JDK 6 32 bit bin directory to the PATH environment variable
  • Removed the earlier JDK 6 64 bit bin directory from the PATH environment variable.  
All set!  Ran all the test and bingo!  All pass its a SUCCESS!

Saturday, July 3, 2010

How to fix the OutOfMemoryError when writing tests with PowerMock

We use PowerMock (With the Mockito Api) in our current project as the Mocking/Stubbing framework. It has worked our really well so far!

Completely in love with the Mockito syntax and especially the error messages that it gives out when something is wrong.
Love the power that PowerMock adds to Mockito which enables us to test the un-testable code. The combination i.e. PowerMocks with Mockito, makes it a deadly combination to ignore and I call it Mocks on Steroids!

But life is not always perfect! is it? Recently I faced a situation, suddenly out of no where I started getting the

infamous java.lang.OutOfMemoryError: PermGen space  Error here is the stack trace.

Man! its always a challenge to fix such issues.
Googled a little, found that its a known issue have a look at this url

Its caused because of a Memory leak (wow! as if I am telling something new! Its obvious, we get OutOfMemoryError when we have memory leaks! Everyone knows that!). Yes, and as you guys already know finding the source of memory leak is a challenge in itself.

But looks like, they have narrowed the problem down to the MockClassLoader class.

The problem:

If your project uses third party frameworks like log4j or spring, then those classes are also loaded by the MockClassLoader class. Causing log4j or spring classes to be loaded multiple times by multiple instances of MockClassLoader class.

The long term solution:

This problem will be fixed in the PowerMock's 1.4 version for sure!

But what should you do if you can't wait till then?

The short term solution:

Use the @PowerMockIgnore annotation. This annotation signal PowerMock not to load third party framework jars such as log4j and spring using the MockClassLoader. Let the system class loader load them.

The sample test case looks like this

That fixes the problem for our project!

This problem is a perfect example of the fact that, there is always a flip side!
But, if the flip side is not as bad, then as said by Amir Khan in the movie 3 idiots

All izz well!
Have some Fun!