但是,當您沒有依賴項注入并且使用的第三方庫包含某個包含靜態方法的特定年份的類時,會發生什么? 一種方法是通過在它們周圍編寫包裝器或適配器并在測試過程中提供隔離來隔離這些類。 但是,還有另一種方法:使用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 bundleLocale 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 {@Mockprivate ResourceBundle bundle;private UsesResourceBundle instance;@Beforepublic void setUp() {instance = new UsesResourceBundle();}@Testpublic 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。
- JUnit 4.9(測試版3)中的規則
- 使用PowerMock測試對象的內部狀態
- Servlet 3.0異步處理可將服務器吞吐量提高十倍
- 用Scala測試
- Java工具:源代碼優化和分析
- Java教程和Android教程列表
翻譯自: https://www.javacodegeeks.com/2011/11/mock-static-methods-with-powermock.html