使用PowerMock模拟静态方法

本文介绍了如何使用PowerMock框架来模拟静态方法,特别是在处理依赖于静态方法的类时。通过示例展示了如何模拟JDK的ResourceBundle类,以及使用PowerMock进行单元测试的步骤,包括设置PowerMock JUnit运行器、声明测试类、指定嘲笑的静态类以及设置期望值。
摘要由CSDN通过智能技术生成
在最近的博客中,我试图强调使用依赖注入的好处,并表达一种想法,即这种技术的主要好处之一是,通过在类之间提供高度的隔离,它可以使您更轻松地测试代码,并且得出的结论是,许多好的测试等于好的代码。

但是,当您没有依赖项注入并且使用的第三方库包含某个包含静态方法的特定年份的类时,会发生什么? 一种方法是通过在它们周围编写包装器或适配器并在测试过程中提供隔离来隔离这些类。 但是,还有另一种方法:使用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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值