我读了很多关于使用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个这样的静态方法,重构并不是一个真正的选择。类似地,在其他一些静态方法中,正在检索数据库连接。
例如:如何模拟资源包ENTRIES_bundle并对该方法进行单元测试?我正在寻找一种可以普遍应用于所有静态方法的模式。
使用ResourceBundle.getBundle(String,ResourceBundle.Control)让ResourceBundle为给定的String缓存一个bundle。您可以将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() );
}
};
您不需要模拟ResourceBundle.getBundle
方法。只需在测试源树的适当位置创建一个".properties"文件即可。这仍然是一个非常好和有用的单元测试。
我们在模拟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({ClassThatCallsSystemClass.class})不是ResourceBundle类!
如果您使用以下库: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);
}