十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
单元测试是我们在软件开发过程中经常用到的一种软件测试的方法,而今天我们就一起来了解一下,一个好的单元测试都是如何来编辑完成的。
创新互联公司专注于网站建设,为客户提供网站建设、成都网站建设、网页设计开发服务,多年建网站服务经验,各类网站都可以开发,成都品牌网站建设,公司官网,公司展示网站,网站设计,建网站费用,建网站多少钱,价格优惠,收费合理。
1.使用框架来用于单元测试Java提供了若干用于单元测试的框架。
TestNG和JUnit是流行的测试框架。
JUnit和TestNG的一些重要功能:易于设置和运行。
支持注释。
允许忽略或分组并一起执行某些测试。
支持参数化测试,即通过在运行时指定不同的值来运行单元测试。
通过与构建工具,如Ant,Maven和Gradle集成来支持自动化的测试执行。
EasyMock是一个模拟框架,是单元测试框架,如JUnit和TestNG的补充。
EasyMock本身不是一个完整的框架。
它只是添加了创建模拟对象以便于测试的能力。
例如,我们想要测试的一个方法可以调用从数据库获取数据的DAO类。
在这种情况下,EasyMock可用于创建返回硬编码数据的MockDAO。
这使我们能够轻松地测试我们意向的方法,而不必担心数据库访问。
2.谨慎使用测试驱动开发!测试驱动开发(TDD)是一个软件开发过程,在这过程中,在开始任何编码之前,我们基于需求来编写测试。
由于还没有编码,测试初会失败。
然后写入小量的代码以通过测试。
然后重构代码,直到被优化。
目标是编写覆盖所有需求的测试,而不是一开始就写代码,却可能甚至都不能满足需求。
TDD是伟大的,因为它导致简单的模块化代码,且易于维护。
总体开发速度加快,容易发现缺陷。
此外,单元测试被创建作为TDD方法的副产品。
然而,TDD可能不适合所有的情况。
在设计复杂的项目中,专注于简单的设计以便于通过测试用例,而不提前思考可能会导致巨大的代码更改。
此外,TDD方法难以用于与遗留系统,GUI应用程序或与数据库一起工作的应用程序交互的系统。
另外,测试需要随着代码的改变而更新。
因此,在决定采用TDD方法之前,应考虑上述因素,并应根据项目的性质采取措施。
3.测量代码覆盖率代码覆盖率衡量(以百分比表示)了在运行单元测试时执行的代码量。
通常,高覆盖率的代码包含未检测到的错误的几率要低,因为其更多的源代码在测试过程中被执行。
重庆电脑培训发现测量代码覆盖率的一些佳做法包括:使用代码覆盖工具,如Clover,Corbetura,JaCoCo或Sonar。
使用工具可以提高测试质量,因为这些工具可以指出未经测试的代码区域,让你能够开发开发额外的测试来覆盖这些领域。
新建一个Android studio项目后,项目文件列表如图所示:
但是,在文件列表中并没有找到R.java文件。切换项目列表试图为project,如图:
依次,打开app--build--generated--source--r--debug,在debug中的两个选项的子文件中分别有有一个R文件,既我们要找的R.java文件。
4
双击打开,即可看到R.java内容。如图所示:
goto 保留关键字,没有具体含义
abstract 表明类或者成员方法具有抽象属性
assert 用来进行程序调试
boolean 基本数据类型之一,布尔类型
break 提前跳出一个块
byte 基本数据类型之一,字节类型
case 用在switch语句之中,表示其中的一个分支
catch 用在异常处理中,用来捕捉异常
char 基本数据类型之一,字符类型
class 类
const 保留关键字,没有具体含义
continue 回到一个块的开始处
default 默认,例如,用在switch语句中,表明一个默认的分支
do 用在do-while循环结构中
double 基本数据类型之一,双精度浮点数类型
else 用在条件语句中,表明当条件不成立时的分支
enum 枚举
extends 表明一个类型是另一个类型的子类型,这里常见的类型有类和接口
final 用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变,用来定义常量
finally 用于处理异常情况,用来声明一个基本肯定会被执行到的语句块
float 基本数据类型之一,单精度浮点数类型
for 一种循环结构的引导词
goto 保留关键字,没有具体含义
if 条件语句的引导词
implements 表明一个类实现了给定的接口
import 表明要访问指定的类或包
instanceof 用来测试一个对象是否是指定类型的实例对象
int 基本数据类型之一,整数类型
interface 接口
long 基本数据类型之一,长整数类型
native 用来声明一个方法是由与计算机相关的语言(如C/C++/FORTRAN语言)实现的
new 用来创建新实例对象
package 包
private 一种访问控制方式:私用模式
protected 一种访问控制方式:保护模式
public 一种访问控制方式:共用模式
return 从成员方法中返回数据
short 基本数据类型之一,短整数类型
static 表明具有静态属性
strictfp 用来声明FP_strict(单精度或双精度浮点数)表达式遵循IEEE 754算术规范
super 表明当前对象的父类型的引用或者父类型的构造方法
switch 分支语句结构的引导词
synchronized 表明一段代码需要同步执行
this 指向当前实例对象的引用
throw 抛出一个异常
throws 声明在当前定义的成员方法中所有需要抛出的异常
transient 声明不用序列化的成员域
try 尝试一个可能抛出异常的程序块
void 声明当前成员方法没有返回值
volatile 表明两个或者多个变量必须同步地发生变化
while 用在循环结构中
一个好的集成开发环境能告诉你,以开发java的IDEA为例:
1、声明却未使用的变量:
它会建议你删除该变量。
2、无用的初始值:
它也会建议你删除初始值。
3、不必要的变量:
它会建议直接返回就行,不需要定义额外的变量。
4、可以简化的if语句:
5、可以简化的for语句:
6、一些潜在的可能引起bug的地方:
将会引起空指针异常
没有检查泛型
7、重复代码:
重复的代码可以考虑合并成公共的方法。
还有太多例子我就不举例了,总之好的ide在开发过程中就能告诉我们很多潜在的问题,解决代码不规范的地方,像eclipse也有专门的插件来检查代码。
当然平时就养成好的开发习惯和好的代码规范,长期积累下来在开发过程中自己就能解决掉一大堆冗余代码。
1、eclipse是开发环境,可以帮你提示代码里出现的问题。这些问题分为两种:error和warning,其中error的话程序就没法运行了,warning只是告诉你代码不完美。
2、未使用变量意思是,这个变量在程序里没有被用过,也就是多余的,此时会以warning的形式提示你。
3、比如你一个类里定义了一个private类型的成员,且从未用过,对程序来说,它就是不需要的。
本文首先介绍了静态代码分析的基本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBugs,PMD,Jtest),最后从功能、特性等方面对它们进行分析和比较,希望能够帮助 Java 软件开发人员了解静态代码分析工具,并选择合适的工具应用到软件开发中。
引言
在 Java 软件开发过程中,开发团队往往要花费大量的时间和精力发现并修改代码缺陷。Java 静态代码分析(static code analysis)工具能够在代码构建过程中帮助开发人员快速、有效的定位代码缺陷并及时纠正这些问题,从而极大地提高软件可靠性并节省软件开发和测试成 本。目前市场上的 Java 静态代码分析工具种类繁多且各有千秋,因此本文将分别介绍现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBugs,PMD,Jtest),并从功能、特性等方面对它们进行分析和比较,希望能够帮助 Java 软件开发人员了解静态代码分析工具,并选择合适的工具应用到软件开发中。
静态代码分析工具简介
什么是静态代码分析
静态代码分析是指无需运行被测代码,仅通过分析或检查源程序的语法、结构、过程、接口等来检查程序的正确性,找出代码隐藏的错误和缺陷,如参数不匹配,有歧义的嵌套语句,错误的递归,非法计算,可能出现的空指针引用等等。
在软件开发过程中,静态代码分析往往先于动态测试之前进行,同时也可以作为制定动态测试用例的参考。统计证明,在整个软件开发生命周期中,30% 至 70% 的代码逻辑设计和编码缺陷是可以通过静态代码分析来发现和修复的。
但是,由于静态代码分析往往要求大量的时间消耗和相关知识的积累,因此对于软件开发团队来说,使用静态代码分析工具自动化执行代码检查和分析,能够极大地提高软件可靠性并节省软件开发和测试成本。
静态代码分析工具的优势
1. 帮助程序开发人员自动执行静态代码分析,快速定位代码隐藏错误和缺陷。
2. 帮助代码设计人员更专注于分析和解决代码设计缺陷。
3. 显著减少在代码逐行检查上花费的时间,提高软件可靠性并节省软件开发和测试成本。
Java 静态代码分析理论基础和主要技术
缺陷模式匹配:缺陷模式匹配事先从代码分析经验中收集足够多的共性缺陷模式,将待分析代码与已有的共性缺陷模式进行模式匹配,从而完成软件的安全分析。这种方式的优点是简单方便,但是要求内置足够多缺陷模式,且容易产生误报。
类型推断:类型推断技术是指通过对代码中运算对象类型进行推理,从而保证代码中每条语句都针对正确的类型执行。这种技术首先将预定义一套类型机制,包括类 型等价、类型包含等推理规则,而后基于这一规则进行推理计算。类型推断可以检查代码中的类型错误,简单,高效,适合代码缺陷的快速检测。
模型检查:模型检验建立于有限状态自动机的概念基础之上,这一理论将被分析代码抽象为一个自动机系统,并且假设该系统是有限状态的、或者是可以通过抽象归 结为有限状态。模型检验过程中,首先将被分析代码中的每条语句产生的影响抽象为一个有限状态自动机的一个状态,而后通过分析有限状态机从而达到代码分析的 目的。模型检验主要适合检验程序并发等时序特性,但是对于数据值域数据类型等方面作用较弱。
数据流分析:数据流分析也是一种软件验证技术,这种技术通过收集代码中引用到的变量信息,从而分析变量在程序中的赋值、引用以及传递等情况。对数据流进行 分析可以确定变量的定义以及在代码中被引用的情况,同时还能够检查代码数据流异常,如引用在前赋值在后、只赋值无引用等。数据流分析主要适合检验程序中的 数据域特性。
现有主流 Java 静态分析工具
Checkstyle
Checkstyle 是 SourceForge 的开源项目,通过检查对代码编码格式,命名约定,Javadoc,类设计等方面进行代码规范和风格的检查,从而有效约束开发人员更好地遵循代码编写规范。
Checkstyle 提供了支持大多数常见 IDE 的插件,文本主要使用 Eclipse 中的 Checkstyle 插件。如下图 1 所示,Checkstyle 对代码进行编码风格检查,并将检查结果显示在 Problems 视图中。图中,代码编辑器中每个放大镜图标表示一个 Checkstyle 找到的代码缺陷。开发人员可通过在 Problems 视图中查看错误或警告详细信息。
图 1. 使用 Checkstyle 进行编码风格检查
此外,Checkstyle 支持用户根据需求自定义代码检查规范,在下图 2 中的配置面板中,用户可以在已有检查规范如命名约定,Javadoc,块,类设计等方面的基础上添加或删除自定义检查规范。
图 2. 使用 Checkstyle 添加自定义代码检查规范
FindBugs
FindBugs 是由马里兰大学提供的一款开源 Java 静态代码分析工具。FindBugs 通过检查类文件或 JAR 文件,将字节码与一组缺陷模式进行对比从而发现代码缺陷,完成静态代码分析。FindBugs 既提供可视化 UI 界面,同时也可以作为 Eclipse 插件使用。文本将主要使用将 FindBugs 作为 Eclipse 插件。在安装成功后会在 eclipse 中增加 FindBugs perspective,用户可以对指定 Java 类或 JAR 文件运行 FindBugs,此时 FindBugs 会遍历指定文件,进行静态代码分析,并将代码分析结果显示在 FindBugs perspective 的 bugs explorer 中,如下图 3 所示:
图 3. 使用 FindBugs 进行静态代码分析
图中 Bug Explorer 中的灰色图标处为 Bug 类型,每种分类下红色图标表示 bug 较为严重,黄色的图标表示 bug 为警告程度。Propreties 列出了 bug 的描述信息及修改方案。
此外,FindBugs 还为用户提供定制 Bug Pattern 的功能。用户可以根据需求自定义 FindBugs 的代码检查条件,如下图 4 所示:
图 4. 使用 FindBugs 添加自定义代码检查规范
PMD
PMD 是由 DARPA 在 SourceForge 上发布的开源 Java 代码静态分析工具。PMD 通过其内置的编码规则对 Java 代码进行静态检查,主要包括对潜在的 bug,未使用的代码,重复的代码,循环体创建新对象等问题的检验。PMD 提供了和多种 Java IDE 的集成,例如 Eclipse,IDEA,NetBean 等。本文主要使用 PMD 以插件方式与 Eclipse 集成。如下图 5 所示:在 Violations Overview 视图中,按照代码缺陷严重性集中显示了 PMD 静态代码分析的结果。
图 5. 使用 PMD 进行静态代码分析
PMD 同样也支持开发人员对代码检查规范进行自定义配置。开发人员可以在下图 6 中的面板中添加、删除、导入、导出代码检查规范。
图 6. 使用 PMD 添加自定义代码检查规范
Jtest
Jtest 是 Parasoft 公司推出的一款针对 Java 语言的自动化代码优化和测试工具,Jtest 的静态代码分析功能能够按照其内置的超过 800 条的 Java 编码规范自动检查并纠正这些隐蔽且难以修复的编码错误。同时,还支持用户自定义编码规则,帮助用户预防一些特殊用法的错误。Jtest 提供了基于 Eclipse 的插件安装。Jtest 支持开发人员对 Java 代码进行编码规范检查,并在 Jtask 窗口中集中显示检查结果,如下图 7 所示:
图 7. 使用 Jtest 进行静态代码分析
同时,Jtest 还提供了对用户定制代码检查配置甚至自定义编码规则的支持,这一功能使得开发人员可以基于不同场景定制所需要的编码规范,如图 8 所示:
图 8. 使用 Jtest 添加自定义代码检查规范
Java 静态分析工具对比
本章节将从以下几个方面对上述 Java 静态分析工具进行比较:
应用技术及分析对象
下表 1 列出了不同工具的分析对象及应用技术对比:
表 1. 不同工具的分析对象及应用技术对比
Java 静态分析工具
分析对象
应用技术
Checkstyle Java 源文件 缺陷模式匹配
FindBugs 字节码 缺陷模式匹配;数据流分析
PMD Java 源代码 缺陷模式匹配
Jtest Java 源代码 缺陷模式匹配;数据流分析
内置编程规范
Checkstyle:
Javadoc 注释:检查类及方法的 Javadoc 注释
命名约定:检查命名是否符合命名规范
标题:检查文件是否以某些行开头
Import 语句:检查 Import 语句是否符合定义规范
代码块大小,即检查类、方法等代码块的行数
空白:检查空白符,如 tab,回车符等
修饰符:修饰符号的检查,如修饰符的定义顺序
块:检查是否有空块或无效块
代码问题:检查重复代码,条件判断,魔数等问题
类设计:检查类的定义是否符合规范,如构造函数的定义等问题
FindBugs:
Bad practice 坏的实践:常见代码错误,用于静态代码检查时进行缺陷模式匹配
Correctness 可能导致错误的代码,如空指针引用等
国际化相关问题:如错误的字符串转换
可能受到的恶意攻击,如访问权限修饰符的定义等
多线程的正确性:如多线程编程时常见的同步,线程调度问题。
运行时性能问题:如由变量定义,方法调用导致的代码低效问题。
PMD:
可能的 Bugs:检查潜在代码错误,如空 try/catch/finally/switch 语句
未使用代码(Dead code):检查未使用的变量,参数,方法
复杂的表达式:检查不必要的 if 语句,可被 while 替代的 for 循环
重复的代码:检查重复的代码
循环体创建新对象:检查在循环体内实例化新对象
资源关闭:检查 Connect,Result,Statement 等资源使用之后是否被关闭掉
Jtest
可能的错误:如内存破坏、内存泄露、指针错误、库错误、逻辑错误和算法错误等
未使用代码:检查未使用的变量,参数,方法
初始化错误:内存分配错误、变量初始化错误、变量定义冲突
命名约定:检查命名是否符合命名规范
Javadoc 注释:检查类及方法的 Javadoc 注释
线程和同步:检验多线程编程时常见的同步,线程调度问题
国际化问题:
垃圾回收:检查变量及 JDBC 资源是否存在内存泄露隐患
错误检查能力
为比较上述 Java 静态分析工具的代码缺陷检测能力,本文将使用一段示例代码进行试验,示例代码中将涵盖我们开发中的几类常见错误,如引用操作、对象操作、表达式复杂化、数 组使用、未使用变量或代码段、资源回收、方法调用及代码设计几个方面。最后本文将分别记录在默认检查规范设置下,不同工具对该示例代码的分析结果。以下为 示例代码 Test.java。其中,代码的注释部分列举了代码中可能存在的缺陷。
清单 1. Test.java 示例代码
package Test;import java.io.*;public class Test {/** * Write the bytes from input stream to output stream. * The input stream and output stream are not closed. * @param is * @param os * @throws IOException */public boolean copy(InputStream is, OutputStream os)throws IOException {intcount = 0;//缺少空指针判断byte[] buffer =new byte[1024];while((count = is.read(buffer)) = 0) {os.write(buffer,0, count);}//未关闭I/O流returntrue;}/** * * @param a * @param b * @param ending * @return copy the elements from a to b, and stop when meet element ending */publicvoid copy(String[] a, String[] b, String ending){intindex;String temp =null;//空指针错误System.out.println(temp.length());//未使用变量intlength=a.length;for(index=0; indexa.length; index++){//多余的if语句if(true){//对象比较 应使用equalsif(temp==ending){break;}//缺少 数组下标越界检查b[index]=temp;}}}/** * * @param file * @return file contents as stri if file does not exist */public void readFile(File file) {InputStream is =null;OutputStream os =null;try{is =new BufferedInputStream(newFileInputStream(file));os =new ByteArrayOutputStream();//未使用方法返回值copy(is,os);is.close();os.close();}catch (IOException e) {//可能造成I/O流未关闭e.printStackTrace();}finally{//空的try/catch/finally块}}}
通过以上测试代码,我们对已有 Java 静态代码分析工具的检验结果做了如下比较,如下表 2 所示。
表 2. Java 静态代码分析工具对比
代码缺陷分类
示例
Checkstyle
FindBugs
PMD
Jtest
引用操作 空指针引用 √ √ √ √
对象操作 对象比较(使用 == 而不是 equals) √ √ √
表达式复杂化 多余的 if 语句 √
数组使用 数组下标越界 √
未使用变量或代码段 未使用变量 √ √ √
资源回收 I/O 未关闭 √ √
方法调用 未使用方法返回值 √
代码设计 空的 try/catch/finally 块 √
由表中可以看出几种工具对于代码检查各有侧重。其中,Checkstyle 更偏重于代码编写格式,及是否符合编码规范的检验,对代码 bug 的发现功能较弱;而 FindBugs,PMD,Jtest 着重于发现代码缺陷。在对代码缺陷检查中,这三种工具在针对的代码缺陷类别也各有不同,且类别之间有重叠。
总结
本文分别从功能、特性和内置编程规范等方面详细介绍了包括 Checkstyle,FindBugs,PMD,Jtest 在内的四种主流 Java 静态代码分析工具,并通过一段 Java 代码示例对这四种工具的代码分析能力进行比较。由于这四种工具内置编程规范各有不同,因此它们对不同种类的代码问题的发现能力也有所不同。其中 Checkstyle 更加偏重于代码编写格式检查,而 FindBugs,PMD,Jtest 着重于发现代码缺陷。最后,希望本文能够帮助 Java 软件开发和测试人员进一步了解以上四种主流 Java 静态分析工具,并帮助他们根据需求选择合适的工具。