Mocking a final method with PowerMock + EasyMock

匿名 (未验证) 提交于 2019-12-03 08:44:33

问题:

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.

回答1:

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)



回答2:

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.



回答3:

Why bother mocking the call to the resource bundle? Generally, I try to avoid mocking the nuts and bolts of java, such as ArrayList, Date, etc. Resource bundles (and MessageFormat.format()) more or less fall into the same category for me. They generally operate on strings which are fundamentals, and if these things are broken or changing their behavior enough to break a test it's definitely something I want to know :)

Just let them grab the string (which presumably is about to be set in the UI, perhaps after . Don't bother to assert the value returned since you don't want edits to the bundle to break your test. If the string gets set on a mock UI component, This is a good place for anyObject(String.class) which correctly expresses the fact you (probably) don't actually care about the specific string displayed.

I also consider it a benefit when the test fails due to a missing message key. THAT I want to know.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!