诊断Java代码: 单元测试与自动化代码分析协同工作

支持静态分析(包括类型检查)的主要论据是:其结果适用程序所有可能的运行,而通过单元测试只能保证被测试的组件(在测试它们的平台上)只适用测试组件的特定输入。

支持单元测试的主要论据是它更容易处理。您可以测试程序的许多约束,这些约束远远超出了同期的静态分析工具所能达到的范围。

请允许我在此冒昧地说一句:我认为将这两种工具看作对立的是一个错误。每种工具都有助于构建更健壮的程序。实际上,它们可以通过非常强大的方式进行互补。

每种工具都有各自的长处,对于补充另一种工具特别有用:

单元测试能显示执行的常用路径,从而显示程序是如何运行的。

分析工具能检查单元测试提供的覆盖范围。

让我们研究这其中的每个属性,并讨论一些可帮助您将其长处带给其它方法的工具。

显示常用执行路径的单元测试

单元测试套件提供了程序组件的示例用法的稳固基础。通过检查测试运行时程序是如何运作的,分析工具可以就开发人员希望在程序中保持的不变量进行试探性推测(就和程序员阅读单元测试所做的一样)。

还有另一种方法,其中单元测试可以是一种可执行的文档形式。在从单元测试的运行中 从特殊到一般地推断出推测性不变量之后,分析工具可以尝试 从一般到特殊地验证不变量的存在,或者它可以利用可在运行时检查的断言注释该代码。

在任何一种情况下,在该工具做任何其它工作之前,最好向用户返回推测的不变量集的报告,以询问用户真正想要哪些不变量。顺便提一下,如果此类工具向用户报告了许多他们不想要的不变量,这可能是单元测试出了问题的信号 ― 例如,它们不够一般。

可用这种方式与单元测试一起使用的工具是 Daikon,它是一款来自 MIT 的 Mike Ernst 的程序分析小组的免费的、试验性的工具。Daikon 分析程序的运行(例如单元测试的运行),并尝试推测不变量。然后它询问用户是否想要这些不变量,并将用户想要的不变量作为断言插入程序。

例如,假定我们编写一个向量(Vector)的适配器,该适配器实现接口 Sequence ,该接口包含用于检索元素的方法 lookup 和用于将元素放在向量末尾的方法 insert 。方法 lookup 带有一个索引 i ,用来访问它所包含的向量。

假定该数组的长度存储在字段 length 中。通过维护适配器中的长度,我们可以不通知向量本身就将元素从其尾部删除。

让我们为这个假想的简单适配器编写一个简单的测试用例:

清单 1. 向量容器中简单查找方法的测试用例

import junit.framework.TestCase;
public class VectorAdapterTest extends TestCase {
  public VectorAdapterTest(String name) {
   super(name);
  }

  public void testLookupAndInsert() {
   VectorAdapter v = new VectorAdapter();
   v.insert("this");
   v.insert("is");
   v.insert("a");
   v.insert("test");
   assertEquals("Retrieved and inserted elements don't match",
         "a",
         v.lookup(2));
  }
}

时间: 2024-08-02 20:30:50

诊断Java代码: 单元测试与自动化代码分析协同工作的相关文章

诊断Java代码

诊断Java代码: Broken Dispatch错误模式 诊断Java代码: Double Descent错误模式 诊断Java代码: Impostor Type错误模式 诊断Java代码: Java编程中的断言和时态逻辑 诊断Java代码: Liar View错误模式 诊断Java代码: Repl提供交互式评价 诊断Java代码: 单元测试与自动化代码分析协同工作 诊断Java代码: 将时态逻辑用于错误模式 诊断Java代码: 进行记录器测试以正确调用方法 诊断Java代码: 空标志错误模式

诊断Java代码: 进行记录器测试以正确调用方法

用 JUnit进行单元测试是一个功能强大的方法,它可以确保您的代码基础的完整性,但是一些不变量比其他(方法调用序列是其中一种)更难测试.在诊断Java 代码这一部分,Eric Allen描述了怎样在您的单元测试中使用记录器(一种特殊的侦听器),来确保一个方法调用序列按恰当的顺序发生.请点击文章顶部和底部的 讨论,与作者和其他读者在论坛上分享您关于本文的看法. 随着时间的推移,当系统开发人员,维护人员甚至是系统详细说明改变时,JUnit 框架提供一个很好的方法来改善系统的坚固性.通过测试,您可以检

