首页 / 软件开发 / JAVA / Java理论与实践: 平衡测试,第3部分:用方面检验设计约束
Java理论与实践: 平衡测试,第3部分:用方面检验设计约束2010-12-22 IBM Brian Goetz面向方面编程(AOP)是项大有前途的新技术,但是采用新技术可能有风险( 当然,不 采用新技术也会有风险)。与所有的新技术一样,通常来说,最好是 沿着一条可以管理风险的路径来采用它们。如果用 AOP 来执行策略和测试,就 可以从 AOP 得到降低风险的好处。因为方面不会进入生产,所以不会出现技术 破坏代码稳定性或开发过程的风险,但却会有助于开发质量更好的软件。用方面 进行测试也是学习方面的工作方式,并体验这项激动人心的新技术的好方法。组合测试方法正如我在 第 1 部分 中讨论过的,QA 的目的不是找到所有可能有的 bug — — 因为这是不可能的 —— 而是提升我们对代码按预期工作的确信程度。对于 管理有效的 QA 组织,它的挑战就是最大化所花费资源的回报,即确信度。因为 所有的测试方法最终都会表现出回报消退(对于等量的付出增加,得到的确信度 增加越来越少),而且不同的方法适合寻找不同类型的错误,所以把 QA 付出分 散在测试、代码审查和静态分析上,要比把整个 QA 预算只花在其中一项措施上 ,回报要更好。FindBugs 这样的静态分析工具是不精确的,但是不精确的分析对于提高软件 质量仍然是非常有用和有效的。它们可能发出假警告,例如在无害的构造上触发 警告,也可能忽略了 bug,例如没有找出与特定 bug 模式匹配的全部 bug。但 是它们仍然能发现真正的 bug,而且只要误报率没有高到让用户厌烦的程度,那 么它们仍然对测试付出提供了有价值的回报。从测试的角度来说,使用 AOP 来验证设计规则与使用静态分析有许多共同之 处。静态分析和面向方面编程都不用为了特定的方法或类设计测试用例,而是都 鼓励找出违犯规则的全部分类,并创建能够发现代码体中任何违规的工件。另一 个相似性就是它们不必非常完善也能够发挥作用;尽管 bug 探测器或测试方面 都不能找出所有可能的 bug,甚至有些会发出假警告,它们仍然是非常有用的工 具,可以验证代码是否按期望的那样工作。有些 bug 模式用静态工具更容易找 出,而另一些用方面会更容易找出 —— 这使得方面成为参与 QA 过程的一个有 用的方法。简单的测试方面FindBugs 这样的静态分析工具审计代码但不执行代码;面向方面的工具既提 供静态类工具,也提供动态类工具。静态方面可以生成编译时警告或错误;动态 方面可以把错误检测代码插入类。在 第 1 部分 中,我提供了一个简单的 FindBugs 探测器,查找可能潜伏在 库中的对 System.gc() 的调用。静态分析能探测的许多 bug 模式(包括这个模 式)也能被方面探测到;根据具体的 bug 模式,用静态分析或用方面来做可能 会更容易,所以把它们都放在工具库中,可以提高效果。清单 1 显示了一个简单的动态方面,在要调用 System.gc() 时,抛出 AssertionError。(因为这类 bug 探测器的一个重要作用是不仅要找到您自己 代码中的错误,还要找到代码依赖的库中的错误,所以可能需要告诉工具还要分 析或处理这些库。)清单 1. 执行 “不调用 System.gc()” 规则的动态方面public aspect GcAspect {
pointcut gcCalls() : call(void java.lang.System.gc ());
before() : gcCalls() {
throw new AssertionError("Don"t call System.gc!");
}
}清单 1 演示的动态方式不如使用静态分析进行测试有效,因为它要求程序在 方面发现问题之前,实际地执行对 System.gc() 的调用,而不是程序只需包含 一个对 System.gc() 的调用,就会被探测到。但是,很快就会看到,动态方面 更灵活,因为它们能在方面触发的点上执行任意测试代码,从而对声明的问题提 供更精细的控制。也可以容易地创建一个静态方面,在编译时识别对 System.gc() 的调用,如 清单 2 所示。同样,如果想发现在库代码中出现的这个 bug 模式,不仅要处理 项目中的代码,还要处理它使用的库。清单 2. 执行 “不调用 System.gc()” 规则的静态方面public aspect StaticGcAspect {
pointcut gcCalls() : call(void java.lang.System.gc ());
declare error : gcCalls() : "Don"t call System.gc!";
}