【问题标题】:Mocking a final method with PowerMock + EasyMock使用 PowerMock + EasyMock 模拟最终方法
【发布时间】:2012-08-23 15:51:56
【问题描述】:

我正在尝试模拟对最终方法 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 的类型显示为“EasyMock for class java.util.ResourceBundle”,因此模拟被正确注入。 (另外,在设置过程中,在expect() 调用中对getString() 的调用没有错误)。

使用普通模拟而不是漂亮模拟,我收到以下错误:

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

知道我做错了什么吗?

谢谢。

【问题讨论】:

    标签: easymock powermock


    【解决方案1】:

    您正在使用 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();
        }
    }
    

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

    【讨论】:

    • 我也面临同样的问题。但这仍然没有帮助。您是指仅最终方法还是静态方法?
    • @Siddharth {{PowerMock.mockStaticNice()}} 模拟一个类的一个静态方法,但保持其余方法不变。如果此主题对您没有帮助,您应该创建一个新问题,因为您似乎遇到了不同的问题。
    • 感谢您的回复@Andy。但是这个线程的主题谈论的是 final 方法,但你谈论的是静态方法。我错过了什么吗?我的问题是我试图模拟“public final void”方法,并且测试调用的是实际方法而不是模拟。上述问题与我所说的不同吗?对不起,如果我错过了一些点。
    • PowerMock 也适用于 final 方法。我现在无法测试它,所以我可以为您指出正确的方向。有时我在使用 Java-Internals 的 PowerMock 模拟方法时遇到了问题(即 {{System.currentTimeMillis()}} - 由于 PowerMock 的工作方式,它无法模拟它,所以我使用了 jMockit ,它就像一个魅力,但使用起来完全不同。
    【解决方案2】:

    尝试使用:

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

    仅在 PrepareForTest 中使用 ResourceBundle,当直接从您的单元测试方法调用时,mock 将起作用,但从 BeanBeingTested 调用时,您会得到正在使用的真实方法。

    这方面缺少 Powermock 文档。

    【讨论】:

      【解决方案3】:

      为什么还要模拟对资源包的调用呢?通常,我尽量避免嘲笑 java 的具体细节,例如 ArrayList、Date 等。资源包(和 MessageFormat.format())对我来说或多或少属于同一类别。他们通常在基本的字符串上操作,如果这些东西被破坏或改变它们的行为足以破坏测试,那绝对是我想知道的:)

      让他们抓住字符串(大概是在 UI 中设置,可能在 之后。不要费心断言返回的值,因为您不希望对包的编辑破坏您的测试。如果string 在模拟 UI 组件上设置,这是 anyObject(String.class) 的好地方,它正确表达了您(可能)实际上并不关心显示的特定字符串的事实。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-30
        • 1970-01-01
        • 2016-12-05
        • 2017-05-19
        相关资源
        最近更新 更多