`
jamesfork
  • 浏览: 32773 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
最近访客 更多访客>>
社区版块
存档分类
最新评论

junit初步

    博客分类:
  • java
阅读更多
【IT168技术文档】本文主要介绍了如何使用 JUnit 4 提供的各种功能开展有效的单元测试,并通过一个实例演示了如何使用 Ant 执行自动化的单元测试。本文假设读者对 Eclipse 下进行 Java 开发有一定的经验,并了解 Java 5 中的注解(annotation)特性。

引言

毋庸置疑,程序员要对自己编写的代码负责,您不仅要保证它能通过编译,正常地运行,而且要满足需求和设计预期的效果。单元测试正是验证代码行为是否 满足预期的有效手段之一。但不可否认,做测试是件很枯燥无趣的事情,而一遍又一遍的测试则更是让人生畏的工作。幸运的是,单元测试工具 JUnit 使这一切变得简单艺术起来。

JUnit 是 Java 社区中知名度最高的单元测试工具。它诞生于 1997 年,由 Erich Gamma 和 Kent Beck 共同开发完成。其中 Erich Gamma 是经典著作《设计模式:可复用面向对象软件的基础》一书的作者之一,并在 Eclipse 中有很大的贡献;Kent Beck 则是一位极限编程(XP)方面的专家和先驱。

麻雀虽小,五脏俱全。JUnit 设计的非常小巧,但是功能却非常强大。Martin Fowler 如此评价 JUnit:在软件开发领域,从来就没有如此少的代码起到了如此重要的作用。它大大简化了开发人员执行单元测试的难度,特别是 JUnit 4 使用 Java 5 中的注解(annotation)使测试变得更加简单。

JUnit 4 初体验

在开始体验 JUnit 4 之前,我们需要以下软件的支持:

  • Eclipse:最为流行的 IDE,它全面集成了 JUnit,并从版本 3.2 开始支持 JUnit 4。当然 JUnit 并不依赖于任何 IDE。您可以从 http://www.eclipse.org/ 上下载最新的 Eclipse 版本。
  • Ant:基于 Java 的开源构建工具,您可以在 http://ant.apache.org/ 上得到最新的版本和丰富的文档。Eclipse 中已经集成了 Ant,但是在撰写本文时,Eclipse 使用的 Ant 版本较低(必需 1.7 或者以上版本),不能很好的支持 JUnit 4。
  • JUnit:它的官方网站是 http://www.junit.org/。您可以从上面获取关于 JUnit 的最新消息。如果您和本文一样在 Eclipse 中使用 JUnit,就不必再下载了。

首先为我们的体验新建一个 Java 工程 —— coolJUnit。现在需要做的是,打开项目 coolJUnit 的属性页 -> 选择“Java Build Path”子选项 -> 点选“Add Library…”按钮 -> 在弹出的“Add Library”对话框中选择 JUnit(图1),并在下一页中选择版本 4.1 后点击“Finish”按钮。这样便把 JUnit 引入到当前项目库中了。


图1 为项目添加 JUnit 库

可以开始编写单元测试了吗?等等……,您打算把单元测试代码放在什么地方呢?把它和被测试代码混在一起,这显然会照成混乱,因为单元测试代码是不会 出现在最终产品中的。建议您分别为单元测试代码与被测试代码创建单独的目录,并保证测试代码和被测试代码使用相同的包名。这样既保证了代码的分离,同时还 保证了查找的方便。遵照这条原则,我们在项目 coolJUnit 根目录下添加一个新目录 testsrc,并把它加入到项目源代码目录中(加入方式见 图2)。

图2 修改项目源代码目录

现在我们得到了一条 JUnit 的最佳实践:单元测试代码和被测试代码使用一样的包,不同的目录。

一切准备就绪,一起开始体验如何使用 JUnit 进行单元测试吧。下面的例子来自笔者的开发实践:工具类 WordDealUtil 中的静态方法 wordFormat4DB 是专用于处理 Java 对象名称向数据库表名转换的方法(您可以在代码注释中可以得到更多详细的内容)。下面是第一次编码完成后大致情形:

<!---->package com.ai92.cooljunit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 对名称、地址等字符串格式的内容进行格式检查
* 或者格式化的工具类
*
* @author Ai92
*/
public class WordDealUtil {
/**
* 将Java对象名称(每个单词的头字母大写)按照
* 数据库命名的习惯进行格式化
* 格式化后的数据为小写字母,并且使用下划线分割命名单词
*
* 例如:employeeInfo 经过格式化之后变为 employee_info
*
* @param name Java对象名称
*/
public static String wordFormat4DB(String name){
Pattern p
= Pattern.compile("[A-Z]");
Matcher m
= p.matcher(name);
StringBuffer sb
= new StringBuffer();
while(m.find()){
m.appendReplacement(sb,
"_"+m.group());
}
return m.appendTail(sb).toString().toLowerCase();
}
}

它是否能按照预期的效果执行呢?尝试为它编写 JUnit 单元测试代码如下:

<!---->package com.ai92.cooljunit;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class TestWordDealUtil {
//测试wordFormat4DB正常运行的情况
@Test public void wordFormat4DBNormal(){
String target
= "employeeInfo";
String result
= WordDealUtil.wordFormat4DB(target);
assertEquals(
"employee_info", result);
}
}

很普通的一个类嘛!测试类 TestWordDealUtil 之所以使用“Test”开头,完全是为了更好的区分测试类与被测试类。测试方法 wordFormat4DBNormal 调用执行被测试方法 WordDealUtil.wordFormat4DB,以判断运行结果是否达到设计预期的效果。需要注意的是,测试方法 wordFormat4DBNormal 需要按照一定的规范书写:

  1. 测试方法必须使用注解 org.junit.Test 修饰。
  2. 测试方法必须使用 public void 修饰,而且不能带有任何参数。

测试方法中要处理的字符串为“employeeInfo”,按照设计目的,处理后的结果应该为“employee_info”。 assertEquals 是由 JUnit 提供的一系列判断测试结果是否正确的静态断言方法(位于类 org.junit.Assert 中)之一,我们使用它将执行结果 result 和预期值“employee_info”进行比较,来判断测试是否成功。

看看运行结果如何。在测试类上点击右键,在弹出菜单中选择 Run As JUnit Test。运行结果如下图所示:

图3 JUnit 运行成功界面

绿色的进度条提示我们,测试运行通过了。但现在就宣布代码通过了单元测试还为时过早。记住:您的单元测试代码不是用来证明您是对的,而是为了证明您 没有错。因此单元测试的范围要全面,比如对边界值、正常值、错误值得测试;对代码可能出现的问题要全面预测,而这也正是需求分析、详细设计环节中要考虑 的。显然,我们的测试才刚刚开始,继续补充一些对特殊情况的测试:

<!---->public class TestWordDealUtil {
……
//测试 null 时的处理情况
@Test public void wordFormat4DBNull(){
String target
= null;
String result
= WordDealUtil.wordFormat4DB(target);
assertNull(result);
}
//测试空字符串的处理情况
@Test public void wordFormat4DBEmpty(){
String target
= "";
String result
= WordDealUtil.wordFormat4DB(target);
assertEquals(
"", result);
}
//测试当首字母大写时的情况
@Test public void wordFormat4DBegin(){
String target
= "EmployeeInfo";
String result
= WordDealUtil.wordFormat4DB(target);
assertEquals(
"employee_info", result);
}
//测试当尾字母为大写时的情况
@Test public void wordFormat4DBEnd(){
String target
= "employeeInfoA";
String result
= WordDealUtil.wordFormat4DB(target);
assertEquals(
"employee_info_a", result);
}
//测试多个相连字母大写时的情况
@Test public void wordFormat4DBTogether(){
String target
= "employeeAInfo";
String result
= WordDealUtil.wordFormat4DB(target);
assertEquals(
"employee_a_info", result);
}
}

再次运行测试。很遗憾,JUnit 运行界面提示我们有两个测试情况未通过测试(图4)——当首字母大写时得到的处理结果与预期的有偏差,造成测试失败(failure);而当测试对 null 的处理结果时,则直接抛出了异常——测试错误(error)。显然,被测试代码中并没有对首字母大写和 null 这两种特殊情况进行处理,修改如下:

<!---->//修改后的方法wordFormat4DB
/*
*
* 将Java对象名称(每个单词的头字母大写)按照
* 数据库命名的习惯进行格式化
* 格式化后的数据为小写字母,并且使用下划线分割命名单词
* 如果参数name为null,则返回null
*
* 例如:employeeInfo 经过格式化之后变为 employee_info
*
* @param name Java对象名称
*/
public static String wordFormat4DB(String name){
if(name == null){
return null;
}
Pattern p
= Pattern.compile("[A-Z]");
Matcher m
= p.matcher(name);
StringBuffer sb
= new StringBuffer();
while(m.find()){
if(m.start() != 0)
m.appendReplacement(sb, (
"_"+m.group()).toLowerCase());
}
return m.appendTail(sb).toString().toLowerCase();
}

图4 JUnit 运行失败界面

JUnit 将测试失败的情况分为两种:failure 和 error。Failure 一般由单元测试使用的断言方法判断失败引起,它表示在测试点发现了问题;而 error 则是由代码异常引起,这是测试目的之外的发现,它可能产生于测试代码本身的错误(测试代码也是代码,同样无法保证完全没有缺陷),也可能是被测试代码中的 一个隐藏的bug。

啊哈,再次运行测试,绿条又重现眼前。通过对 WordDealUtil.wordFormat4DB 比较全面的单元测试,现在的代码已经比较稳定,可以作为 API 的一部分提供给其它模块使用了。

不知不觉中我们已经使用 JUnit 漂亮的完成了一次单元测试。可以体会到 JUnit 是多么轻量级,多么简单,根本不需要花心思去研究,这就可以把更多的注意力放在更有意义的事情上——编写完整全面的单元测试。

请牢记!
请牢记这一条 JUnit 最佳实践:测试任何可能的错误。单元测试不是用来证明您是对的,而是为了证明您没有错。
分享到:
评论

相关推荐

    JUnit3.8的初步学习

    JUnit3.8是Java开发中一个非常重要的单元测试框架,它是JUnit系列的早期版本,用于帮助程序员编写可重复运行的测试代码,确保软件的质量。在本文中,我们将深入探讨JUnit3.8的基础知识,了解其核心概念、用法以及...

    Junit4环境搭建和Hamcrest初步

    本篇将重点介绍如何搭建Junit4的测试环境以及初步接触Hamcrest库,这将帮助你提升测试的质量和效率。 首先,我们来理解什么是Junit4。Junit4是JUnit框架的一个版本,它引入了注解(Annotation)来简化测试用例的...

    junit实战第二版

    在第一章“JUnit起步”中,作者首先介绍了如何手工编写简单的测试,让读者对测试有一个初步的认识。接着,讲解了如何安装JUnit以及运行测试,这部分内容对于初学者来说至关重要,因为JUnit必须被正确安装才能在Java...

    junit pdf

    - 分析与设计:对选定的场景进行深入分析和初步设计。 - 开发单元测试列表:基于高阶设计制定单元测试列表。 - 使用 CRC 卡、序列图等可视化手段辅助理解测试需求。 当开发者认为某个测试场景已经实现时,会通知...

    Junit使用:适合初学者使用

    通过以上讲解,你应该对JUnit的基本使用有了初步了解。继续学习`JUnit.ppt`中的内容和实际操作`JuintTest`中的代码示例,将有助于加深理解并提升你的单元测试技能。在实际开发中,熟练运用单元测试能显著提高代码...

    【Java框架-JUnit】(01) - 文件

    通过以上内容,你应该对JUnit有了初步的认识。继续学习JUnit,你会发现它能极大地提高你的开发效率和代码质量。在实际项目中,还可以结合Mockito等工具进行模拟对象测试,或者使用TestNG等其他测试框架,进一步提升...

    单元测试利器JUnit4_opt1

    【JUnit 4 初步了解】 JUnit 是一个广泛使用的 Java 单元测试框架,由 Erich Gamma 和 Kent Beck 创建,自 1997 年以来,它极大地简化了编写和执行单元测试的过程。JUnit 4 版本引入了 Java 5 的注解特性,使得测试...

    spring-text-3.2.8和junit4.10

    此外,它还包含了对Spock测试框架的初步支持,使得开发者可以更灵活地选择测试框架。 接下来,我们来谈谈"junit-4.10"。JUnit 4.10是JUnit系列的一个版本,它在JUnit 4的基础上进行了一些改进和扩展。这个版本引入...

    软件测试实验报告

    对Java单元测试有初步的了解,学会使用Junit开发自己的测试用例,并对被测试类进行测试。 1. 获取Junit。 2. Junit的安装与配置。 3. 利用Junit开发自己的测试用例,并对被测试类进行测试。

    xray-junit-extensions:增强的JUnit 5与Xray Test Management的Jira集成

    这是一个初步发行版,因此随时可能更改。 概述 可以在测试管理工具中跟踪以@Test方法实现的自动化脚本的结果,以提供有关这些脚本所针对的质量方面及其影响的见解。 因此,在执行测试期间附加一些相关信息非常重要...

    JPA+SPRING权限系统初步框架

    标题中的“JPA+SPRING权限系统初步框架”是指基于Java Persistence API (JPA) 和Spring框架构建的一个初步的权限管理系统。这样的系统主要用于管理用户权限,确保不同用户只能访问其被授权的数据或功能。 1. **Java...

    JUnit 4 Extensions-开源

    例如,可以创建一个快速运行的“Smoke Tests”类别和一个深度的“Integration Tests”类别,便于快速获取初步反馈或执行全面测试。 此外,JUnitExt可能包含了其他自定义的Runners,比如用于并行执行测试的`...

    南邮软件工程实验三.pdf

    本实验的主要目的是让学生初步了解 JAVA 单元测试,并学习使用 Junit 编写测试用例对被测试类进行测试。通过本实验,学生将掌握 Junit 的工作机制、Eclipse 环境下的单元测试、编写测试用例和对被测试类进行功能测试...

    JAVA版公司员工初步管理系统!

    JUnit是Java领域广泛使用的单元测试框架,可以帮助开发者验证代码的正确性。如果项目规模较大,可能还会用到Mockito等工具来模拟对象,以便独立测试特定功能。 最后,考虑到这是一个初步的管理系统,可能还没有涉及...

    SpingMVC+MongoDB+Redis 初步架构设计

    6. **测试和持续集成**:编写单元测试和集成测试,利用Junit和Mockito等工具,确保每个组件的正确性。同时,引入CI/CD工具(如Jenkins或GitLab CI/CD),自动化构建和部署流程。 7. **微服务化**:随着项目发展,可...

Global site tag (gtag.js) - Google Analytics