动态网站制作指南 [  QQ表情  ]
[ 投票调查 ]
[ 企业邮箱 ]
[ 网站空间 ]
网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
ASP源码 | .Net源码 | PHP源码 | JSP源码 | JAVA源码 | CGI源码 | VB源码 | C++源码 | Delphi源码 | PB源码 | VF源码 | 汇编 | 服务器
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > 软件工程
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
文章搜索服务
邮件订阅
输入你的邮件地址,
你将不会错过任何关于:
[ 软件工程 ]的信息

本月文章推荐
.3DS模型Bump Map(凹凸贴图)渲染.
.Bash readline 使用技巧.
.怎么提高与客户沟通的技巧.
.OO设计模式和设计原则.
.构建安全的.NET系统.
.成功规划SOA.
.用好2005之使用强类型DataSet简化.
.利用UML类图设计Java应用程序详解.
..NET 2.0远程传输数据集的优化方.
.软件项目规模估计方法介绍.
.规划SOA(3)进行长期SOA规划.
.SOA Software宣称独立于UDDI注册.
.Mozilla开发组的开发策略(英文).
.使用.NET智能版进行SIM编程.
.需求分析简介.
.如何对软件质量进行评估(1).
.面向服务的体系结构SOA简介.
.VS.NET2005 Beta2初体验.
.真正的软件工程师(中国与印度).
.Windows 2000 Professional中用命.

感悟测试驱动开发

