Wednesday, June 16, 2010

How to test methods of a class whos constructor is evil, using PowerMock

As promised in my previous post, today I will show, the second way to write test cases for methods of a class whose constructor does crazy stuff.
Example of "crazy stuff" would include opening a db connection, load a native library etc. There are many things that would come under the "crazy" umbrella but lets not go there.

Code under test:

You remember our dear friend Mr. LegacyCustomer right? Yes this class has an evil constructor that does some crazy stuff, in our case it throws a RuntimeException. Effectively, this means we can never create an instance of this class, as there is not constructor that we could invoke.

One of the way to test the method getCreditLimit would be to suppress the constructor of LegacyCustomer using the suppress method which we have already seen in the previous post. So what is the other method to test it?

(On the side note, most Mocking framework don't even have one way to write test for the above code but PowerMock's has two ways in which we could test the above code! How awesome!)

How would we test it - How do they do it!

Turns out, there is a class called Whitebox in PowerMocks using which we could instantiate a class without invoking its constructor. Whitebox class has a lot of features to bypass encapsulation of a class but we will discuss those features later. Today lets focus only on instantiating the class and testing the getCreditLimit method.

To instantiate the class using Whitebox class we use the following syntax

The newInstance method on the Whitebox class takes the name of the class that has to be instantiated without calling the constructor.

Now writing the complete test case would be tad simple. Lets look at the complete test code

Note that we don't even need to use the @RunWith and @PrepareForTest annotations. Whitebox class can instantiate LegacyCustomer without even invoking the constructor.

Please note: If we had to write the test case using the suppress method we would have to use the @RunWith and @PrepareForTest annotations.

Life looks a lot better when we have powerful tools like PowerMock (with Mockito api) at hand!
Have some Fun!