Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerMock EasyMock Fundamentals

This one is probably a PowerMock/EasyMock 101 question which I cannot figure out why. I have a class C with methods

public static boolean testInner(String s) {
    return false;
}

public static boolean testOuter() {
    String x = "someValue";
    return testInner(x);
}

In my test of testOuter() method I want to ensure testInner is called with appropriate parameter. To do so, I am doing something like this: [@RunWith(PowerMockRunner.class) @PrepareForTest(EmailUtil.class) declared at Class level]

EasyMock.expect(C.testInner("blabla")).andReturn(true);
PowerMock.replayAll();
boolean status = C.testOuter();
PowerMock.verifyAll();  
assertTrue(status);

But I am getting error as:

java.lang.AssertionError: 
Unexpected method call testOuter():
testInner("blabla"): expected: 1, actual: 0
    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:45)
    at org.powermock.api.easymock.internal.invocationcontrol.EasyMockMethodInvocationControl.invoke(EasyMockMethodInvocationControl.java:95)
    at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:105)
    at org.powermock.core.MockGateway.methodCall(MockGateway.java:60)
    at C.testOuter(C.java)

I replaced the actual parameter with EasyMock.IsA(String.class) but still no luck. I am pretty sure I am doing something fundamentally silly here. Any help?

like image 706
phewataal Avatar asked Jan 26 '12 18:01

phewataal


People also ask

How does EasyMock work?

easymock. EasyMock: mock(…): generates a mock of the target class, be it a concrete class or an interface. Once created, a mock is in “recording” mode, meaning that EasyMock will record any action the Mock Object takes, and replay them in the “replay” mode.

What is difference between Mockito and Powermock?

While Mockito can help with test case writing, there are certain things it cannot do viz:. mocking or testing private, final or static methods. That is where, PowerMockito comes to the rescue. PowerMockito is capable of testing private, final or static methods as it makes use of Java Reflection API.

What is EasyMock expect?

The expect() method tells EasyMock to simulate a method with certain arguments. The andReturn() method defines the return value of this method for the specified method parameters. The times() method defines how often the Mock object will be called. The replay() method is called to make the Mock object available.

Which among the following are benefits of using EasyMock?

Benefits of EasyMockNo Handwriting − No need to write mock objects on your own. Refactoring Safe − Renaming interface method names or reordering parameters will not break the test code as Mocks are created at runtime. Return value support − Supports return values. Exception support − Supports exceptions.


1 Answers

I think there are two issues here, one has to do with a missing call in your test code. The second has to do with your understanding of behavioral mocking and the difference between full and partial mocking.

Missing Calls

You seem to be missing a call to PowerMock.mockStatic or one of the PowerMock.mockPartialMock methods (see also this). The first method will mock all static methods passed to it, while the second will mock only the list of methods it's given.

An Example

Here's a complete example with two test methods that illustrate the two options. First, we have to annotate the test class using these two annotations:

@RunWith(PowerMockRunner.class)
@PrepareForTest(Dummy.class)
public class DummyTest {

The first annotation tells JUnit to run the test using PowerMockRunner. The second annotation tells PowerMock to prepare to mock the class Dummy.

Full Static Mock

Next, we'll look at the an example where all the static methods from class Dummy are mocked. What does this mean? It means essentially that we'll like to replace the actual implementation with fake ones (mocks). How should this fake implementation behave? This is what we specify in expectation.

Thus, in the testStaticMock method, we're telling EasyMock to give us a fake implementation of the two methods. We'll like the fake Dummy.testOuter to simply return true. And we'll like the fake Dummy.testInner to return true when passed the argument "bb". Note that when these mocks are activated (PowerMock.replayAll), the test code will only run the fake methods and not the actual implementation -- this appears to be the source of your confusion. I have more to say on that later.

    @Test
    public void testStaticMock() {
        mockStatic(Dummy.class);
        EasyMock.expect(Dummy.testOuter()).andReturn(true);
        EasyMock.expect(Dummy.testInner("bb")).andReturn(true);
        replayAll();
        boolean status = Dummy.testOuter();
        Assert.assertTrue(status);
        status = Dummy.testInner("bb");
        Assert.assertTrue(status);
        verifyAll();
    }

Partial Static Mock

Here is another test where we don't mock all the methods, only the ones that we pass to mockStaticPartial. Below, we are telling PowerMock that we only want to mock the method Dummy.testInner. Thus, part of Dummy is mocked and the rest is the class under test.

    @Test
    public void testPartialStaticMock() {
        mockStaticPartial(Dummy.class, "testInner");
        EasyMock.expect(Dummy.testInner("someValue")).andReturn(true);
        replayAll();
        boolean status = Dummy.testOuter();
        verifyAll();
        Assert.assertTrue(status);
    }
}

And let the mocked class Dummy be defined as follows:

public class Dummy {
    public static boolean testInner(String s) {
        return false;
    }

    public static boolean testOuter() {
        String x = "someValue";
        return testInner(x);
    }
}

Full mocking vs Partial Mocking

One thing to understand about full static mocking is that all the static methods are mocked. Thus, the method testOuter will be replace by a mocked version will have a implementation such as the following:

    public static boolean testOuter() {
        return true; //or whatever value is provided in the expectation
    }

Thus, we shouldn't expect the mocked version to invoke methods that the actual implementation does. We didn't want to care about the internals of the method. This was the reason, we decided to mock it anyway -- to replace its internals with a toy implementation, defined only by the expectation we set for it.

One the other hand, when we did partial mocking, we didn't mock testOuter, so we were invoking its actual implementation.

like image 141
rrufai Avatar answered Sep 21 '22 11:09

rrufai