发表日期:2008-3-23 |



  软件开发方法学的泰斗Kent Beck先生最为推崇"模式、极限编程和测试驱动开发"。在他所创造的极限编程(XP)方法论中,就向大家推荐"测试先行"这一最佳实践,并且还专门撰写了《测试驱动开发》一书,具体说明如何实现。测试驱动开发是极限编程的重要特点,它以不断的测试推动代码的开发,从而实现既简化代码,又保证质量的目标。

  一看到"测试先行"、"测试驱动"这样的名字,就深深地激起了我强烈的好奇心,开始了自己的探索之旅..

  心灵震憾

  一段时间的学习,让我的内心受到了深深的震撼。我们原来的方法居然如此的笨我面对测试先行这一名字时,当时最大的疑问就是"程序都还没有写出来, 测试什么呀!"。后来一想,其实这是一个泥瓦匠都明白的道理,却是自己在画地为牢。我们来看看两个不同泥瓦匠是

  如何工作的吧:

  工匠一:先拉上一根水平线,砌每一块砖时,都与这根水平线进行比较,使得每一块砖都保持水平。

  工匠二:先将一排砖都砌完,然后拉上一根水平线,看看哪些砖有问题,再进行调整。

  你会选择哪种工作方法呢?你一定会骂工匠二笨吧!这样多浪费时间呀! 然而你自己想想,你平时在编写程序的时候又是怎么做的呢?我们就是按工匠二的方法在干活的呀!甚至有时候比工匠二还笨,是整面墙都砌完了,直接进行"集成测试",经常让整面的墙倒塌。看到这里,你还觉得自己的方法高明吗?

  单元测试长期以来被忽视

  每一个程序员都知道应该为自己的代码编写测试程序,但却很少这样做。当人们问为什么的时候,最常听到的回答就是:"我们的开发工作太紧张了"。但这样却导致了一个恶性循环,越是没空编写测试程序,代码的效率与质量越差,花在找Bug、解决Bug的时间也越来越多, 实际效率大大降低。由于效率降低了,因此时间更紧张,压力更大。你想想,为什么不拉上一根水平线呢?难道,我们不能够将后面浪费的时间花在单元测试上,使得我们的程序一开始就更加健壮,更加易于修改吗?抛弃原来的托词吧!

  我们的自动化水平太低了

  有人还会解释说,那是因为拉根水平线很简单,而写测试程序却是十分复杂的。我暂且对这句话本身不置可否。不过也体现了一个新问题,我们需要更加方便、省时的编写测试程序的方法。

  要测试一个类,最简单的方法是直接在调试器中使用表达式观察对象的值与状态,你也可以在程序中加上一些断言、打印中间值等,当然还可以编写专门的测试程序。但是这些方法都有一个很大的局限性,都需要加入人工的判定和分析。

  由此,自动化测试的引入才是解决之道。正是因为如此,提倡"测试驱动开发"的人群,开发出一系列的自动化单元测试框架xUnit,现在已经有针对Java、Pyhton、C++、PHP等各种常用语言的测试框架。这足以搪塞住那些以"编写测试代码太麻烦"为理由的开发人员,让他们没有理由逃避单元测试。

  正如Robert Martin所说:"测试套件运行起来越简单,就会越频繁地运行它们。测试运行越多,就会越快地发现和那些测试的任何背离。假如能够一天多次地运行所有的测试,那么系统的失效时间就决不会超过几分钟"。

  认清测试驱动开发

  测试驱动开发理论最初源于对这些问题的思考:

  1)假如我们能够在编写程序代码之前先进行测试方案的设计,会怎样?

  2)假如我们保证除非没有这个功能将导致测试失败,否则就不在程序中实现该功能,会怎样?

  3)换一个角度,假如当测试时发现必须增加某项功能才能够通过测试时, 我们就增加这一功能,会怎样?

  大师们通过带着这些问题的实践, 发现这的确是一个提高软件代码质量, 使得效率得到保障的一个很好出发点。

  以这样的思路进行软件开发,可以保证程序中的每一项功能都有测试来验证它是正确的,而且每当功能被无意修改时, 测试程序会发现。同时,也使我们获得了一个新的观察点,从对程序调用者有利的视角来观察我们的程序,这使得我们在关心程序功能的本身还能够对接口予以足够感悟测试驱动开发的关注,使得其更轻易被调用。另外,这种思路下的代码,将变得更加易于调用,也就必须使其与其它代码保持低耦合性。并且,当你想复用这些模块时,测试代码给出了很好的示例。这一切,使得软件开发工作的质量一下子变得有保障了。

  因此,测试驱动开发的精髓在于: 将测试方案设计工作提前,在编写代码之前先做这一项工作; 从测试的角度来验证设计,推导设计; 同时将测试方案当作行为的准绳,有效地利用其检验代码编写的每一步,实时验证其正确性,实现软件开发过程的"小步快走"。

  实践测试驱动开发

  下面,我就结合一个实际的小例子,来说明如何进行"测试驱动开发"。本实例在J2SE SDK 1.4.2环境下开发,以及配套工具JUnit 3.8.1。

  任务简述

  队列是一种在程序开发中十分常用的数据结构,在此我就以编写一个实现队列功能的类--Queue为例进行说明。该类将实现以下基本运算:

  判定队列是否为空:empty()

  插入队列(即在队列未尾增加一个数据元素):inqueue(x)

  出队列(也就是将队列首数据元素删除):outqueue()

  取列头(也就是读者队列首数据元素的值):gethead()

  清空队列(也就是将队列的所有数据元素全删除): clear()

  查询x在队列中的位置:search(x)

  测试案例分析

  在测试驱动开发实践中,第一步就是考虑测试方案,通过分析该类的功能,我们可以得到以下测试案例:

  1) 队列为空测试

   TC01: 队列新建时,应为空;

   TC02: 清空队列后,应为空;

   TC03: 当出队列操作次数与插入队列操作次数一样时,应为空;

  2) 插入队列测试:

   TC04: 插入队列操作后,新数据元素将插入在队列的未尾;

   TC05: 插入队列操作后,队列将一定不为空;

  3) 出队列测试

   TC06: 出队列操作后,第一个数据元素将被从队列中删除;

  4) 取队头测试

   TC07: 取队头操作将获得队列中的第一个数据元素。

  5) 清空队列测试

   TC08: 清空队列操作后,队列将为空队列;

  注: 此处为了讲解的方便,并未将所有的测试用例都列出,同时也选择了一些十分简单的测试用例。

  第一次迭代

  我们首先编写第一个测试代码,这一测试代码只考虑了测试案例TC01, 也就是保证新建的队列为空:

