使用PowerMock + EasyMock模拟最终方法

时间:2012-08-23 15:51:56

标签: easymock powermock

我正在尝试模拟对最终方法ResourceBundle.getString()的调用。使用PowerMock 1.4.12和EasyMock 3.1,呼叫不会被嘲笑;相反,调用“真实”方法。

我的测试班:

@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);
    }
    ...
}

BeanBeingTested中的代码:

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

错误讯息:

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)

当我逐步完成测试用例时,调试器将beanBeingTested.messages的类型显示为“类java.util.ResourceBundle的EasyMock”,因此正确注入了mock。 (另外,在设置过程中,getString()来电中expect()的来电没有错误。

使用普通模拟而非模拟,我收到以下错误:

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

知道我做错了吗?

感谢。

3 个答案:

答案 0 :(得分:3)

您正在使用EasyMock创建实例。相反,在使用静态方法时,必须模拟(使用PowerMock)。

它应该像那样(用EasyMock 3.0和PowerMock 1.5进行测试):

@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();
    }
}

(我知道这个问题已经有几个月了,但它可能对其他人有所帮助)

答案 1 :(得分:1)

尝试使用:

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

只有在PrepareForTest中使用ResourceBundle时,模拟在直接从单元测试方法调用时才会起作用,但是当从BeanBeingTested调用时,您将获得正在使用的实际方法。

此领域缺乏Powermock文档。

答案 2 :(得分:0)

为什么要打扰模拟对资源包的调用?一般来说,我试图避免模仿java的细节,比如ArrayList,Date等。资源包(和MessageFormat.format())或多或少都属于同一类别。它们通常以字符串为基础进行操作,如果这些事情被破坏或改变其行为足以打破测试,那肯定是我想知道的事情:)

让他们抓住字符串(可能是在UI中设置,也许是在之后。不要打扰断言返回的值,因为你不想编辑捆绑包来破坏你的测试。如果string在一个模拟UI组件上设置,这是anyObject(String.class)的一个好地方,它正确地表达了你(可能)实际上并不关心显示的特定字符串的事实。

当测试由于缺少消息密钥而失败时,我也认为这是一个好处。我想知道。