Wednesday, April 28, 2010

PowerMock - Mocks on Steriods!

I have been developing software for some time now.  But have never seen a mocking/stubbing framework (in the java world) that is able to mock/stub everything!  literally everything!

People will argue that, the need to mock static methods, final classes/methods, mock static class, etc. is a sign of bad coding.  I couldn't agree more!  But time and again I have come to terms with a fact that there is a lot of legacy code people have already written and we are inevitably faced with situations where we have to work with it.  In such situations mocking framework like PowerMock is a real boon!

PowerMock basically extends other mocking libraries such as Mockito, EasyMocks and now even TestNGPowerMock uses a custom class-loader and byte-code manipulation to enable mocking of static methods, final classes/methods, etc.  Because of this, no changes need to be done to the IDE or continuous integration servers which simplifies adoption.

PowerMocks have the following capabilities

  • Extends various well known mocking frameworks like Mockito, EasyMocks and TestNG.  Hence, it has an extremely low learning curve if you are familiar with any of of those mocking libraries.
  • Can 
    • mock static methods
    • mock final methods
    • mock static classes
    • mock final classes
    • mock constructors
    • mock private methods
    • remove static initializes
    • partially mock a class i.e. create spy
    • Suppress methods
    • Suppress constructors
    • Suppress static initializes
    • Suppress fields!
    • On top of all this it can also mock/stub normal classes and interfaces :)
Wow! now that's what I call a mocking framework on steroids!

Well, if you like what you are reading and what to see some code in action, stay tuned in the next series of posts I will show working samples of how actually its done!

As usual, feedback, comments and complaints are always welcome!

4 comments:

  1. Good intro, and I agree that such a mocking framework becomes necessary when dealing with legacy code (even if you want to start refactoring to make it better).

    Have you given JMockit a shot? How does it compare to PowerMock?

    I'm part of a project right now where we need to work on legacy code and we spiked both PowerMock and JMockit... we finally chose JMockit.

    ReplyDelete
  2. Yes, I was using JMockit before I switched to PowerMocks (Mockito extension api).

    I agree both the frameworks are extremely powerful and can mock almost anything.

    The main reason for my switch was the compact and English like syntax that Mockito offers.

    For e.g. To mock a static method All i have to write is
    when(SomeClass.someStaticMethod()).thenReturn(someReturnValue)

    while in JMockit the code reads like

    new Expectations()
    {
    {
    SomeClass.someStaticMethod(); result = someReturnValue;
    }
    };


    I felt the PowerMocks (Mockito) syntax is much more compact and readable.

    The end effect, my test cases were visibly shorter and easier to read.

    ReplyDelete
  3. No doubt such powerful tool might be very useful sometimes. Yet, some would question benefits of its usage. I blogged about this subject some time ago: http://kaczanowscy.pl/tomek/2010-12/developers-testing-dilemma-aim-at-verification-or-design

    --
    Cheers,
    Tomek Kaczanowski
    http://kaczanowscy.pl/tomek/

    ReplyDelete
  4. i need to create testcase for following class. Can u explain me so that i can do it for similar classes.I am new to mocking.



    @Repository("accountHistoryRepositoty")
    public class AccountHistoryRepositotyImpl implements AccountHistoryRepository {

    @Autowired
    private HoldingServiceClient holdingServiceClient;
    @Autowired
    private HoldingServiceRequestHelper cimRequestHelper;
    @Autowired
    private AccountHistoryCimAdapter cimAccountHistoryResponseHelper;

    @Autowired
    private CIMJaxbUtil cimJaxbUtil;


    private static final Logger LOG = LoggerFactory.getLogger(AccountHistoryRepositotyImpl.class);

    @Override
    public FinancialActivity getAccountHistoryDetail(
    final AccountHistoryDetailRequest request, final Holding holding,
    FinancialActivity financialActivity) throws Exception {
    // TODO Auto-generated method stub

    HoldingInquiryDetailRequest cimRequest = cimRequestHelper.getAccountHistoryDetail(request, holding, financialActivity);

    LOG.debug("Request being sent to business for Account History Details \n"+ cimJaxbUtil.holdingInquiryRequestToString(cimRequest));
    HoldingInquiryDetailResponse cimResponse = holdingServiceClient.getHoldingInquiryPort().getFinancialHistoryDetail(cimRequest);
    LOG.debug("Request being sent to business for Account History Details \n"+ cimJaxbUtil.holdingInquiryResponseToString(cimResponse));

    return cimAccountHistoryResponseHelper.parseAccountHistoryDetail(cimResponse);
    }

    @Override
    public List getAccountHistoryList(final AccountHistoryListRequest request, final Holding holding) throws Exception {

    HoldingInquiryDetailRequest cimRequest = cimRequestHelper.getAccountHistoryList(request,holding);

    LOG.debug("Request being sent to business for Account History List \n"+cimJaxbUtil.holdingInquiryRequestToString(cimRequest));
    HoldingInquiryDetailResponse cimResponse = holdingServiceClient.getHoldingInquiryPort()
    .getFinancialHistoryList(cimRequest);
    LOG.debug("Response recieved from business for Account History List \n"+cimJaxbUtil.holdingInquiryResponseToString(cimResponse));

    return cimAccountHistoryResponseHelper.parseAccountHistoryList(cimResponse);

    }


    }

    ReplyDelete

Have some Fun!