import junit.framework.*;
//每个使用JUnit编写的测试代码都应该包括本行
public class testQueue extends TestCase
//创建一个测试用例,继续TestCase
{
protected Queue q1;
public static void main (String[] args)
{
junit.textui.TestRunner.run (suite());
//执行测试用例
}
protected void setUp() //环境变量预备
{
q1= new Queue();
}
public static Test suite() //通用格式,指定测试内容
{
return new TestSuite(testQueue.class);
}
public void testEmpty() //以下每个方法就是一个测试
{
assertTrue(q1.empty());
//当队列新建时,应为空-TC01
}
}

  安装JUnit十分简单,只需在www.junit.org中下载最新的软件包(ZIP格式), 然后将其解压缩,并且将"JUnit安装目录\junit.jar" 以及"JUnit安装目录"都加到系统环境变量CLASSPATH中去即可。

  执行套件可以像上述程序一样在main方法中使用,也可以直接在命令行调用:java junit.textui.TestRunner 测试类名(文本格式)、java junit.awtui.TestRunner 测试类名(图形格式,AWT版)、java junit.swingui.TestRunner测试类名(图形版,Swing版)。

  编译执行(即在命令行执行javac testQueue.java和javatestQueue), 你会发现屏幕上出现提示:

  .E 一个小点说明执行了一个测试用例,E表示其失败

  Time: 0.11 说明执行测试共花费了0.11秒

  There was 1 error: 说明存在一个错误

  1) testEmpty(testQueue)java.lang.NoClassDefFoundError: Queue
    at testQueue.setUp(testQueue.java:13)
    at testQueue.main(testQueue.java:9)
  FAILURES!!!
  Tests run: 1, Failures: 0, Errors: 1

  测试没有通过是肯定的,因为Queue类都还没有写呢?怎么可能通过测试,因此,我们就编写以下代码,以使测试通过:

public class Queue extends java.util.Vector
{
public Queue()
{
super();
}
public boolean empty()
{
return super.isEmpty();
}
}

  将这个类编译后,再次执行测试程序,这时将出以下提示:

  . 一个小点说明执行了一个测试用例,没有E表示其成功

  Time: 0.11

  OK (1 test)

  你还可以使用前面我们说到的另两个命令,使测试反馈以图形化的形式体现出来,例如,执行java junit.awtui.TestRunner testQueue, 将出现:
感悟测试驱动开发(图一)
图1   第二次迭代

  接下来,我们修改测试程序,加入测试案例TC04、TC05的考虑。

import junit.framework.*;
public class testQueue extends TestCase
{
protected Queue q1,q2;
public static void main (String[] args)
{
junit.textui.TestRunner.run (suite());
}
protected void setUp() {
q1= new Queue();
q2= new Queue();
q2.inqueue("first"); /对队列q2执行插入队列操作
q2.inqueue("second");
}
public static Test suite()
{
return new TestSuite(testQueue.class);
}
public void testEmpty()
{
assertTrue(q1.empty());
//当队列新建时,应为空-TC01
}
public void testInqueue()
{
assertTrue(!(q2.empty()));
//执行了插入队列操作,队列就应不为空-TC05
assertEquals(1,q2.search("second"));
//search方法用于确定元素在队列中的位置
//后插入的数据元素,应在未尾-TC04
//插入两个,第一个在位置0, 第二在位置1
}
}

  根据这个测试代码,我们需要在Queue类中添加上inqueue() 和search() 两个方法,如下所示:

public class Queue extends java.util.Vector
{
public Queue()
{
super();
}
public boolean empty()
{
return super.isEmpty();
}
public synchronized void inqueue (Object x)
{
super.addElement(x);
}
public int search(Object x)
{
return super.indexOf(x);
}
}

  编译之后,再次执行java junit.awtui.TestRunnertestQueue, 你将再次看到成功的绿色。

感悟测试驱动开发(图二)
图2

  我们仔细看一下这一界面。

  1) 最上面列出了测试代码的类名,右边有一个"Run" 按钮,当你需要再次运行这一测试代码时,只需单击这个按钮。另外,将"Reload classesevery run" 选项打上勾很有用,当你测试未通过(出现红色时), 你可以转身去修改代码,修改完后,只需再按"Run" 按钮就可以再次运行。

  2) 中间区域是一个状态汇报区,红色表示未通过,统计了共运行了多少个测试(也就是在TestCase类中方法的数量)。

  3) 假如测试时出现错误,例如,我们不小心将"assertTrue(!(q2.empty()));" 误写成为"assertTrue(q2.empty());" 就将造成测试失败:

  注:由于第一个测试还是通过的,因此你会看到绿色条一闪。这时,你将会发现JUnit会将错误列出来,并且对应的"Run"按钮也由灰变成了亮,这表示你可以转身修改,完成后单击这个"Run按钮"可以只做刚才失效的这个测试,这将节省大量的时间。

  同时,在最下面的窗体里,列出了失效的具体原因。

