2

我已经阅读了很多关于使用 Powermock 和 Mockito 的文章并尝试了很多不同的方法,但我仍然无法弄清楚如何对下面的静态方法进行单元测试。

public static Map<String, String> getEntries() {
    Map<String, String> myEntriesMap = new TreeMap<String, String>();
    ResourceBundle myEntries = ResourceBundle.getBundle(ENTRIES_BUNDLE);
    Enumeration<String> enumList = myEntries.getKeys();
    String key = null;
    String value = null;
    while (enumList.hasMoreElements()) {
        key = enumList.nextElement().toString();
        value = myEntries.getString(key);
        myEntriesMap.put(key, value);
    }
    return myEntriesMap;
}

该代码是包含大约 30 个这样的静态方法的(遗留)类的一部分,重构并不是一个真正的选择。类似地,在其他一些静态方法中,正在检索 DBconnections。

例如:我如何模拟资源包 ENTRIES_BUNDLE 并对这个方法进行单元测试?我正在寻找一种可以普遍应用于所有静态方法的模式。

4

4 回答 4

10

使用 ResourceBundle.getBundle(String, ResourceBundle.Control) 让 ResourceBundle 缓存给定字符串的包。您可以继承 ResourceBundle.Control 以提供您想要的任何类型的捆绑包。

@Test
public void myTest()
{
    // In your Test's init phase run an initial "getBundle()" call
    // with your control.  This will cause ResourceBundle to cache the result.
    ResourceBundle rb1 = ResourceBundle.getBundle( "blah", myControl );

    // And now calls without the supplied Control will still return
    // your mocked bundle.  Yay!
    ResourceBundle rb2 = ResourceBundle.getBundle( "blah" );
}

这是子类控制:

ResourceBundle.Control myControl = new ResourceBundle.Control()
{
    public ResourceBundle newBundle( String baseName, Locale locale, String format,
            ClassLoader loader, boolean reload )
    {
        return myBundle;
    }
};

这是模拟 ResourceBundle 的一种方法(使用单元测试所需的键/值填充 TreeMap,留给读者作为练习):

ResourceBundle myBundle = new ResourceBundle()
{
    protected void setParent( ResourceBundle parent )
    {
      // overwritten to do nothing, otherwise ResourceBundle.getBundle(String)
      //  gets into an infinite loop!
    }

    TreeMap<String, String> tm = new TreeMap<String, String>();

    @Override
    protected Object handleGetObject( String key )
    {
        return tm.get( key );
    }

    @Override
    public Enumeration<String> getKeys()
    {
        return Collections.enumeration( tm.keySet() );
    }
};
于 2015-02-21T00:18:25.993 回答
6

您不需要模拟该ResourceBundle.getBundle方法。只需在测试源代码树的适当位置创建一个“.properties”文件即可。这仍然是一个非常好的和有用的单元测试。

于 2013-08-22T13:40:22.447 回答
1

我们在模拟 ResourceBundle.getString() 方法时遇到了类似的问题。

java.util.MissingResourceException: Can't find resource for bundle $java.util.ResourceBundle$$EnhancerByMockitoWithCGLIB$$e9ea44f0, key name

我们的问题是该方法是最终的,这使得 mockito 无法模拟该方法。

相反,我们使用了这个灵魂:https ://code.google.com/p/powermock/wiki/MockSystem

请注意,@PrepareForTest({ClassThatCallsTheSystemClass.class}) 不是 ResourceBundle 类!

于 2014-02-11T15:29:31.883 回答
0

如果您使用以下库:mockito-all 和 jmockit,请执行以下步骤:

假设你想从 xxxx.class 模拟方法 yyyy

@MockClass(realClass = xxxx.class)
public static class MyClass {
     @Mock
     public static void yyyy(){
          ......
     }
}

在你的测试中:

@Test
public void test() {
     Mockit.setUpMock(MyClass.class);
}
于 2013-08-22T11:20:17.133 回答