Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking a final method with PowerMock + EasyMock

I'm trying to mock a call to the final method ResourceBundle.getString(). With PowerMock 1.4.12 and EasyMock 3.1, the call is not being mocked; instead, the "real" method is called.

My test class:

@RunWith(PowerMockRunner.class)
@PrepareForTest(ResourceBundle.class) 
public class TestSuite {
    @Before
    public void setUp() throws Exception {
        ResourceBundle resourceBundleMock = PowerMock.createNiceMock(ResourceBundle.class);
        expect(resourceBundleMock.getString(BundleConstants.QUEUE)).andReturn("Queue");
        PowerMock.replay(resourceBundleMock);

        beanBeingTested.setMessages(resourceBundleMock);
    }
    ...
}

Code in BeanBeingTested:

private ResourceBundle messages;
...
String label = messages.getString(BundleConstants.QUEUE);

Error message:

java.util.MissingResourceException: Can't find resource for bundle $java.util.ResourceBundle$$EnhancerByCGLIB$$e4a02557, key Queue
at java.util.ResourceBundle.getObject(ResourceBundle.java:384)
at java.util.ResourceBundle.getString(ResourceBundle.java:344)
at com.yoyodyne.BeanBeingTested.setUpMenus(BeanBeingTested.java:87)

When I step through the test case, the debugger shows the type of beanBeingTested.messages as "EasyMock for class java.util.ResourceBundle", so the mock is injected correctly. (Also, there's no error on the call to getString() within the expect() call during set up).

With a plain mock instead of a nice mock, I get the following error:

java.lang.AssertionError: 
  Unexpected method call handleGetObject("Queue"): 
    getString("Queue"): expected: 1, actual: 0

Any idea what I'm doing wrong?

Thanks.

like image 293
Mike Woinoski Avatar asked Aug 23 '12 15:08

Mike Woinoski


People also ask

Can you mock a final method?

Methods marked as final will be proxied to the original method, i.e., final methods can't be mocked.

How do you mock on EasyMock?

EasyMock also supports injecting mocks using annotations. To use them, we need to run our unit tests with EasyMockRunner so that it processes @Mock and @TestSubject annotations. Equivalent to mock(…), a mock will be injected into fields annotated with @Mock.

Is EasyMock a mocking framework?

EasyMock is a mocking framework, JAVA-based library that is used for effective unit testing of JAVA applications. EasyMock is used to mock interfaces so that a dummy functionality can be added to a mock interface that can be used in unit testing.


2 Answers

You are creating an instance using EasyMock. Instead, when working with static methods, you must mock the class (using PowerMock).

It should work like that (tested with EasyMock 3.0 and PowerMock 1.5, though):

@RunWith(PowerMockRunner.class)
@PrepareForTest(ResourceBundle.class) 
public class TestSuite {
    @Before
    public void setUp() throws Exception {
        // mock the class for one method only
        PowerMock.mockStaticNice(ResourceBundle.class, "getString");

        // define mock-behaviour on the class, when calling the static method
        expect(ResourceBundle.getString(BundleConstants.QUEUE)).andReturn("Queue");

        // start the engine
        PowerMock.replayAll();
    }
}

(I'm aware this question is a few months old, but it might help others, though)

like image 166
Andy Avatar answered Sep 27 '22 23:09

Andy


Try using:

@PrepareForTest({ResourceBundle.class, BeanBeingTested.class})

With only ResourceBundle in the PrepareForTest the mock will work when called directly from your unit test method, but when called from BeanBeingTested you get the real method being used.

Powermock documentation is lacking in this area.

like image 20
tom Avatar answered Sep 27 '22 23:09

tom