感悟测试驱动开发(图三)

  后面的迭代   到这里,开发还没有完成,但这种思想却已经通过这样两个短小的实践传递出去了,后面的活大家可以动手试一下。

  另外值得一提的是,这里虽然洋洋洒洒一大篇,实际两次迭代花费了我不到15分钟就完成了。而且,当看到绿条时,心里十分愉快。

  一些遗憾

  文章到此就告一段落,但却有些许遗憾。

  遗憾之一:这只是一篇文章,没有办法把所有方面都讲得面面俱到,以致于大家可能无法马上上手。

   正是由于这样的原因,本文取名为"感悟", 与大家交流一下体会,希望能够帮助大家更好地接受"测试驱动开发"的理念,并开始着手实践。

  遗憾之二:笔者水平有限,无法解决大家的各种问题。

  让笔者感到欣慰的是,记载着这些答案的《测试驱动开发》、《灵敏软件开发》、《拥抱变化: 解析极限编程》等大作都已悉数摆上了中国的书店。路虽难走,但明师已有。

  实践永远是学习的最好方法,看到笔者的感悟,就开始极限之旅吧,因为那里风光无限,乐趣无限。当你把握了测试驱动开发的精髓,那你就能够对你自己编写的所有代码布满信心,不再担心它们什么时候在你的后面放一冷箭,从此离别这给你带来无限压力的苦恼。
上一篇:软件开发的未来中程序员与客户的矛盾 人气:250
下一篇:RSA中UML建模元素的扩展与定制 人气:308
浏览全部软件工程的内容 Dreamweaver插件下载 常用网页广告代码全集
  最新网站源码 最新软件下载
2008-9-6 Movie34电影搜索引擎 v3.0
2008-9-6 wap2.0仿帝国建站喜用 v2.0
2008-9-6 免费人才招聘网 宽屏版 v3.01
2008-9-6 喜喔喔视频采集程序 v1.0 beta
2008-9-6 ASP客户管理系统
2008-9-6 主流驿站中秋祝福程序
2008-9-6 php实现msn协议的类
2008-9-5 Coppermine Photo Gallery v1.4.
2008-9-5 清松网络日记本 v2.4
2008-8-23 Mini WinMount V0.4
2008-8-23 Vista优化大师3.11正式版
2008-8-23 Wine 1.13
2008-8-23 KlipFolio 5.0 Build 5899-80
2008-8-23 Windows Sysinternals Desktops
2008-8-23 OneTap Movies1.2破解版
2008-8-23 AnnotaterPDF阅读1.1.503 破解版
2008-8-23 SoundMeter分贝测量仪 v1.0汉化破
2008-8-23 iDrum音乐节拍1.0破解版
  发表评论
姓 名: 验证码:
内 容:
站长工具:网站收录查询 | Google PR查询 | ALEXA排名查询 | CSS在线编辑器 | 广告代码 | Html转换js | js/vbs加密 | md5加密 | 进制转换
实用工具:汉字翻译拼音 | 符号对照表 | 个税计算 | 经典小工具 | 汉字简繁转换 | 普通单位换算 | 公制单位换算 | 生辰老黄历 | 国内电话区号 国家代码与域名缩写 | 文字加密解密 | 健康查询 | 万年历 | 汉字横竖排版 | 手机号码查询 | 计算器 | ip搜索
业务联系 | 广告刊登 | 频道合作 | 投稿荐稿 | 联系方式 | 加入收藏 | RSS订阅
Copyright © 2000-2008 www.knowsky.com All rights reserved | 网络实名:动态网站制作指南 | 沪ICP备05001343号
ホームページ制作 不動産検索システム 求人情報
防水工事·改修工事 フットサル大会 探偵