powermock模拟对象_使用PowerMock测试对象的内部状态

powermock模拟对象

大多数单元测试都集中于测试对象的行为以证明其有效。 这可以通过编写一个JUnit测试来实现,该测试调用对象的公共方法,然后测试这些调用的返回值是否与先前定义的一组期望值匹配。 这是一种非常常见且成功的技术。 但是,不应忘记对象也显示状态。 由于它是隐藏的,因此经常被忽略。

我于1995年夏季首次阅读Grady Booch的1994年的《 面向对象的分析和设计 》一书,它通过以下方式定义了对象的状态:

对象的状态包含对象的所有(通常是静态)属性以及这些属性中每个属性的当前(通常是动态)值。

他使用自动售货机示例定义了静态和动态状态之间的差异。 静态状态是通过机器始终准备好拿钱的方式表现出来的,而动态状态是在任何给定实例中获得的钱数。

我怀疑在这一点上,您会正确地辩称,明确的行为测试确实会测试对象的状态,这是因为给定的方法调用返回了正确的结果,并且要获得正确的结果,对象的状态也必须是是的...我会同意的。 但是,在极少数情况下,经典行为测试不适用。 当公共方法调用没有输出并且对对象不执行任何操作(更改其状态)时,会发生这种情况。 一个示例是返回void的方法或构造函数。 例如,给定一个具有以下签名的方法:

public void init();

…如何确保其完成工作? 事实证明,有几种方法可以用来实现这一目标……

  • 向您的类中添加许多getter方法。 这不是一个特别好的主意,因为您只是在松开后门的封装。
  • 放松封装:将私有实例变量打包为私有。 一个非常有争议的事情。 您可能会务实地认为,经过良好测试,正确和可靠的代码可能比高度封装更好,但是我在这里不太确定。 这可能是一个短期修复,但将来可能会导致各种问题,因此应该有一种编写经过良好测试,正确和可靠的代码的方式,其中不包括破坏对象的封装
  • 编写一些使用反射来访问对象内部状态的代码。 这是迄今为止最好的主意。 不利的一面是,这需要付出相当大的努力,并且需要一定数量的编程能力。
  • 使用PowerMock的Whitebox测试课程为您完成艰苦的工作。

以下完全人为设计的场景演示了PowerMock的Whitebox类的用法。 它需要一个非常简单的AnchorTag <a>类,该类将在测试输入URL字符串有效之后构建一个锚标记。

public class AnchorTag {

  private static final Logger logger = LoggerFactory.getLogger(AnchorTag.class);

  /** Use the regex to figure out if the argument is a URL */
  private final Pattern pattern = Pattern.compile("^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$");

  /**
   * A public method that uses the private method
   */
  public String getTag(String url, String description) {

    validate(url, description);
    String anchor = createNewTag(url, description);

    logger.info("This is the new tag: " + anchor);
    return "The tag is okay";
  }

  /**
   * A private method that's used internally, but is complex enough to require testing in its own right
   */
  private void validate(String url, String description) {

    Matcher m = pattern.matcher(url);

    if (!m.matches()) {
      throw new IllegalArgumentException();
    }
  }

  private String createNewTag(String url, String description) {
    return "<a href=\"" + url + "\">" + description + "</a>";
  }
}

URL验证测试是使用正则表达式和Java Pattern对象完成的。 使用Whitebox类将确保正确配置模式对象,并且我们的AnchorTag处于正确的状态。 下面的JUnit测试证明了这一点:

/**
   * Works for private instance vars. Does not work for static vars.
   */
  @Test
  public void accessPrivateInstanceVarTest() throws Exception {

    Pattern result = Whitebox.<pattern> getInternalState(instance, "pattern");

    logger.info("Broke encapsulation to get hold of state: " + result.pattern());
    assertEquals("^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$", result.pattern());
  }

该测试的关键是该行:

Pattern result = Whitebox.<pattern> getInternalState(instance, "pattern");

…使用反射返回Pattern对象的私有实例变量。 一旦访问了该对象,我们就可以简单地通过调用以下命令询问它是否已正确初始化:

assertEquals("^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$", result.pattern());

总而言之,我建议仅在无法将简单的经典JUnit测试用于行为测试时,才应使用PowerMock显式测试对象的内部状态。 话虽如此,它是工具箱中的另一个工具,可以帮助您编写更好的代码。

参考:来自JCG合作伙伴的 PowerMock测试对象的内部状态 调试队长博客上的 Roger。

相关文章 :

翻译自: https://www.javacodegeeks.com/2011/10/testing-objects-internal-state-with.html

powermock模拟对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值