诊断Java代码: Impostor Type错误模式

当使用字段中特殊的标记来区别对象类型时,可能会产生标记对相关数据误贴标签的错误 ― 通称为 Impostor Type 错误模式.在诊断 Java 代码的这一部分中,Eric Allen 对这个错误的症状和起因进行了分析,详细说明了预防错误发生的方法,并讨论了一种吸引人的混合实现方法,这种方法不使用 impostor type,但最后,还是有很多相同的缺点产生.请在 讨论论坛与作者及其他读者分享您对本文的看法. 程序中除了最无关紧要的部分外都要对某些数据类型进行操作.静态类型系统提供了一种方法,

诊断Java代码: 设计可扩展应用程序,第3部分

对应于我们上一篇" 诊断 Java 代码"中所讨论的透明盒可扩展性,黑盒可扩展性是指,在源代码既不能查看也不能修改时,可以扩展软件系统的方法.通常通过系统配置或使用特定于应用程序的脚本语言来进行这样的扩展.在本专题中,Eric Allen 讨论了何时设计黑盒可 扩展性的系统是有意义的,并提供了如何有效地实现这一设计的一些想法.阅读了本文后,您将知道何时使用黑盒并掌握如何实现它的一些技巧. 我已在以前的文章中谈到了代码重用设计策略的重要性(主要是因为各种信息处理任务的差异和相应费用的增加

诊断Java代码: 设计可扩展的应用程序,第2部分

玻璃箱可扩展性是指这样一种方式:软件系统可在源代码可以查看而不可以修改时被扩展 ― 它是黑箱设计(在这里构建扩展时,不查看原始代码)和开放箱设计(扩展代码直接写入到基础代码)的折衷.因为新的扩展直接建立在原始代码基础上,但不改动原始代码,所以,玻璃箱设计或许是扩展一个软件系统最有效.最安全的方法.在 诊断 Java 代码的这一部分中,Eric Allen 详述了上个月谈及的玻璃箱可扩展性主题.读完本文后,您将知道什么时候使用玻璃箱,并将获得一些如何实现它的提示. 随着信息处理任务(和与之相关的成

诊断Java代码:孤线程(Orphaned Thread)错误模式

在多线程代码中,使用驱动其它线程所负责的动作的单个主线程是常见的.这个主线程发送消息,通常是通过把它们放到一个队列中,然后其它线程处理这些消息.但是如果主线程抛出一个异常,那么剩余的线程会继续运行,等待更多输入到该队列,导致程序冻结.在诊断 Java 代码的这一部分中,专职 Java 开发者兼兼职捉虫者 Eric Allen 讨论检测.修复和避免这一错误模式. 用多线程编写代码对程序员大有好处.多线程能使编程(和程序)进行得快得多,而且代码能有效得多地使用资源.然而,跟生活中的很多事情一样,多线

java swing mysql 下面的代码无法连接到数据库,插入数据

问题描述 java swing mysql 下面的代码无法连接到数据库,插入数据 import java.awt.*; import javax.swing.*; import java.awt.event.*; import java.sql.*; class Test { /*private String driver="com.mysql.jdbc.Driver"; private String url="jdbc:mysql://localhost:3306/tech

Apache Struts2远程代码执行漏洞S2-048 CVE-2017-9791 分析和防护方案

今天,Apache Struts官方发布公告,漏洞编号为S2-048 CVE-2017-9791,公告称Struts2和Struts1中的一个Showcase插件可能导致远程代码执行,并评价为高危漏洞. 绿盟科技发布分析和防护方案,其中开放了在线检测工具 https://cloud.nsfocus.com/#/krosa/views/initcdr/productandservice?page_id=12 通告全文如下 Apache Struts2远程代码执行漏洞S2-048 CVE-2017-

Java编程那些事儿16——代码框架、关键字和标识符

3.2 代码框架 "罗马不是一天建成的",所以想只学习几天的语法或者一两周的语法就能很熟练的编程,是不实际的想法.说个极端的例子,你的英语学了多少年了,能很流利的与人交流和书写文章吗?当然,就程序语法来说,比英语简单多了. 在开始学习Java时,不可能把所有的语法都一下子介绍清楚,但是如果需要把程序正确的运行起来,那么还必须不少的语法知识,为了在学习的初期可以让自己编写的代码编译通过,并且能够执行,所以特提供一个简单的代码框架,方便大家初期的练习. 代码框架的结构如下: public