powermock模拟对象
我于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.*/@Testpublic 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。
- JUnit 4.9(测试版3)中的规则
- Servlet 3.0异步处理可将服务器吞吐量提高十倍
- 用Scala测试
- Java工具:源代码优化和分析
- Java教程和Android教程列表
翻译自: https://www.javacodegeeks.com/2011/10/testing-objects-internal-state-with.html
powermock模拟对象