Tuesday, May 25, 2010

How to partially mock a class and its private methods using PowerMock

Earlier, in the how-to series we had seen how-to mock constructors.  In this post we will have a look at how-to partially mock classes and even their private methods using PowerMocks - Mocks on Steroids!

Lets first look at the code to test before I start with my rambling

Code under test:

We want to write a test case to test method1 of ServiceA class.  ServiceA's method1 invokes method2.  method2 performs some complicated business logic - in this case creates an instance of ServiceB and invoked doBusinessOperation on that instance.

There are two approaches to test ServiceA's method1.


  • Write the test case to mock out the ServiceB's constructor and assert that doBusinessOperation method was invoked on the mocked ServiceB object.
  • Stub the method2 call!  Only verify that from method1 a call was made to the method2.

We already know how to write tests for the first approach.  Today we are more interested in looking at how do we write tests for the second approach.

Why would we ever choose the second approach over the first approach?  May be because method2 was already tested in some other test case.  Hence, we just want to make sure that method1 calls method2 with the right arguments.

So how do we partially mock ServiceA?

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

PowerMockito class provides a method called spy to create partial mock of a class.  This method takes an instance of the class that you want to partially mock as argument (in this case ServiceA).  Why? Because we want to invoke actual implementation of method1 and mock only method2.

Syntax

Then, we want to stubb out the method2 and return some dummy value.  This how its done

Notice the difference in the syntax then the regular when-theReturn syntax.  As, if we use the when-thenReturn syntax actual call to method2 will be made!  Why? Because PowerMocks does not know whether you are setting up an expectation on a partial mock or actually invoking the method.  Hence, be careful with partial mocks and choose the right syntax.

How to verify that the method was actually called?

No surprises here.

The full test case would look like:

A variation of the above example, what if the method2 was private?  Can we still stub it?  Of-course the right answer is YES!

Code under test:

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

Now, the above doReturn-when-method2 syntax wont work.  As method2 is private and is not accessible outside the scope of the class.  How do we stub it then?

Only change is, we pass in the name of the private method to stub as string argument to when method.  when method also accepts the var args array of arguments to the method2.

To verify that the private method2 was invoked use

Here also, instead of verify we use verifyPrivate and call a invoke method which accepts, name of the private method and its arguments.

Full test case would look like this:

Yes!  Thats it.  We have achieved what we intended to do!  PowerMock's is really a valuable tool to have in once arsenal!

2 comments:

  1. Hi Deep,
    I got lot of knowledge on PowerMock from your blog but when I tried the methods(doReturn, when , spy to make partial mock) in eclipse then it is not showing these methods.
    In my lib folder I allready have following PowerMock jars:

    powermock-api-easymock-1.3.1.jar
    powermock-api-support-1.3.1.jar
    powermock-classloading-1.3.1.jar
    powermock-core-1.3.1.jar
    powermock-module-junit3-1.3.1.jar
    powermock-module-junit4-1.3.1.jar
    powermock-module-junit4-common-1.3.1.jar
    powermock-module-junit4-legacy-1.3.1.jar
    powermock-reflect-1.3.1.jar

    so please help me that is their any need to add more jars.
    Initialy I was using createMock and expectPrivate methods of power mock but not able to mock no argument methods.
    In power mock , is their any way to mock a method with no arguments.

    So please take me out of this problem , I will be greatly thankful to you.

    Thanks with Regards
    Bhupendra Sharma

    ReplyDelete
  2. Hello Bhupendra,

    All the examples I have sown on my blog are developed using the Mockito extension of PowerMock. It seems that you have the EasyMock extension jars in your classpath because of which you are not able to see the doReturn, when, spy etc. method of Mockito api.

    To solve the problem please remove the powermock-api-easymock-1.3.1.jar from your classpath and add the powermock-api-mockito-1.3.1.jar to your classpath.

    Hope this helps

    ReplyDelete

Have some Fun!