Tuesday, May 25, 2010

How to mock constructors using PowerMock

In the how-to series today I will show how-to mock constructors using PowerMocks - Mocks on Steroids!.  In my previous post we saw how can we write unit-tests for mocking final methods and classes.

Requirement:

Again, taking a fictitious example, lets say that ServiceA creates an instance of ServiceB and invokes a businessOperation on ServiceB's instance.  ServiceB's constructor is evil and it throws a Exception.  We want to test this code.  Lets look at the code under test

As we can see, ServiceA's doSomething method create an instance of ServiceB class (by invoking a constructor with no arguments) and then invokes doBusinessOperation() method.  Looks like a simple class, but wait, have a look at ServiceB's constructor, its evil, it throws an exception!  Now how do we mock the constructor so that we can write a good tests case for ServiceA's doSomething method?  Simple, Using PowerMocks (Mockito api) :)

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

We have to use @PrepareForTest annotation with ServiceA class as, it instanciates ServiceB and we actually want to inject a stub on ServiceB so that we can verify that doBusinessOperation method was actually invoked.

Then, we use the whenNew method of PowerMockito to actually return a stub of ServiceB when a new instance of ServiceB is created using a no argument constructor.

Just read the above line in and then compare the syntax below

We can actually read the code in English and it does make a lot of sense!

Lets look at the test code now:

Piece of cake isn't!

11 comments:

  1. Hi

    Its very nice. This is very help me.

    Brijesh Baser

    ReplyDelete
  2. Hello!! i have a little question here, how could we do to mock a variable that is created by casting?

    i have this method:

    public ActionForward execute(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response)
    {

    ...

    XActionForm form = (XActionForm)actionForm;

    mode = form.getCode();

    ....

    }


    *i can't figure out how to mock that "getCode()" call....

    I tried with

    PowerMockito.whenNew(XActionForm.class).withNoArguments().thenReturn(mockXActionForm);

    when(mockXActionForm.getCode()).thenReturn("1");

    Thanks in advance!!! Your post are exelent.

    ReplyDelete
  3. Hi,

    In your case you don't need to bother about the casting at all. The method "execute" is already taking ActionForm instance as argument and you can pass a mocked XActionForm instance to this method.

    for e.g. lets say the class A has the method execute with the same signature you have shown.

    Now to mock the getCode method on XActionForm you can write code like this.

    XActionForm mockedForm = mock(XActionForm.class);
    // Assuming that getCode returns string
    when(mockedForm.getCode()).thenReturn("Hello World");
    new A().execute(null, mockedForm, null, null)

    Now when getCode method will be invoked on the mockedForm instance it will always return "Hello World"

    That's all you need.

    Hope this helps

    Deep

    ReplyDelete
  4. Hello Deep Shah !!

    Thank you very much for your response!!! It worked exactly as u said... thanks again!! Great work!!!

    ReplyDelete
  5. How can we cast one interface to another. Example
    Interface A
    Interface B
    Code to be tested has a block like
    ((B) a).doSomething();
    JUnit code goes like -
    A a = EasyMock.createMock(A.class);
    B b = EasyMock.createMock(B.class);
    EasyMock.expect((B) a).andReturn(b); This line gives a ClassCastException. Please advice on the same.

    ReplyDelete
  6. If one has to cast the reference of Interface A to Interface B in the code, there is something definitely wrong with the design.

    But lets not discuss that. Lets focus on your problem.

    If the code you want to test looks like this

    public class ServiceA {
    public void doSomething(final A a) {
    final B b = (B) a;
    b.doSomething();
    }
    }

    If there is no direct relationship between interfaces A and B (i.e. there is no inheritance relationship between A and B) then, I would test the above code using the following test case.

    For the above cast to work we need an interface or a class that implements A and B. So lets create a dummy interface C that extends A and B but has no methods of its own.

    /**
    * Creating a dummy interface C which extends interface A and B
    *
    */
    interface C extends A, B {
    }


    public class ServiceATest {
    @Test
    public void shouldTestDoSomething() {
    final C c = mock(C.class);

    new ServiceA().doSomething(c);

    verify(c).doSomething();
    }
    }

    ReplyDelete
  7. Thanks, that's what I needed!

    ReplyDelete
  8. How do you write a mock for the "new" keyword ? To test whether the instance variable is created.
    Ex : Myclass obj = new Myclass();

    ReplyDelete
  9. I have a Class that creates a new Date object in its constructor. I want to create a Date object in my test class and have the call to "new Date()" return my already created Date object (I don't care if it's a mock date object or a real one) so that I can compare them for testing a getDate method that has no corresponding setDate method. Here's what I have:

    MyClass uut;
    private final Date mockDate = new Date();

    PowerMockito.whenNew(Date.class).withNoArguments().thenReturn(mockDate);

    uut = new MyClass();

    Where MyClass's constructor creates the new Date object. When I check the date created by the constructor, it is the most current date, not the date I previously created. Help!

    ReplyDelete
  10. Hi Deep,

    I have a concern here, if you put ServiceA in a PrepareForTest annotation will the coverage for any part of code in ServiceA will be reported?

    Please reply.

    Thanks

    ReplyDelete

Have some Fun!