但是,当您没有依赖项注入并且使用的第三方库包含某个包含静态方法的特定年份的类时,会发生什么? 一种方法是通过在它们周围编写包装器或适配器并在测试过程中提供隔离来隔离这些类。 但是,还有另一种方法:使用PowerMock。 PowerMock是一个模拟框架,可扩展其他模拟框架以提供急需的其他功能。 模仿旧广告:“它刷新了其他模拟框架无法达到的部分”。
该博客介绍了PowerMock模拟静态方法的能力,并提供了一个模拟JDK的ResourceBundle类的示例,众所周知,该类使用ResourceBundle.getBundle(...)来…加载资源束。
与许多其他博客作者和作家一样,我通常会提出一些高度人为的方案来突出问题。 今天有所不同,我只得到了一个使用ResourceBundle的类,称为:UsesResourceBundle:
public class UsesResourceBundle {
private static Logger logger = LoggerFactory.getLogger(UsesResourceBundle.class);
private ResourceBundle bundle;
public String getResourceString(String key) {
if (isNull(bundle)) {
// Lazy load of the resource bundle
Locale locale = getLocale();
if (isNotNull(locale)) {
this.bundle = ResourceBundle.getBundle("SomeBundleName", locale);
} else {
handleError();
}
}
return bundle.getString(key);
}
private boolean isNull(Object obj) {
return obj == null;
}
private Locale getLocale() {
return Locale.ENGLISH;
}
private boolean isNotNull(Object obj) {
return obj != null;
}
private void handleError() {
String msg = "Failed to retrieve the locale for this page";
logger.error(msg);
throw new RuntimeException(msg);
}
}
您可以看到有一个方法:getResourceString(…),给定一个键将从包中检索资源字符串。 为了使这项工作更有效率,我懒洋洋地加载了我的资源包,加载后,我调用bundle.getString(key)检索我的资源。 为了测试这一点,我编写了一个PowerMock JUnit测试:
import static org.easymock.EasyMock.expect;
import static org.junit.Assert.assertEquals;
import static org.powermock.api.easymock.PowerMock.mockStatic;
import static org.powermock.api.easymock.PowerMock.replayAll;
import static org.powermock.api.easymock.PowerMock.verifyAll;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.annotation.Mock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(UsesResourceBundle.class)
public class UsesResourceBundleTest {
@Mock
private ResourceBundle bundle;
private UsesResourceBundle instance;
@Before
public void setUp() {
instance = new UsesResourceBundle();
}
@Test
public final void testGetResourceStringAndSucceed() {
mockStatic(ResourceBundle.class);
expect(ResourceBundle.getBundle("SomeBundleName", Locale.ENGLISH)).andReturn(bundle);
final String key = "DUMMY";
final String message = "This is a Message";
expect(bundle.getString(key)).andReturn(message);
replayAll();
String result = instance.getResourceString(key);
verifyAll();
assertEquals(message, result);
}
@Test(expected = MissingResourceException.class)
public final void testGetResourceStringWithStringMissing() {
mockStatic(ResourceBundle.class);
expect(ResourceBundle.getBundle("SomeBundleName", Locale.ENGLISH)).andReturn(bundle);
final String key = "DUMMY";
Exception e = new MissingResourceException(key, key, key);
expect(bundle.getString(key)).andThrow(e);
replayAll();
instance.getResourceString(key);
}
@Test(expected = MissingResourceException.class)
public final void testGetResourceStringWithBundleMissing() {
mockStatic(ResourceBundle.class);
final String key = "DUMMY";
Exception e = new MissingResourceException(key, key, key);
expect(ResourceBundle.getBundle("SomeBundleName", Locale.ENGLISH)).andThrow(e);
replayAll();
instance.getResourceString(key);
}
}
在上面的代码中,我采取了不寻常的步骤,包括导入语句。 要强调的是,我们使用的是PowerMock的导入静态版本,而不是EasyMock的静态版本。 如果您不小心导入了EasyMock的静态函数,那么整个过程将不起作用。
设置模拟静态调用的测试有四个简单的步骤:
1.使用PowerMock JUnit运行器:
@RunWith(PowerMockRunner.class)
2.声明我们要嘲笑的测试类:
@PrepareForTest(UsesResourceBundle.class)
3.告诉PowerMock包含静态方法的类的名称:
mockStatic(ResourceBundle.class);
4.设置期望值,告诉PowerMock期望对静态方法的调用:
expect(ResourceBundle.getBundle("SomeBundleName", Locale.ENGLISH)).andReturn(bundle);
其余的工作很顺利,您可以为其他标准方法调用设置期望,并告诉PowerMock / EasyMock运行测试,并验证结果:
final String key = "DUMMY";
final String message = "This is a Message";
expect(bundle.getString(key)).andReturn(message);
replayAll();
String result = instance.getResourceString(key);
verifyAll();
PowerMock可以做更多的事情,例如模拟构造函数和私有方法调用。 也许以后再说……
参考: 使用PowerMock来模拟我们JCG合作伙伴的 静态方法 调试队长博客上的 Roger。
翻译自: https://www.javacodegeeks.com/2011/11/mock-static-methods-with-powermock.html