﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-辰o(^o^)o的专栏[除非注释原创，其它文章基本来源于网络]-文章分类-测试</title><link>http://www.blogjava.net/jackybu/category/966.html</link><description>&lt;a href="http://www.fastonlineusers.com"&gt;&lt;b&gt;&lt;font color=red&gt;共有&lt;script src=http://fastonlineusers.com/online.php?d=jackybu.blogjava.net&gt;&lt;/script&gt;人在同时阅读此Blog&lt;/font&gt;&lt;/b&gt;&lt;/a&gt;</description><language>zh-cn</language><lastBuildDate>Fri, 02 Mar 2007 03:30:21 GMT</lastBuildDate><pubDate>Fri, 02 Mar 2007 03:30:21 GMT</pubDate><ttl>60</ttl><item><title>版本控制工具 </title><link>http://www.blogjava.net/jackybu/articles/3139.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Mon, 11 Apr 2005 06:47:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/3139.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/3139.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/3139.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/3139.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/3139.html</trackback:ping><description><![CDATA[<P><STRONG>版本控制工具</STRONG><BR><STRONG>&nbsp;&nbsp;&nbsp; </STRONG>版本控制是程序开发、管理必不可少的工具，特别是在多人协作的团队中，适宜的版本控制工具可以提高开发效率，消除很多有代码版本带来的问题。本文首先列举没有版本控制工具时可能遇到的问题，再对主流版本控制工具做概要介绍，之后对作为Java开发者首选的版本控制工具CVS的历史、功能、概念做详细的介绍；最后在Eclipse＋CVS环境中，以CVS使用的一个完整流程为例，介绍如何正确的使用CVS工具。<BR><BR><STRONG>为什么要使用版本控制工具？</STRONG><BR>如果没有版本控制工具的协助，在开发中我们经常会遇到下面的一些问题：<BR>一、&nbsp;代码管理混乱。如果是别人添加或删除一个文件，你很难发现。没有办法对文件代码的修改追查跟踪。甚至出现文件丢失，或新版本代码被同伴无意覆盖等现象。<BR>二、&nbsp;解决代码冲突困难。当大家同时修改一个公共文件时，解决代码冲突是一件很头疼的事。最原始的办法是手工打开冲突文件，逐行比较，再手工粘贴复制。更高级的做法是使用文件比较工具，但仍省不了繁杂的手工操作，一不小心，甚至会引入新的bug。<BR>三、&nbsp;在代码整合期间引入深层BUG。例如开发者A写了一个公共函数，B觉得正好可以复用；后来A又对这个公共函数进行了修改，添加了新的逻辑，而这个改动的却是B不想要的。或者是A发现这个公共函数不够用，又新做了一个函数，B却没有及时获得通知。这些，都为深层BUG留下隐患。<BR>四、&nbsp;无法对代码的拥有者进行权限控制。代码完全暴露在所有的开发者面前，任何人都可以随意进行增、删、改操作，无法指定明确的人对代码进行负责。特别是产品的开发，这是极其危险的。<BR>五、&nbsp;项目不同版本发布困难。特别是对产品的开发，你会频繁的进行版本发布，这时如果没有一个有效的管理产品版本的工具，一切将变得非常艰难。<BR>&nbsp;&nbsp;&nbsp; 上面只是列举了一些没有版本控制系统可能带来的问题，特别是对大型项目和异地协同开发有了一个合适的版本控制工具，它可以有效解决因为代码版本不同引起的各种问题，让我们的开发人员能更多的把精力花费在开发上面。而不是每次都花费很多时间进行代码整合和解决版本不同带来的各种问题。</P>
<P><STRONG>主流版本控制工具介绍</STRONG><BR>&nbsp;&nbsp;&nbsp; 现在，有很多优秀的版本控制工具供我们选择，下面就五种主流的版本控制工具做简单的介绍。<BR><STRONG>Starteam</STRONG> <BR>&nbsp;&nbsp;&nbsp; 是一个集合了版本控制、构建管理（Build Management）和缺陷跟踪系统为一体的软件，并且具有强大的图形界面，易学易用；但管理复杂、维护困难。2002年底被Borland公司收购。<BR><STRONG>PVCS Version Manager<BR></STRONG>&nbsp;&nbsp;&nbsp;&nbsp; 是美国的MERANT公司软件配置管理工具PVCS 家族中的一个组成部分，它能够实现源代码、可执行文件、应用文件、图形文件和文档的版本管理；它能安全地支持软件并行开发，对多个软件版本的变更进行有效的控制管理。<BR><STRONG>ClearCase(CC)<BR></STRONG>&nbsp;&nbsp;&nbsp; 是ROSE构件的一部分，目前最牛的配置管理工具，主要应用于复杂的产品发放、分布式团队合作、并行的开发和维护任务。可以控制word, excel,powerpoint，visio等文件格式，对于不认识的格式可以自己定义一种类型来标识。<BR><STRONG>Visual SourceSafe（VSS）<BR></STRONG>&nbsp;&nbsp;&nbsp; 简单易用、方便高效、与Windows操作系统及微软开发工具高度集成。<BR><STRONG>CVS（Concurrent Versions System）<BR></STRONG>&nbsp;&nbsp;&nbsp; 是开发源码的并发版本系统,它是目前最流行的面向软件开发人员的源代码版本管理解决方案。它可用于各种平台，包括 Linux 、Unix和 Windows NT/2000/XP等等。<BR>&nbsp;&nbsp;&nbsp; 前面三种是重量级的商业版本控制工具，更适合庞大的团队和项目，并且价格不菲。Visual SourceSafe是微软的产品，当然只能用在windows平台并与微软的开发工具无缝集成。CVS免费开源，并且几乎所有开源项目都是使用CVS进行版本管理，无疑，它是我们Java开发者最优选择。<BR><BR><STRONG>CVS的历史、功能、基本概念的介绍<BR><BR>历史</STRONG><BR>&nbsp;&nbsp;&nbsp; CVS 诞生于 1986 年，当时作为一组 shell 脚本而出现；1989年3月，Brian Berlinor用C语言重新设计并编写了CVS的代码；1993年前后，Jim Kingdon最终将CVS设计成基于网络的平台，开发者们能从Internet任何地方获得程序源代码。截至目前最新版本是2004年12月13日发布的1.12.11。<BR><BR><STRONG>功能介绍</STRONG><BR>一、&nbsp;代码统一管理，保存所有代码文件更改的历史记录。对代码进行集中统一管理，可以方便查看新增或删除的文件，能够跟踪所有代码改动痕迹。可以随意恢复到以前任意一个历史版本。并避免了因为版本不同引入的深层BUG。<BR>二、&nbsp;完善的冲突解决方案，可以方便的解决文件冲突问题，而不需要借助其它的文件比较工具和手工的粘贴复制。<BR>三、&nbsp;代码权限的管理。可以为不同的用户设置不同的权限。可以设置访问用户的密码、只读、修改等权限，而且通过CVS ROOT目录下的脚本，提供了相应功能扩充的接口，不但可以完成精细的权限控制，还能完成更加个性化的功能。<BR>四、&nbsp;支持方便的版本发布和分支功能。</P>
<P><STRONG>基本概念<BR>资源库（Repository）</STRONG><BR>CVS的资源库存储全部的版本控制下的文件copy，通常不容许直接访问，只能通过cvs命令，获得一份本地copy，改动后再check in（commit）回资源库。而资源库通常为与工作目录分离的。CVS通过多种方式访问资源库。每种方法有不同目录表示形式。<BR><STRONG>版本（Revision）</STRONG><BR>每一个文件的各个版本都不相同，形如1.1, 1.2.1,一般1.1是该文件的第一个revision，后面的一个将自动增加最右面的一个整数，比如1.2, 1.3, 1.4...有时候会出现1.3.2.2，原因见后。revision总是偶数个数字。一般情况下将revision看作时CVS自己内部的一个编号，而tag则可以标志用户的特定信息。<BR><STRONG>标签（Tag）</STRONG><BR>用符号化的表示方法标志文件特定revision的信息。通常不需要对某一个孤立的文件作tag，而是对所有文件同时作一个tag，以后用户可以仅向特定tag的文件提交或者checkout。另外一个作用是在发布软件的时候表示哪些文件及其哪个版本是可用的；各文件不同revision可以包括在一个tag中。如果命名一个已存在的tag默认将不会覆盖原来的；<BR><STRONG>分支（Branch）<BR></STRONG>当用户修改一个branch时不会对另外的branch产生任何影响。可以在适当的时候通过合并的方法将两个版本合起来；branch总是在当前revision后面加上一个偶数整数（从2开始，到0结束），所以branch总是奇数个数字，比如1.2后面branch为1.2.2，该分支下revision可能为1.2.2.1,1.2.2.2,...<BR><STRONG>冲突（Conflct）<BR></STRONG>完全是纯文本的冲突，不包含逻辑上的矛盾。一般是一份文件，A做了改动，B在A提交之前也做了改动，这样最后谁commit就会出现冲突，需要手工解决冲突再提交。<BR><BR><STRONG>CVS与eclipse集成开发</STRONG><BR>&nbsp; 前面对CVS的历史、功能、概论等理论知识做了介绍。下面我们将使用最流行的Java IDE Eclipse中内置的CVS工具，以一个完整开发流程，介绍实际环境中CVS的正确使用。关于CVS系统的安装，不是本文的内容，您可以从附录的链接中获取安装的介绍资料。<BR><BR><STRONG>常用的CVS控制命令</STRONG><BR><STRONG>Check Out（检出）</STRONG><BR>把源文件从cvs源代码仓库中取出，缺省的版本是最新的版本，你也可以选择指定的版本。在每次更改源代码之前，需要Check Out最新的版本，再起基础之上对源代码进行修改。将代码目录checkout到指定目录下，所有文件都是read-write。<BR><STRONG>Check In（检入）</STRONG><BR>把源代码加入到cvs源代码仓库中，每一个添加进代码库中的文件的版本是 1.1。以后每次修改文件重新ci以后，此文件的版本递增为1.2 ，1.3.……。在每次对源代码修改之后，需要Check In，提交最新版本的源代码。<BR><STRONG>Synchronize with Repository(与资源库同步，简称同步)</STRONG><BR>使本地更改与资源库同步，它会列出本地和资源库之间不同的所有文件。<BR><STRONG>Add to Version Control</STRONG><BR>将新的文件加入到版本控制之中。<BR><STRONG>Add to .cvsIgnore</STRONG><BR>将文件设置到版本控制之外，这样该文件或目录中的文件的更改在CVS中不可见，即使同步也无法发现。</P>
<P><STRONG>CVS正确使用步骤<BR>一、&nbsp;同步（Synchronize）</STRONG><BR>就是将本地更改与服务器同步，同步之后可以清晰的看到上一捡出（Check Out）版本之后本地、服务器上的最新改动。这是非常有用的，特别是敏捷开发，强调集体拥有代码。有了同步功能，你可以全局把握项目的代码，可以很方便的跟踪公共模块代码的任何改动。<BR>具体操作：在Eclipse的资源视图（Resource Perspective）或者Java视图（Java Perspective）中，选中要同步的目录，点击右键选择"Synchronize with Repository",之后它将显示同步的视图。如下图：<BR>&nbsp;<IMG alt="" hspace=0 src="file:///F:/j2ee_s/csdn-java/synchronize_1.bmp" align=baseline border=0><BR>(图一、CVS同步视图)<BR>同步之后，它有四种Mode可以选择，见上图绿色框框里按钮。从做到右分别为：<BR>Incoming Mode：表示修改是来自服务器，对应于更新（update）操作。<BR>Outgoing Mode：表示修改是来自本地，对应提交（commit）操作。<BR>Incoming/ Outgoing Mode：本地和服务器修改都在该模式（Mode）中显示。<BR>Conflicts Mode：显示本地和服务器修改的冲突文件。<BR><STRONG>二、&nbsp;更新（update）<BR></STRONG>比较简单，选择Incoming Mode，再选中要更新的文件，右键选择update操作。<BR><STRONG>三、&nbsp;解决冲突并合并(solve conflct and merge)</STRONG><BR>如果有冲突文件，冲突文件不能更新。你必须先解决冲突再操作。选中冲突的文件，再点右键选择"Open in Compare Editor"，用比较工具打开该文件。如下图： <BR><IMG alt="" hspace=0 src="file:///F:/j2ee_s/csdn-java/cmpare.bmp" align=baseline border=0><BR>（图二、CVS比较器视图）</P>
<P>比较器（Compare）视图，左边版本底的是本地文件（Local File），右边是远程服务器文件（Remote File）。使用"Select Next Change"按钮（绿框中的第一箭头向下按钮），逐一查看不同点。如果不同点标识为黑色框框，则不用管它。如果是蓝色框框，则需要手工调整。如上图，不同点是蓝色框框，将鼠标放到两个不同点的中间小方框中，则凸出一个向右的按钮，并显示提示信息"Copy Current Change from Right to Left"，意思是将右边服务器的不同点覆盖到左边的本地文件。点中此按钮。重复这样的操作，将所有服务器上的更改拷贝到本地。<BR>如果有一行代码，本地和服务器都同时做了修改。这时，修改点则显示红色框框。这时，你就必须手工做正确的修改。全部修改完成，保存本地文件。<BR>此时，如果修改点没有了蓝色的框框，就可以开始做合并（merge）操作了。操作也很简单，选择该文件，点击右键，选择"Mark as merged"。<BR>注意：必须确保没有蓝色框框，即完全拷贝了服务器的修改才可以做合并（merge）操作，否则会覆盖服务器上的代码。<BR><STRONG>四、&nbsp;提交（commit）<BR></STRONG>更新服务器代码，解决冲突之后，首先要查看本地文件修改之后是否有错误。如果有，当然首先解决错误，再提交。<BR><BR><STRONG>附录：</STRONG><BR><A href="http://www.8848software.com/scmchina/scmtools.htm">http://www.8848software.com/scmchina/scmtools.htm</A> 由很多版本控制工具的文档链接。<BR><A href="http://www.perforce.com/perforce/reviews.html">http://www.perforce.com/perforce/reviews.html</A> Infrastructure Group对Perforce 和Clearcase, CVS, PVCS,Visual SourceSafe (VSS)几种CM工具进行了定量和定性的比较. 对于定性的比较，内容涉及工具支持的方法和环境；对于定量的比较，包括在不同的项目规模上，执行不同的活动所需要的时间。<BR></P><BR><img src ="http://www.blogjava.net/jackybu/aggbug/3139.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-04-11 14:47 <a href="http://www.blogjava.net/jackybu/articles/3139.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>单元测试－入门篇 </title><link>http://www.blogjava.net/jackybu/articles/3138.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Mon, 11 Apr 2005 06:46:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/3138.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/3138.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/3138.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/3138.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/3138.html</trackback:ping><description><![CDATA[<P>前面的一篇文章（单元测试－理论篇）讨论了什么是单元测试、单元测试的优点并列举了很多不写单元测试的借口。如果你同意我们的观点，认同单元测试确实是软件开发中不可缺少的过程，那么我们就开始单元测试之旅吧！</P>
<P><BR><STRONG>一个比较最大值的函数<BR></STRONG>&nbsp; 我们首先引入一个比较最大值的函数。我们传入一个类型为int的数组参数，它将返回最大值的那个元素。代码如下：<BR>public class Largest {<BR>&nbsp;public static int largest(int[] datas){<BR>&nbsp;&nbsp;int max = 0;<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;for(int i = 0 ; i &lt; datas.length ; i++){<BR>&nbsp;&nbsp;&nbsp;if(max &lt; datas[i]){<BR>&nbsp;&nbsp;&nbsp;&nbsp;max = datas[i];<BR>&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;return max;<BR>&nbsp;}<BR>}<BR>&nbsp; 可是，如何写我们的测试代码呢？</P>
<P><BR>直接在Largest类中添加一个main方法，要么重新写一个可运行的类来测试Largest。这样的测试，同样给我们带来了很大的挑战：<BR>1、&nbsp;验证困难。如何去验证代码的行为和我们的期望一致呢？使用很多的if…else再加上＝＝或equals()来判断？对异常的情况又如何处理呢？混乱的验证，很容易给我们的测试代码带来BUG，让我们对自己的测试不够自信。<BR>2、&nbsp;测试类无法管理。我们如何直观的得到测试运行成功或失败的消息?用原始的System.out.println()吗？我们能一次运行多个单元测试吗？如果前面的测试运行出现异常，后面的测试还能继续运行吗？如果测试类很多，上百个甚至更多，我们能方便的由控制台输出测试结果吗？<BR>3、&nbsp;无法统计测试代码覆盖情况。缺少统一的测试代码编写规范和约定，可读性和维护性差。<BR>不过，面对这些挑战不用沮丧。单元测试框架已经帮我们解决了这些问题，它提供了很多测试的基础设施，让我们能把更多的经历投入到测试代码的编写中来。</P>
<P><BR><STRONG>JUnit</STRONG><BR>JUnit最初是由Erich Gamma（GoF之一）和Kent Beck（xp和refactor的先驱之一）编写的，它是一个开源的Java测试框架，用于编写和运行可重复的测试。</P>
<P><BR>下面我们逐步介绍如何对Largest类测试：<BR>一、&nbsp;JUnit的安装。如果你使用的开发工具是Eclipse，不用做任何安装，它已经提供了Junit的支持。否则，你需要去<A href="http://www.junit.org/">http://www.junit.org/</A> 下载Junit安装包。安装非常简单，只要将junit.jar包设置到ClassPath中，让你的Java代码能够找到它就可以了。<BR>二、&nbsp;编写测试代码。代码如下：<BR>&nbsp;&nbsp;&nbsp; public class LargestTest extends TestCase {<BR>&nbsp;&nbsp;public void testLargest(){<BR>&nbsp;&nbsp;&nbsp;int[] datas = {7,8,9};<BR>&nbsp;&nbsp;&nbsp;assertEquals(9,Largest.largest(datas));<BR>&nbsp;&nbsp;}<BR>}<BR>说明：<BR>1、&nbsp;测试类一般要继承抽象类TestCase。它实现了各种测试方法，并提供了一个测试过程的架构。<BR>2、&nbsp;测试代码通过断言（Assert）来判断某个被测试函数是否正常工作。JUnit提供了很多断言函数，用来确定：某个条件是否为真；两个数据是否相等，或者不等，或者其它的一些情况。<BR>3、&nbsp;测试方法名以“test”开头，这样JUnit框架会自动发现这是一个测试方法。</P>
<P>三、&nbsp;运行测试类。<BR>&nbsp;&nbsp; 运行测试成功。</P>
<P>我们的单元测试这样就算完成了吗？不，上面的测试只能算是一次验证而已。我们给的数据中，最大值9是数组的最后一个元素，如果9是第一个元素它还正确吗？如果数据是负数呢？等等。我们的求最大值函数有着很多的边界情况需要单元测试来验证。<BR>&nbsp;&nbsp; 因此，我们在写单元测试之前，一定要对测试做一个周全的计划，预先设置好要测试的内容，可能发生错误的边界条件。<BR>下面是对Largest做的测试计划：<BR>1、&nbsp;数组元素的位置是否对最大值产生影响？<BR>l&nbsp;[7,8,9] – 9<BR>l&nbsp;[7,9,8] – 9<BR>l&nbsp;[9,8,7] – 9<BR>2、&nbsp;如果有两个相等的最大值，会出现什么情况呢？<BR>l&nbsp;[7,9,8,9] – 9<BR>3、如果数组中只有一个元素，结果会怎么样？<BR>l&nbsp;[1] - 1<BR>4、&nbsp;如果元素都是负数呢？<BR>l&nbsp;[-7,-8,-9] - -7<BR>完整的测试代码应该如下：<BR>public class LargestTest extends TestCase {<BR>&nbsp;<BR>&nbsp;public void testSimple(){<BR>&nbsp;&nbsp;assertEquals(9,Largest.largest(new int[]{7,8,9}));<BR>&nbsp;}<BR>&nbsp;public void testOrder(){<BR>&nbsp;&nbsp;assertEquals(9,Largest.largest(new int[]{7,9,8}));<BR>&nbsp;&nbsp;assertEquals(9,Largest.largest(new int[]{9,8,7}));<BR>&nbsp;}<BR>&nbsp;public void testDups(){<BR>&nbsp;&nbsp;assertEquals(9,Largest.largest(new int[]{7,9,8,9}));<BR>&nbsp;}<BR>&nbsp;public void testOne(){<BR>&nbsp;&nbsp;assertEquals(1,Largest.largest(new int[]{1}));<BR>&nbsp;}<BR>&nbsp;public void testNegative(){<BR>&nbsp;&nbsp;&nbsp;assertEquals(-7,Largest.largest(new int[]{-7,-8,-9}));<BR>&nbsp;}<BR>}<BR>当然，你可以写完一个测试方法就立即来运行它。这次并没有那么幸运了，在运行最后一个测试方法testNegative()时出现了错误：<BR>junit.framework.AssertionFailedError: expected:&lt;-7&gt; but was:&lt;0&gt;<BR>&nbsp;at test.junit.LargestTest.testNegative(LargestTest.java:24)<BR>细心的你，也许在一开始就发现了Largest的这个Bug。原来我们的字段max初始化为0是不对的，应该改为Integer.MIN_VALUE。<BR>由此我们可以想到，使用单元测试确实可以尽早的发现隐藏的BUG，上一篇我们也说过，越早发现BUG就能节省更多的时间，降低更多的风险。<BR>这是，我们的单元测试已经完美结束了吗？呵呵，也许你会想到，如果在largest()方法中传入数组为空，又会怎么样呢？这个问题留给我们的读者思考吧。</P>
<P><BR>写到这里，算是入门结束了吧！关于JUnit的详细介绍，网上有非常多的文章，去google你可以找到一大堆。下面我提供几个不错的单元测试网站，希望能对你有所帮助：<BR>51Testing-无忧软件测试网：<A href="http://www.51testing.com/">http://www.51testing.com/</A><BR>测试时代：<A href="http://www.testage.net/">http://www.testage.net/</A><BR>UML软件工程组织－软件测试：<A href="http://www.uml.org.cn/Test/test.asp">http://www.uml.org.cn/Test/test.asp</A><BR>测试管理中心：<A href="http://www.testmanager.com.cn/">http://www.testmanager.com.cn/</A><BR>软件工程专家网：<A href="http://www.51cmm.com/">http://www.51cmm.com/</A><BR>开放软件测试研究：<A href="http://www.opentest.net/">http://www.opentest.net/</A><BR></P><img src ="http://www.blogjava.net/jackybu/aggbug/3138.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-04-11 14:46 <a href="http://www.blogjava.net/jackybu/articles/3138.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>单元测试－理论篇 </title><link>http://www.blogjava.net/jackybu/articles/3137.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Mon, 11 Apr 2005 06:45:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/3137.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/3137.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/3137.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/3137.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/3137.html</trackback:ping><description><![CDATA[<P>作者：Moxie</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 测试是软件开发的重要环节之一。按照软件开发的过程测试可分为：单元测试、集成测试、系统测试、域测试（Field test）等。我们这里将讨论面向程序员的单元测试。本文首先介绍单元测试的定义，为什么要使用单元测试？单元测试能给我们带来的好处。之后我们将介绍单元测试的范畴，最后将讨论很多朋友不写单元测试的借口。希望本文能够再次引起您对单元测试的重视，并说服您老板对编写单元测试的支持，能让美丽的单元测试真正应用到您的项目之中。<BR><BR><STRONG><FONT size=4>什么是单元测试</FONT></STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 单元测试是开发者编写的一小段代码，用于检验被测代码的一个很小的、很明确的功能是否正确。通常而言，一个单元测试是用于判断某个特定条件（或者场景）下某个特定函数的行为。例如，你可能把一个很大的值放入一个有序list 中去，然后确认该值出现在list 的尾部。或者，你可能会从字符串中删除匹配某种模式的字符，然后确认字符串确实不再包含这些字符了。<BR>&nbsp;&nbsp;&nbsp; 单元测试是由程序员自己来完成，最终受益的也是程序员自己。可以这么说，程序员有责任编写功能代码，同时也就有责任为自己的代码编写单元测试。执行单元测试，就是为了证明这段代码的行为和我们期望的一致。<BR><BR><STRONG><FONT size=4>为什么要使用单元测试</FONT></STRONG><BR>&nbsp;&nbsp;&nbsp; 我们编写代码时，一定会反复调试保证它能够编译通过。如果是编译没有通过的代码，没有任何人会愿意交付给自己的老板。但代码通过编译，只是说明了它的语法正确；我们却无法保证它的语义也一定正确，没有任何人可以轻易承诺这段代码的行为一定是正确的。<BR>&nbsp;&nbsp;&nbsp; 幸运，单元测试会为我们的承诺做保证。编写单元测试就是用来验证这段代码的行为是否与我们期望的一致。有了单元测试，我们可以自信的交付自己的代码，而没有任何的后顾之忧。<BR><BR><STRONG>单元测试有下面的这些优点：</STRONG><BR><STRONG>1、它是一种验证行为。<BR></STRONG>&nbsp;&nbsp;&nbsp; 程序中的每一项功能都是测试来验证它的正确性。它为以后的开发提供支缓。就算是开发后期，我们也可以轻松的增加功能或更改程序结构，而不用担心这个过程中会破坏重要的东西。而且它为代码的重构提供了保障。这样，我们就可以更自由的对程序进行改进。<BR><STRONG>2、它是一种设计行为。<BR></STRONG>&nbsp;&nbsp;&nbsp; 编写单元测试将使我们从调用者观察、思考。特别是先写测试（test-first），迫使我们把程序设计成易于调用和可测试的，即迫使我们解除软件中的耦合。<BR><STRONG>3、它是一种编写文档的行为。<BR></STRONG>&nbsp;&nbsp;&nbsp; 单元测试是一种无价的文档，它是展示函数或类如何使用的最佳文档。这份文档是可编译、可运行的，并且它保持最新，永远与代码同步。<BR><STRONG>4、它具有回归性。<BR></STRONG>&nbsp;&nbsp;&nbsp; 自动化的单元测试避免了代码出现回归，编写完成之后，可以随时随地的快速运行测试。 <BR><BR><STRONG><FONT size=4>单元测试的范畴<BR></FONT></STRONG>&nbsp;&nbsp;&nbsp; 如果要给单元测试定义一个明确的范畴，指出哪些功能是属于单元测试，这似乎很难。但下面讨论的四个问题，基本上可以说明单元测试的范畴，单元测试所要做的工作。<BR><STRONG>1、&nbsp;它的行为和我期望的一致吗？</STRONG><BR>&nbsp;&nbsp;&nbsp; 这是单元测试最根本的目的，我们就是用单元测试的代码来证明它所做的就是我们所期望的。<BR><STRONG>2、&nbsp;它的行为一直和我期望的一致吗？</STRONG><BR>&nbsp;&nbsp;&nbsp; 编写单元测试，如果只测试代码的一条正确路径，让它正确走一遍，并不算是真正的完成。软件开发是一个项复杂的工程，在测试某段代码的行为是否和你的期望一致时，你需要确认：在任何情况下，这段代码是否都和你的期望一致；譬如参数很可疑、硬盘没有剩余空间、缓冲区溢出、网络掉线的时候。<BR><STRONG>3、&nbsp;我可以依赖单元测试吗？</STRONG><BR>&nbsp;&nbsp; 不能依赖的代码是没有多大用处的。既然单元测试是用来保证代码的正确性，那么单元测试也一定要值得依赖。<BR><STRONG>4、&nbsp;单元测试说明我的意图了吗？</STRONG><BR>&nbsp;&nbsp;&nbsp; 单元测试能够帮我们充分了解代码的用法，从效果上而言，单元测试就像是能执行的文档，说明了在你用各种条件调用代码时，你所能期望这段代码完成的功能。<BR><BR><FONT size=4><STRONG>不写测试的借口</STRONG><BR></FONT>&nbsp;&nbsp;&nbsp; 到这里，我们已经列举了使用单元测试的种种理由。也许，每个人都同意，是的，该做更多的测试。这种人人同意的事情还多着呢，是的，该多吃蔬菜，该戒烟，该多休息，该多锻炼……这并不意味着我们中的所有人都会这么去做，不是吗？<BR><STRONG>1、&nbsp;编写单元测试太花时间了。</STRONG><BR>&nbsp;&nbsp;&nbsp; 我们知道，在开发时越早发现BUG，就能节省更多的时间，降低更多的风险。<BR>&nbsp;&nbsp;&nbsp; 下图表摘自&lt;&lt;实用软件度量&gt;&gt;(Capers Jones，McGraw-Hill 1991)，它列出了准备测试，执行测试，和修改缺陷所花费的时间(以一个功能点为基准)，这些数据显示单元测试的成本效率大约是集成测试的两倍，是系统测试的三倍(参见条形图)。<BR>&nbsp;<IMG alt="" hspace=0 src="file:///F:/j2ee_s/csdn-java/why.jpg" align=baseline border=0><BR>&nbsp;&nbsp;&nbsp; 术语：域测试(Field test)意思是在软件投入使用以后，针对某个领域所作的所有测试活动。<BR>&nbsp;&nbsp;&nbsp; 如果你仍然认为在编写产品代码的时候，还是没有时间编写测试代码，那么请先考虑下面这些问题：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1）、对于所编写的代码，你在调试上面花了多少时间。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2）、对于以前你自认为正确的代码，而实际上这些代码却存在重大的bug，你花了多少时间在重新确认这些代码上面。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3）、对于一个别人报告的bug，你花了多少时间才找出导致这个bug 的源码位置。<BR>&nbsp;&nbsp;&nbsp; 回答完这些问题，你一定不再以“太花时间”作为拒绝单元测试的借口。<BR><STRONG>2、&nbsp;运行测试的时间太长了。</STRONG><BR>&nbsp;&nbsp;&nbsp; 合适的测试是不会让这种情况发生的。实际上，大多数测试的执行都是非常快的，因此你在几秒之内就可以运行成千上万个测试。但是有时某些测试会花费很长的时间。这时，需要把这些耗时的测试和其他测试分开。通常可以每天运行这种测试一次，或者几天一次。<BR><STRONG>3、&nbsp;测试代码并不是我的工作。</STRONG><BR>&nbsp;&nbsp;&nbsp; 你的工作就是保证代码能够正确的完成你的行为，恰恰相反，测试代码正是你不可缺少的工作。<BR><STRONG>4、&nbsp;我并不清楚代码的行为，所以也就无从测试。</STRONG><BR>&nbsp;&nbsp; 如果你实在不清楚代码的行为，那么估计现在并不是编码的时候。如果你并不知道代码的行为，那么你又如何知道你编写的代码是正确的呢?<BR><STRONG>5、&nbsp;但是这些代码都能够编译通过。</STRONG><BR>&nbsp;&nbsp;&nbsp; 我们前面已经说过，代码通过编译只是验证它的语法通过。但并不能保证它的行为就一定正确。<BR><STRONG>6、&nbsp;公司请我来是为了写代码，而不是写测试。</STRONG><BR>&nbsp;&nbsp;&nbsp; 公司付给你薪水是为了让你编写产品代码，而单元测试大体上是一个工具，是一个和编辑器、开发环境、编译器等处于同一位置的工具。<BR><STRONG>7、&nbsp;如果我让测试员或者QA（Quality Assurance）人员没有工作，那么我会觉得很内疚。</STRONG><BR>&nbsp;&nbsp; 你并不需要担心这些。请记住，我们在此只是谈论单元测试，而它只是一种针对源码的、低层次的，为程序员而设计的测试。在整个项目中，还有其他的很多测试需要这些人来完成，如：功能测试、验收测试、性能测试、环境测试、有效性测试、正确性测试、正规分析等等。<BR><STRONG>8、&nbsp;我的公司并不会让我在真实系统中运行单元测试。<BR></STRONG>&nbsp;&nbsp;&nbsp; 我们所讨论的只是针对开发者的单元测试。也就是说，如果你可以在其他的环境下（例如在正式的产品系统中）运行这些测试的话，那么它们就不再是单元测试，而是其他类型的测试了。实际上，你可以在你的本机运行单元测试，使用你自己的数据库，或者使用mock 对象。<BR><BR><STRONG><FONT size=4>总结<BR></FONT></STRONG>&nbsp; 总而言之，单元测试会让我们的开发工作变得更加轻松，让我们对自己的代码更加自信。无论是大型项目还是小型项目，无论是时间紧迫的项目还是时间宽裕的项目，只要代码不是一次写完永不改动，编写单元测试就一定超值，它已成为我们编码不可缺少的一部分。<BR><BR><STRONG><FONT size=4>参考资料<BR></FONT></STRONG>《单元测试之道Java版——使用JUNIT》：这是一本非常好的介绍单元测试的书，作者讲的非常透彻，译者的文笔也很好。在此向您强烈推荐。本文内容，也有很多直接引用于此书！<BR>《JUNIT IN ACTION》：这是一本专门介绍JUNIT的好书。<BR></P><img src ="http://www.blogjava.net/jackybu/aggbug/3137.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-04-11 14:45 <a href="http://www.blogjava.net/jackybu/articles/3137.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Junit学习笔记</title><link>http://www.blogjava.net/jackybu/articles/2898.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Thu, 07 Apr 2005 02:44:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/2898.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/2898.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/2898.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/2898.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/2898.html</trackback:ping><description><![CDATA[<A title="Junit Home page" href="http://www.infomall.cn/cgi-bin/mallgate/20031008/http://www.junit.org/index.htm">JUnit</A>是由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架（regression testing framework）,供Java开发人员编写单元测试之用。<A name=more></A> 
<P><STRONG>1、概述</STRONG><BR>　　Junit测试是程序员测试，即所谓白盒测试，因为程序员知道被测试的软件如何（How）完成功能和完成什么样（What）的功能。<BR>　　Junit本质上是一套框架，即开发者制定了一套条条框框，遵循这此条条框框要求编写测试代码，如继承某个类，实现某个接口，就可以用Junit进行自动测试了。<BR>　　由于Junit相对独立于所编写的代码，可以测试代码的编写可以先于实现代码的编写，XP 中推崇的 test first design的实现有了现成的手段：用Junit写测试代码，写实现代码，运行测试，测试失败，修改实现代码，再运行测试，直到测试成功。以后对代码的修改和优化，运行测试成功，则修改成功。<BR>　　Java 下的 team 开发，采用 cvs(版本控制) + ant(项目管理) + junit(集成测试) 的模式时，通过对ant的配置，可以很简单地实现测试自动化。</P>
<P>　　对不同性质的被测对象，如Class，Jsp，Servlet，Ejb等，Junit有不同的使用技巧，以后慢慢地分别讲叙。以下以Class测试为例讲解，除非特殊说明。</P>
<P><STRONG>2、下载安装</STRONG><BR><IMG height=504 alt=junit-alltest.gif src="http://hedong.3322.org/archives/pics/junit-alltest.gif" width=474 align=right border=0> 
<UL>
<LI>去<A href="http://www.infomall.cn/cgi-bin/mallgate/20031008/http://www.junit.org/index.htm">Junit主页</A>下载最新版本3.8.1程序包junit-3.8.1.zip<BR>
<LI>用winzip或unzip将junit-3.8.1.zip解压缩到某一目录名为$JUNITHOME<BR>
<LI>将junit.jar和$JUNITHOME/junit加入到CLASSPATH中，加入后者只因为测试例程在那个目录下。<BR>
<LI><INS>注意不要将junit.jar放在jdk的extension目录下</INS><BR>
<LI>运行命令,结果如右图。 
<DIV class=code>java junit.swingui.TestRunner junit.samples.AllTests</DIV></LI></UL>
<P></P>
<P><STRONG>3、Junit架构</STRONG><BR>　　下面以Money这个类为例进行说明。 
<DIV class=code>public class Money {<BR>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;int&nbsp;fAmount;//余额<BR>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;String&nbsp;fCurrency;//货币类型 
<P></P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Money(int&nbsp;amount,&nbsp;String&nbsp;currency)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fAmount=&nbsp;amount;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fCurrency=&nbsp;currency;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;int&nbsp;amount()&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;fAmount;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;String&nbsp;currency()&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;fCurrency;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Money&nbsp;add(Money&nbsp;m)&nbsp;{//加钱<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;Money(amount()+m.amount(),&nbsp;currency());<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;boolean&nbsp;equals(Object&nbsp;anObject)&nbsp;{//判断钱数是否相等<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(anObject&nbsp;instanceof&nbsp;Money)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Money&nbsp;aMoney=&nbsp;(Money)anObject;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;aMoney.currency().equals(currency())<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;&amp;&nbsp;amount()&nbsp;==&nbsp;aMoney.amount();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<BR>}</P></DIV><BR>　　Junit本身是围绕着两个<ACRONYM title="design pattern">设计模式</ACRONYM>来设计的：<ACRONYM title="command pattern">命令模式</ACRONYM>和<ACRONYM title="composite pattern">集成模式</ACRONYM>.<BR>
<UL>
<LI>命令模式<BR>　　利用TestCase定义一个子类，在这个子类中生成一个被测试的对象，编写代码检测某个<ACONYM title=method>方法</ACRONYM>被调用后对象的状态与预期的状态是否一致，进而<ACRONYM title=assert>断言</ACRONYM>程序代码有没有bug。<BR>　　当这个子类要测试不只一个<ACRONYM title=method>方法</ACRONYM>的实现代码时，可以先建立<ACRONYM title=fixture>测试基础</ACRONYM>，让这些测试在同一个基础上运行，一方面可以减少每个测试的初始化，而且可以测试这些不同方法之间的联系。<BR>　　例如，我们要测试Money的Add方法，可以如下: 
<DIV class=code>public&nbsp;class&nbsp;MoneyTest&nbsp;extends&nbsp;TestCase&nbsp;{&nbsp;//<INS>TestCase的子类</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;testAdd()&nbsp;{ //<INS>把测试代码放在testAdd中</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Money&nbsp;m12CHF=&nbsp;new&nbsp;Money(12,&nbsp;"CHF");&nbsp;&nbsp;//<INS>本行和下一行进行一些初始化</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Money&nbsp;m14CHF=&nbsp;new&nbsp;Money(14,&nbsp;"CHF");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Money&nbsp;expected=&nbsp;new&nbsp;Money(26,&nbsp;"CHF");//<INS>预期的结果</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Money&nbsp;result=&nbsp;m12CHF.add(m14CHF);&nbsp;&nbsp;&nbsp;&nbsp;//<INS>运行被测试的方法</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertTrue(expected.equals(result));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//<INS>判断运行结果是否与预期的相同</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}</DIV><BR>　　如果测试一下equals方法，用类似的代码，如下： 
<DIV class=code>public&nbsp;class&nbsp;MoneyTest&nbsp;extends&nbsp;TestCase&nbsp;{&nbsp;//<INS>TestCase的子类</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;testEquals()&nbsp;{&nbsp;//<INS>把测试代码放在testEquals中</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Money&nbsp;m12CHF=&nbsp;new&nbsp;Money(12,&nbsp;"CHF");&nbsp;//<INS>本行和下一行进行一些初始化</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Money&nbsp;m14CHF=&nbsp;new&nbsp;Money(14,&nbsp;"CHF"); 
<P></P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertTrue(!m12CHF.equals(null));//<INS>进行不同情况的测试</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertEquals(m12CHF,&nbsp;m12CHF);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertEquals(m12CHF,&nbsp;new&nbsp;Money(12,&nbsp;"CHF"));&nbsp;//&nbsp;(1)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertTrue(!m12CHF.equals(m14CHF));<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}</P></DIV><BR>　　当要同时进行测试Add和equals方法时，可以将它们的各自的初始化工作，合并到一起进行，形成测试基础,用setUp初始化，用tearDown清除。如下： 
<DIV class=code>public&nbsp;class&nbsp;MoneyTest&nbsp;extends&nbsp;TestCase&nbsp;{//<INS>TestCase的子类</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Money&nbsp;f12CHF;//<INS>提取公用的对象</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Money&nbsp;f14CHF;&nbsp;&nbsp;&nbsp; 
<P></P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;void&nbsp;setUp()&nbsp;{//<INS>初始化公用对象</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f12CHF=&nbsp;new&nbsp;Money(12,&nbsp;"CHF");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f14CHF=&nbsp;new&nbsp;Money(14,&nbsp;"CHF");<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;testEquals()&nbsp;{//测试equals方法的正确性<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertTrue(!f12CHF.equals(null));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertEquals(f12CHF,&nbsp;f12CHF);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertEquals(f12CHF,&nbsp;new&nbsp;Money(12,&nbsp;"CHF"));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertTrue(!f12CHF.equals(f14CHF));<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;testSimpleAdd()&nbsp;{//测试add方法的正确性<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Money&nbsp;expected=&nbsp;new&nbsp;Money(26,&nbsp;"CHF");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Money&nbsp;result=&nbsp;f12CHF.add(f14CHF);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertTrue(expected.equals(result));<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}</P></DIV><BR>　　将以上三个中的任一个TestCase子类代码保存到名为MoneyTest.java的文件里，并在文件首行增加 
<DIV class=code>import junit.framework.*;</DIV>，都是可以运行的。关于Junit运行的问题很有意思，下面单独说明。<BR>　　上面为解释概念“测试基础(fixture)”，引入了两个对两个方法的测试。命令模式与集成模式的本质区别是，前者一次只运行一个测试。<BR>
<LI>集成模式<BR>　　利用TestSuite可以将一个TestCase子类中所有test***()方法包含进来一起运行，还可将TestSuite子类也包含进来，从而行成了一种等级关系。可以把TestSuite视为一个容器，可以盛放TestCase中的test***()方法，它自己也可以嵌套。这种体系架构，非常类似于现实中程序一步步开发一步步集成的现况。<BR>　　对上面的例子，有代码如下： 
<DIV class=code>public&nbsp;class&nbsp;MoneyTest&nbsp;extends&nbsp;TestCase&nbsp;{//TestCase的子类<BR>&nbsp;&nbsp;&nbsp;&nbsp;....<BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;Test&nbsp;suite()&nbsp;{//<INS>静态Test</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TestSuite&nbsp;suite=&nbsp;new&nbsp;TestSuite();//<INS>生成一个TestSuite</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;suite.addTest(new&nbsp;MoneyTest("testEquals"));&nbsp;//<INS>加入测试方法</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;suite.addTest(new&nbsp;MoneyTest("testSimpleAdd"));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;suite;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}</DIV><BR>　　从Junit2.0开始，有列简捷的方法: 
<DIV class=code>public&nbsp;class&nbsp;MoneyTest&nbsp;extends&nbsp;TestCase&nbsp;{//TestCase的子类<BR>&nbsp;&nbsp;&nbsp;&nbsp;....<BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;Test&nbsp;suite()&nbsp;{<INS>静态Test</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;TestSuite(MoneyTest.class);&nbsp;//<INS>以类为参数</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}</DIV><BR>　　TestSuite见嵌套的例子，在后面应用案例中有。<BR>　　</LI></UL>
<P></P>
<P><STRONG>4、测试代码的运行</STRONG><BR>　　先说最常用的集成模式。<BR>　　测试代码写好以后，可以相应的类中写main方法，用java命令直接运行；也可以不写main方法，用Junit提供的运行器运行。Junit提供了textui,awtui和swingui三种运行器。<BR>　　以前面第2步中的AllTests运行为例，可有四种： 
<DIV class=code>java junit.textui.TestRunner junit.samples.AllTests<BR>java junit.awtui.TestRunner junit.samples.AllTests<BR>java junit.swingui.TestRunner junit.samples.AllTests<BR>java junit.samples.AllTests</DIV><BR>　　main方法中一般也都是简单地用Runner调用suite()，当没有main时，TestRunner自己以运行的类为参数生成了一个TestSuite.<BR>　　<BR>　　对于命令模式的运行，有两种方法。<BR>
<UL>
<LI>静态方法<BR>
<DIV class=code>TestCase test= new MoneyTest("simple add") {<BR>public void runTest() {<BR>testSimpleAdd();<BR>}<BR>};</DIV><BR>
<LI>动态方法<BR>
<DIV class=code>TestCase test= new MoneyTest("testSimpleAdd");</DIV></LI></UL><BR>　　我试了一下，<DEL>好象有问题，哪位朋友成功了，请指点我一下。</DEL>确实可以。<BR>
<DIV class=code>import&nbsp;junit.framework.*; 
<P></P>
<P>public&nbsp;class&nbsp;MoneyTest&nbsp;extends&nbsp;TestCase&nbsp;{//<INS>TestCase的子类</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Money&nbsp;f12CHF;//<INS>提取公用的对象</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Money&nbsp;f14CHF;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;MoneyTest(String&nbsp;name){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super(name);<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;void&nbsp;setUp()&nbsp;{//<INS>初始化公用对象</INS><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f12CHF=&nbsp;new&nbsp;Money(12,&nbsp;"CHF");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f14CHF=&nbsp;new&nbsp;Money(14,&nbsp;"CHF");<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;testEquals()&nbsp;{//测试equals方法的正确性<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertTrue(!f12CHF.equals(null));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertEquals(f12CHF,&nbsp;f12CHF);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertEquals(f12CHF,&nbsp;new&nbsp;Money(12,&nbsp;"CHF"));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertTrue(!f12CHF.equals(f14CHF));<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;testAdd()&nbsp;{//测试add方法的正确性<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Money&nbsp;expected=&nbsp;new&nbsp;Money(26,&nbsp;"CHF");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Money&nbsp;result=&nbsp;f12CHF.add(f14CHF);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertTrue(expected.equals(result));<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>//&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{<BR>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TestCase&nbsp;test=new&nbsp;MoneyTest("simple&nbsp;add")&nbsp;{<BR>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;runTest()&nbsp;{<BR>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;testAdd();<BR>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<BR>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junit.textui.TestRunner.run(test);<BR>//&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TestCase&nbsp;test=new&nbsp;MoneyTest("testAdd");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junit.textui.TestRunner.run(test);<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}</P></DIV><BR>再给一个静态方法用集成测试的例子： 
<DIV class=code>public&nbsp;static&nbsp;Test&nbsp;suite()&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;TestSuite&nbsp;suite=&nbsp;new&nbsp;TestSuite();<BR>&nbsp;&nbsp;&nbsp;&nbsp;suite.addTest(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;testCar("getWheels")&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;void&nbsp;runTest()&nbsp;{&nbsp;testGetWheels();&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;); 
<P></P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;suite.addTest(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;testCar("getSeats")&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;void&nbsp;runTest()&nbsp;{&nbsp;testGetSeats();&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;);<BR>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;suite;<BR>}</P></DIV>
<P></P>
<P><STRONG>5、应用案例</STRONG><BR>
<OL>
<LI>Junit Primer例程，运行如下： 
<DIV class=code>java com.hedong.JunitLearning.Primer.ShoppingCartTest</DIV><BR>
<LI>Ant+Junit+Mailto实现自动编译、调试并发送结果的build.xml<BR>
<LI>JUnit实施,写得很棒，理解也深刻。例程运行如下： 
<DIV class=code>java com.hedong.JunitLearning.car.testCarNoJunit<BR>java junit.swingui.TestRunner com.hedong.JunitLearning.car.testCar</DIV><BR>
<LI>Junit与log4j结合，阿菜的例程运行： 
<DIV class=code>cd acai<BR>ant junit</DIV><BR>
<LI><BR>
<LI><BR>
<LI><BR>
<LI><BR></LI></OL><BR><STRONG>6、一些问题</STRONG><BR>　　有人在实践基础上总结出一些非常有价值的使用技巧，我没有经过一一“测试”，暂列在此。<BR>
<OL>
<LI>不要用TestCase的构造函数初始化Fixture，而要用setUp()和tearDown()方法。<BR>
<LI>不要依赖或假定测试运行的顺序，因为JUnit利用Vector保存测试方法。所以不同的平台会按不同的顺序从Vector中取出测试方法。<INS>不知3.8中是不是还是如此，不过它提供的例子有一个是指定用VectorSuite的，如果不指定呢？</INS><BR>
<LI>避免编写有副作用的TestCase。例如：如果随后的测试依赖于某些特定的交易数据，就不要提交交易数据。简单的回滚就可以了。<BR>
<LI>当继承一个测试类时，记得调用父类的setUp()和tearDown()方法。<BR>
<LI>将测试代码和工作代码放在一起，一边同步编译和更新。（使用Ant中有支持junit的task.）<BR>
<LI>测试类和测试方法应该有一致的命名方案。如在工作类名前加上test从而形成测试类名。<BR>
<LI>确保测试与时间无关，不要依赖使用过期的数据进行测试。导致在随后的维护过程中很难重现测试。<BR>
<LI>如果你编写的软件面向国际市场，编写测试时要考虑国际化的因素。不要仅用母语的Locale进行测试。<BR>
<LI>尽可能地利用JUnit提供地assert/fail方法以及异常处理的方法，可以使代码更为简洁。<BR>
<LI>测试要尽可能地小，执行速度快。<BR>
<LI>把测试程序建立在与被测对象相同的包中<BR>
<LI>在你的原始代码目录中避免测试码出现，可在一个源码镜像目录中放测试码<BR>
<LI>在自己的应用程序包中包含一个TestSuite测试类<BR>
<LI><BR></LI></OL><BR><BR><STRONG>7、相关资源下载</STRONG><BR>以下jar包，我只是做了打包、编译和调试的工作，供下载学习之用，相关的权利属于原作者。<BR>
<OL>
<LI><A href="http://www.infomall.cn/cgi-bin/mallgate/20031008/http://hedong.3322.org/archives/docs/prim.jar">可运行例程.jar</A><BR>
<LI><A href="http://www.infomall.cn/cgi-bin/mallgate/20031008/http://hedong.3322.org/archives/docs/ant%20junit%20mailto.build.xml">Build.xml</A><BR>
<LI><A href="http://www.infomall.cn/cgi-bin/mallgate/20031008/http://hedong.3322.org/archives/docs/acai.zip">阿菜的例程</A><BR>
<LI><INS><A href="http://www.infomall.cn/cgi-bin/mallgate/20031008/http://hedong.3322.org/archives/docs/JavaX-14.zip">Junit API 汉译</A>(pdf)</INS><BR></LI></OL>
<P></P>
<P><STRONG>8、未完成的任务</STRONG><BR>
<OL>
<LI>httpunit<BR>
<LI>cactus<BR>
<LI>将Junit用链接池测试<BR></LI></OL><BR>主要参考文献：<BR>
<OL><BR>
<LI>JUnit入門<BR>http://www.dotspace.twmail.org/Test/JUnit_Primer.htm<BR>
<LI>怎样使用Junit Framework进行单元测试的编写<BR>http://www.chinaunix.net/bbsjh/14/546.html<BR>
<LI>Ant+Junit+Log4J+CVS进行XP模式开发的建立<BR>http://ejb.cn/modules/tutorials/printpage.php?tid=4<BR>
<LI>用HttpUnit测试Web应用程序<BR>http://www.zdnet.com.cn/developer/code/story/0,2000081534,39033726,00.htm<BR>
<LI>有没有用过Cactus的，Web层的测试是Cactus还是JUnit？<BR>http://www.jdon.com/jive/thread.jsp?forum=16&amp;thread=9156<BR>
<LI>Ant+junit的测试自动化 biggie（原作）<BR>http://www.csdn.net/Develop/article/19%5C19748.shtm<BR>
<LI>JUnit实施<BR>http://www.neweasier.com/article/2002-08-07/1028723459.html<BR>
<LI>JUnitTest Infected: Programmers Love Writing Tests<BR>http://junit.sourceforge.net/doc/testinfected/testing.htm<BR>
<LI>JUnit Cookbook<BR>http://junit.sourceforge.net/doc/cookbook/cookbook.htm<BR>
<LI>JUnit Primer<BR>http://www.itu.dk/~lthorup/JUnitPrimer.html<BR>
<LI>IBM DevelopWorks<BR><A href="http://www-106.ibm.com/search/searchResults.jsp?query=junit&amp;searchScope=dW&amp;searchType=1&amp;searchSite=dWChina&amp;pageLang=zh&amp;langEncoding=gb2312&amp;Search.x=0&amp;Search.y=0&amp;Search=Search">http://www-106.ibm.com/search/searchResults.jsp?query=junit&amp;searchScope=dW&amp;searchType=1&amp;searchSite=dWChina&amp;pageLang=zh&amp;langEncoding=gb2312&amp;Search.x=0&amp;Search.y=0&amp;Search=Search</A><BR></LI></OL><img src ="http://www.blogjava.net/jackybu/aggbug/2898.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-04-07 10:44 <a href="http://www.blogjava.net/jackybu/articles/2898.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>junit使用简明手册  </title><link>http://www.blogjava.net/jackybu/articles/2897.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Thu, 07 Apr 2005 02:43:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/2897.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/2897.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/2897.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/2897.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/2897.html</trackback:ping><description><![CDATA[用XP进行开发的过程，unit test是必不可少的环节。作为unit test，junit是首选的工具。本文从使用目的、如何使用、以及使用中需要考虑的问题，简略描述了junit的基本用法。<BR><BR>使用目的<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junit是java中书写unit test的framework，目前一些流行的unit test工具大都都是在junit上扩展而来的。目前它的版本是junit3.8.1，可以从www.junit.org上下载。<BR><BR>用法<BR>1. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;基本使用步骤，Junit的使用非常简单，它的基本使用步骤：<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;创建，从junit.framework.TestCase派生unit test需要的test case<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;书写测试方法，提供类似于如下函数签名的测试方法：<BR><BR>public void testXXXXX();<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;编译，书写完test case后，编译所写的test case类<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;运行，启动junit test runner，来运行这个test case。<BR><BR>Junit提供了2个基本的test runner：字符界面和图形界面。启动命令分别如下：<BR><BR>a 图形界面：<BR><BR>java junit.swingui.TestRunner XXXXX<BR><BR>b 字符界面：<BR><BR>java junit.textui.TestRunner XXXXX<BR><BR>2. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用例子：<BR><BR>import junit.frmework.TestCase;<BR><BR>public class TestSample extends TestCaset{<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void testMethod1(){<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertTrue( true);<BR><BR>}<BR><BR>}<BR><BR>3. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setUp与tearDown，这两个函数是junit framework中提供初始化和反初始化每个测试方法的。setUp在每个测试方法调用前被调用，负责初始化测试方法所需要的测试环境；tearDown在每个测试方法被调用之后被调用，负责撤销测试环境。它们与测试方法的关系可以描述如下：<BR><BR><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;测试开始 -&gt; setUp -&gt; testXXXX -&gt; tearDown -&gt;测试结束<BR><BR><BR><BR><BR>4. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用例子：<BR><BR>import junit.frmework.TestCase;<BR><BR>public class TestSample extends TestCaset{<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protected void setUp(){<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//初始化……<BR><BR>}<BR><BR><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void testMethod1(){<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertTrue( true);<BR><BR>}<BR><BR><BR><BR>potected void tearDown(){<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//撤销初始化……<BR><BR>}<BR><BR>}<BR><BR>5. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;区分fail、exception。<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fail，期望出现的错误。产生原因：assert函数出错（如assertFalse(true)）；fail函数产生（如fail(……)）。<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exception，不期望出现的错误，属于unit test程序运行时抛出的异常。它和普通代码运行过程中抛出的runtime异常属于一种类型。<BR><BR>对于assert、fail等函数请参见junit的javadoc。<BR><BR>6. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用例子：<BR><BR>import junit.frmework.TestCase;<BR><BR>public class TestSample extends TestCaset{<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protected void setUp(){<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//初始化……<BR><BR>}<BR><BR><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void testMethod1(){<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;……<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try{<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;boolean b= ……<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertTrue( b);<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new Exception( “This is a test.”);<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fail( “Unable point.”); &nbsp;&nbsp;&nbsp;&nbsp;//不可能到达<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}catch(Exception e){<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fail( “Yes, I catch u”); //应该到达点<BR><BR>}<BR><BR>……<BR><BR>}<BR><BR><BR><BR>potected void tearDown(){<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//撤销初始化……<BR><BR>}<BR><BR>}<BR><BR>7. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;组装TestSuite，运行更多的test。在junit中，Test、TestCase和TestSuite三者组成了composiste pattern。通过组装自己的TestSuite，可以完成对添加到这个TestSuite中的所有的TestCase的调用。而且这些定义的TestSuite还可以组装成更大的TestSuite，这样同时也方便了对于不断增加的TestCase的管理和维护。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;它的另一个好处就是，可以从这个TestCase树的任意一个节点（TestSuite或TestCase）开始调用，来完成这个节点以下的所有TestCase的调用。提高了unit test的灵活性。<BR><BR>8. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用例子：<BR><BR>import junit.framework.Test;<BR><BR>import junit.framework.TestSuite;<BR><BR>public class TestAll{<BR><BR>public class TestAll{<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//定义一个suite，对于junit的作用可以视为类似于java应用程序的main。<BR><BR>&nbsp;&nbsp;&nbsp;public static Test suite(){<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TestSuite suite = new TestSuite("Running all tests.");<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;suite.addTestSuite( TestCase1.class);<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;suite.addTestSuite( TestCase2.class);<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return suite;<BR><BR>&nbsp;&nbsp;&nbsp;}<BR><BR>}<BR><BR>运行同运行单独的一个TestCase是一样的，参见step 1 “运行”。<BR><BR>9. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用Ant junit task。我们除了使用java来直接运行junit之外，我们还可以使用junit提供的junit task与ant结合来运行。涉及的几个主要的ant task如下：<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;junit&gt;，定义一个junit task<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;batchtest&gt;，位于&lt;junit&gt;中，运行多个TestCase<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;test&gt;，位于&lt;junit&gt;中，运行单个TestCase<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;formatter&gt;，位于&lt;junit&gt;中，定义一个测试结果输出格式<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;junitreport&gt;，定义一个junitreport task<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;report&gt;，位于&lt;junitreport&gt;中，输出一个junit report<BR><BR>具体的语法请参见相关文档。<BR><BR>10. &nbsp;&nbsp;使用例子：<BR><BR>&lt;junit printsummary="yes" haltonfailure="no"&gt;<BR><BR>&nbsp;&nbsp;&nbsp;&lt;classpath&gt;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;path refid="classpath"/&gt;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;pathelement location="${dist.junit}"/&gt;<BR><BR>&nbsp;&nbsp;&nbsp;&lt;/classpath&gt;<BR><BR>&nbsp;&nbsp;&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&lt;formatter type="brief" usefile="false"/&gt;<BR><BR>&nbsp;&nbsp;&nbsp;&lt;formatter type="xml"/&gt;<BR><BR><BR><BR>&nbsp;&nbsp;&nbsp;&lt;batchtest todir="${doc.junitReport}"&gt;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;fileset dir="${dist.junit}" includes="**/*Test.class" /&gt;<BR><BR>&nbsp;&nbsp;&nbsp;&lt;/batchtest&gt;<BR><BR>&lt;/junit&gt;<BR><BR><BR><BR>&lt;junitreport todir="${doc.junitReport}"&gt;<BR><BR>&nbsp;&nbsp;&nbsp;&lt;fileset dir="${doc.junitReport}"&gt;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="TEST*-*.xml"/&gt;<BR><BR>&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;<BR><BR>&nbsp;&nbsp;&nbsp;&lt;report format="frames" styledir="${junit.styleDir}" todir="${doc.junitReport}"/&gt;<BR><BR>&lt;/junitreport&gt;<BR><BR>检查表<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junit的使用并不很难，然而要书写一个好的TestCase却并非易事。一个不好的TestCase往往是既浪费了时间，也起不了实际的作用。相反，一个好的TestCase，不仅可以很好的指出代码中存在的问题，而且也可以作为代码更准确的文档，同时还在持续集成的过程中起非常重要的作用。在此给出书写TestCase时需要注意的几点：<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;测试的独立性：一次只测试一个对象，方便定位出错的位置。这有2层意思：一个TestCase，只测试一个对象；一个TestMethod，只测试这个对象中的一个方法。<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;给测试方法一个合适的名字。<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在assert函数中给出失败的原因，如：assertTrue( “… should be true”, &nbsp;……)，方便查错。在这个例子中，如果无法通过assertTrue，那么给出的消息将被显示。在junit中每个assert函数都有第一个参数是出错时显示消息的函数原型。<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;测试所有可能引起失败的地方，如：一个类中频繁改动的函数。对于那些仅仅只含有getter/setter的类，如果是由IDE（如Eclipse）产生的，则可不测；如果是人工写，那么最好测试一下。<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在setUp和tearDown中的代码不应该是与测试方法相关的，而应该是全局相关的。如针对与测试方法A和B，在setUp和tearDown中的代码应该是A和B都需要的代码。<BR><BR>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;测试代码的组织：相同的包，不同的目录。这样，测试代码可以访问被测试类的protected变量/方法，方便测试代码的编写。放在不同的目录，则方便了测试代码的管理以及代码的打包和发布。一个例子如下：<BR><BR>src &nbsp;&nbsp;&lt;=源代码根目录<BR><BR><IMG style="VERTICAL-ALIGN: middle" height=19 src="http://www.uml.org.cn/j2ee/images/016.gif" width=19 border=0>-com<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;<IMG style="VERTICAL-ALIGN: middle" height=19 src="http://www.uml.org.cn/j2ee/images/016.gif" width=19 border=0>-mod1<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<IMG style="VERTICAL-ALIGN: middle" height=19 src="http://www.uml.org.cn/j2ee/images/016.gif" width=19 border=0>-class1<BR><BR>junit &nbsp;&nbsp;&lt;=测试代码根目录<BR><BR><IMG style="VERTICAL-ALIGN: middle" height=19 src="http://www.uml.org.cn/j2ee/images/016.gif" width=19 border=0>-com<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;<IMG style="VERTICAL-ALIGN: middle" height=19 src="http://www.uml.org.cn/j2ee/images/016.gif" width=19 border=0>-mod1<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<IMG style="VERTICAL-ALIGN: middle" height=19 src="http://www.uml.org.cn/j2ee/images/016.gif" width=19 border=0>-class1 <BR><img src ="http://www.blogjava.net/jackybu/aggbug/2897.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-04-07 10:43 <a href="http://www.blogjava.net/jackybu/articles/2897.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[软件测试]JUnit和单元测试入门简介</title><link>http://www.blogjava.net/jackybu/articles/2896.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Thu, 07 Apr 2005 02:42:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/2896.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/2896.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/2896.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/2896.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/2896.html</trackback:ping><description><![CDATA[1、几个相关的概念 <BR><BR>白盒测试——把测试对象看作一个打开的盒子，程序内部的逻辑结构和其他信息对测试人员是公开的。 <BR><BR>回归测试——软件或环境的修复或更正后的“再测试”，自动测试工具对这类测试尤其有用。 <BR><BR>单元测试——是最小粒度的测试，以测试某个功能或代码块。一般由程序员来做，因为它需要知道内部程序设计和编码的细节。 <BR><BR>JUnit ——是一个开发源代码的Java测试框架，用于编写和运行可重复的测试。他是用于单元测试框架体系xUnit的一个实例（用于java语言）。主要用于白盒测试，回归测试。 <BR><BR><BR><BR>2、单元测试概述 <BR><BR>2.1、单元测试的好处 <BR><BR>A、提高开发速度——测试是以自动化方式执行的，提升了测试代码的执行效率。 <BR><BR>B、提高软件代码质量——它使用小版本发布至集成，便于实现人员除错。同时引入重构概念，让代码更干净和富有弹性。 <BR><BR>C、提升系统的可信赖度——它是回归测试的一种。支持修复或更正后的“再测试”，可确保代码的正确性。 <BR><BR>2．2、单元测试的针对对象 <BR><BR>A、面向过程的软件开发针对过程。 <BR><BR>B、面向对象的软件开发针对对象。 <BR><BR>C、可以做类测试，功能测试，接口测试（最常用于测试类中的方法）。 <BR><BR>2.3、单元测试工具和框架 <BR><BR>目前的最流行的单元测试工具是xUnit系列框架，常用的根据语言不同分为JUnit（java），CppUnit（C++），DUnit （Delphi ），NUnit（.net），PhpUnit（Php ）等等。该测试框架的第一个和最杰出的应用就是由Erich Gamma （《设计模式》的作者）和Kent Beck（XP（Extreme Programming）的创始人 ）提供的开放源代码的JUnit。 <BR><BR><BR><BR>3.Junit入门简介 <BR><BR>3.1、JUnit的好处和JUnit单元测试编写原则 <BR><BR>好处： <BR><BR>A、可以使测试代码与产品代码分开。 <BR><BR>B、针对某一个类的测试代码通过较少的改动便可以应用于另一个类的测试。 <BR><BR>C、易于集成到测试人员的构建过程中，JUnit和Ant的结合可以实施增量开发。 <BR><BR>D、JUnit是公开源代码的，可以进行二次开发。 <BR><BR>C、可以方便地对JUnit进行扩展。 <BR><BR>编写原则： <BR><BR>A、是简化测试的编写，这种简化包括测试框架的学习和实际测试单元的编写。 <BR><BR>B、是使测试单元保持持久性。 <BR><BR>C、是可以利用既有的测试来编写相关的测试。 <BR><BR>3.2、JUnit的特征 <BR><BR>A、使用断言方法判断期望值和实际值差异，返回Boolean值。 <BR><BR>B、测试驱动设备使用共同的初始化变量或者实例。 <BR><BR>C、测试包结构便于组织和集成运行。 <BR><BR>D、支持图型交互模式和文本交互模式。 <BR><BR>3.3、JUnit框架组成 <BR><BR>A、对测试目标进行测试的方法与过程集合，可称为测试用例(TestCase)。 <BR><BR>B、测试用例的集合，可容纳多个测试用例(TestCase)，将其称作测试包(TestSuite)。 <BR><BR>C、测试结果的描述与记录。(TestResult) 。 <BR><BR>D、测试过程中的事件监听者(TestListener)。 <BR><BR>E、每一个测试方法所发生的与预期不一致状况的描述，称其测试失败元素(TestFailure) <BR><BR>F、JUnit Framework中的出错异常（AssertionFailedError）。 <BR><BR>JUnit框架是一个典型的Composite模式：TestSuite可以容纳任何派生自Test的对象；当调用TestSuite对象的run()方法是，会遍历自己容纳的对象，逐个调用它们的run()方法。（可参考《程序员》2003-6期）。 <BR><BR>3.4、JUnit的安装和配置 <BR><BR>JUnit安装步骤分解： <BR><BR>在http://download.sourceforge.net/junit/中下载JUnit包并将Junit压缩包解压到一个物理目录中（例如C：＼Junit3.8.1）。 <BR>记录Junit.jar文件所在目录名（例如C：＼Junit3.8.1\Junit.jar）。 <BR>进入操作系统（以Windows2000操作系统为准），按照次序点击“开始　设置　控制面板”。 <BR>在控制面板选项中选择“系统”，点击“环境变量”，在“系统变量”的“变量”列表框中选择“CLASS-PATH”关键字（不区分大小写），如果该关键字不存在则添加。 <BR>双击“CLASS-PATH”关键字添加字符串“C:＼Junit3.8.1\Junti.jar”(注意，如果已有别的字符串请在该字符串的字符结尾加上分号“；”)，这样确定修改后Junit就可以在集成环境中应用了。 <BR>对于IDE环境，对于需要用到的JUnit的项目增加到lib中，其设置不同的IDE有不同的设置 。 <BR>3.5、JUnit中常用的接口和类 <BR><BR>Test接口——运行测试和收集测试结果 <BR><BR>Test接口使用了Composite设计模式，是单独测试用例 （TestCase），聚合测试模式（TestSuite）及测试扩展（TestDecorator）的共同接口。 <BR>它的public int countTestCases（）方法，它来统计这次测试有多少个TestCase，另外一个方法就是public void　run（ TestResult ），TestResult是实例接受测试结果， run方法执行本次测试。 <BR>TestCase抽象类——定义测试中固定方法 <BR><BR>TestCase是Test接口的抽象实现，（不能被实例化，只能被继承）其构造函数TestCase(string name)根据输入的测试名称name创建一个测试实例。由于每一个TestCase在创建时都要有一个名称，若某测试失败了，便可识别出是哪个测试失败。 <BR>TestCase类中包含的setUp()、tearDown()方法。setUp()方法集中初始化测试所需的所有变量和实例，并且在依次调用测试类中的每个测试方法之前再次执行setUp()方法。tearDown()方法则是在每个测试方法之后，释放测试程序方法中引用的变量和实例。 <BR>开发人员编写测试用例时，只需继承TestCase，来完成run方法即可，然后JUnit获得测试用例，执行它的run方法，把测试结果记录在TestResult之中。 <BR>Assert静态类——一系列断言方法的集合 <BR><BR>Assert包含了一组静态的测试方法，用于期望值和实际值比对是否正确，即测试失败，Assert类就会抛出一个AssertionFailedError异常，JUnit测试框架将这种错误归入Failes并加以记录，同时标志为未通过测试。如果该类方法中指定一个String类型的传参则该参数将被做为AssertionFailedError异常的标识信息，告诉测试人员改异常的详细信息。 <BR>JUnit 提供了6大类31组断言方法，包括基础断言、数字断言、字符断言、布尔断言、对象断言。 <BR>其中assertEquals（Object expcted,Object actual)内部逻辑判断使用equals()方法，这表明断言两个实例的内部哈希值是否相等时，最好使用该方法对相应类实例的值进行比较。而assertSame（Object expected,Object actual）内部逻辑判断使用了Java运算符“==”，这表明该断言判断两个实例是否来自于同一个引用（Reference），最好使用该方法对不同类的实例的值进行比对。asserEquals(String message,String expected,String actual)该方法对两个字符串进行逻辑比对，如果不匹配则显示着两个字符串有差异的地方。ComparisonFailure类提供两个字符串的比对，不匹配则给出详细的差异字符。 <BR>TestSuite测试包类——多个测试的组合 <BR><BR>TestSuite类负责组装多个Test Cases。待测得类中可能包括了对被测类的多个测试，而TestSuit负责收集这些测试，使我们可以在一个测试中，完成全部的对被测类的多个测试。 <BR>TestSuite类实现了Test接口，且可以包含其它的TestSuites。它可以处理加入Test时的所有抛出的异常。 <BR>TestSuite处理测试用例有6个规约（否则会被拒绝执行测试） <BR>A 测试用例必须是公有类（Public） <BR><BR>B 测试用例必须继承与TestCase类 <BR><BR>C 测试用例的测试方法必须是公有的（ Public ） <BR><BR>D 测试用例的测试方法必须被声明为Void <BR><BR>E 测试用例中测试方法的前置名词必须是test <BR><BR>F 测试用例中测试方法误任何传递参数 <BR><BR>n TestResult结果类和其它类与接口 <BR><BR>TestResult结果类集合了任意测试累加结果，通过TestResult实例传递个每个测试的Run（）方法。TestResult在执行TestCase是如果失败会异常抛出 <BR>TestListener接口是个事件监听规约，可供TestRunner类使用。它通知listener的对象相关事件，方法包括测试开始startTest(Test test)，测试结束endTest(Test test),错误，增加异常addError(Test test,Throwable t)和增加失败addFailure(Test test,AssertionFailedError t) <BR>TestFailure失败类是个“失败”状况的收集类，解释每次测试执行过程中出现的异常情况。其toString()方法返回“失败”状况的简要描述 <BR><BR><BR>3.6、JUnit一个实例 <BR><BR>在控制台中简单的范例如下： <BR>1、写个待测试的Triangle类，创建一个TestCase的子类ExampleTest: <BR>2、 ExampleTest中写一个或多个测试方法，断言期望的结果(注意：以test作为待测试的方法的开头，这样这些方法可以被自动找到并被测试) <BR>3、 ExampleTest中写一个suite()方法，它会使用反射动态的创建一个包含所有的testXxxx方法的测试套件： <BR>4、 ExampleTest可以写setUp()、tearDown()方法，以便于在测试时初始化或销毁测试所需的所有变量和实例。（不是必须的） <BR><BR>5、写一个main()方法以文本运行器或其它GUI的方式方便的运行测试 <BR><BR>6、编译ExampleTest，执行测试。 <BR><BR>3.7、Eclipse中JUnit的使用 <BR><BR>Eclipse自带了一个JUnit的插件，不用安装就可以在你的项目中开始测试相关的类，并且可以调试你的测试用例和被测试类。 <BR><BR>使用步骤如下： <BR><BR>1、新建一个测试用例，点击“File-&gt;New-&gt;Other…菜单项，在弹出的“New”对话框中选择”Java-&gt;JUnit”,下的TestCase 或TestSuite，就进入“New JUnit TestCase”对话框 <BR><BR>2、在“New JUnit TestCase”对话框填写相应的栏目，主要有Name（测试用例名），SuperClass（测试的超类一般是默认的junit.framework.TestCase），Class Under Test（被测试的类），Source Folder（测试用例保存的目录），Package（测试用例包名），及是否自动生成main,setUp,tearDown方法。 <BR><BR>3、如果点击下面的”Next&gt;”按钮，你还可以直接勾选你想测试的被测试类的方法，Eclipse将自动生成与被选方法相应的测试方法，点击“Fishish”按钮后一个测试用例就创建好了。 <BR><BR>4、编写完成你的测试用例后，点击“Run”按钮就可以看到运行结果了。 <BR><BR>3.8、JUnit的扩展应用 <BR><BR>以下罗列了些JUnit的扩展应用： <BR><BR>JUnit + HttpUnit=WEB功能测试工具 <BR>JUnit + hansel =代码覆盖测试工具 <BR>JUnit + abbot =界面自动回放测试工具 <BR>JUnit + dbunit =数据库测试工具 <BR>JUnit + junitperf=性能测试工具 <BR><BR>3.9、一些使用JUnit经验 <BR><BR>不要用TestCase的构造函数初始化，而要用setUp()和tearDown()方法。 <BR>不要依赖或假定测试运行的顺序，因为JUnit利用Vector保存测试方法。所以不同的平台会按不同的顺序从Vector中取出测试方法。 <BR>避免编写有副作用的TestCase。例如：如果随后的测试依赖于某些特定的交易数据，就不要提交交易数据。简单的回滚就可以了。 <BR>当继承一个测试类时，记得调用父类的setUp()和tearDown()方法。 <BR>将测试代码和工作代码放在一起，一边同步编译和更新。 <BR>测试类和测试方法应该有一致的命名方案。如在工作类名前加上test从而形成测试类名。 <BR>确保测试与时间无关，不要依赖使用过期的数据进行测试。导致在随后的维护过程中很难重现测试。 <BR>如果你编写的软件面向国际市场，编写测试时要考虑国际化的因素。不要仅用母语的Locale进行测试。 <BR>尽可能地利用JUnit提供地assert/fail方法以及异常处理的方法，可以使代码更为简洁。 <BR>测试要尽可能地小，执行速度快。 <BR><BR><BR>参考资料与附件 <BR><BR>1. http:// www.junit.org JUnit官方网站 <BR><BR>2. http://bbs.51cmm.com 的测试论坛 <BR><BR>3. http://www.uml.org.cn 的软件测试专栏 <BR><BR>4. 单元测试 《程序员》 2002年7期 <BR><BR>5. JUnit设计模式分析 《程序员》2003年6期 <BR><BR>6. 《软件测试和JUnit实践》 <BR><BR>7. 附件Triangle.java 一个要测试的类 <BR><BR>8. 附件ExampleTest.java 一个测试用例类 <BR><BR><BR><BR><BR><BR>Triangle.java <BR><BR>/** <BR><BR>* this is Triangle class <BR><BR>* @author liujun <BR><BR>*/ <BR><BR>public class Triangle <BR><BR>{ <BR><BR>//定义三角形的三边 <BR><BR>protected long lborderA = 0; <BR><BR>protected long lborderB = 0; <BR><BR>protected long lborderC = 0; <BR><BR><BR><BR>//构造函数 <BR><BR>public Triangle(long lborderA,long lborderB,long lborderC) <BR><BR>{ <BR><BR>this.lborderA = lborderA; <BR><BR>this.lborderB = lborderB; <BR><BR>this.lborderC = lborderC; <BR><BR>} <BR><BR>/** <BR><BR>* 判断是否是三角形 <BR><BR>* 是返回ture；不是返回false <BR><BR>*/ <BR><BR>public boolean isTriangle(Triangle triangle) <BR><BR>{ <BR><BR>boolean isTrue = false; <BR><BR>//判断边界，大于0小于200，出界返回false <BR><BR>if((triangle.lborderA&gt;0&amp;&amp;triangle.lborderA&lt;200) <BR><BR>&amp;&amp;(triangle.lborderB&gt;0&amp;&amp;triangle.lborderB&lt;200) <BR><BR>&amp;&amp;(triangle.lborderC&gt;0&amp;&amp;triangle.lborderC&lt;200)) <BR><BR>{ <BR><BR>//判断两边之和大于第三边 <BR><BR>if((triangle.lborderA&lt;(triangle.lborderB+triangle.lborderC)) <BR><BR>&amp;&amp;(triangle.lborderB&lt;(triangle.lborderA+triangle.lborderC)) <BR><BR>&amp;&amp;(triangle.lborderC&lt;(triangle.lborderA+triangle.lborderB))) <BR><BR>isTrue = true; <BR><BR>} <BR><BR>return isTrue; <BR><BR>} <BR><BR><BR><BR>/** <BR><BR>* 判断三角形类型 <BR><BR>* 等腰三角形返回字符串“等腰三角形”； <BR><BR>* 等边三角形返回字符串“等边三角形”； <BR><BR>* 其它三角形返回字符串“不等边三角形”； <BR><BR>*/ <BR><BR>public String isType(Triangle triangle) <BR><BR>{ <BR><BR>String strType = ""; <BR><BR>// 判断是否是三角形 <BR><BR>if(this.isTriangle(triangle)) <BR><BR>{ <BR><BR>//判断是否是等边三角形 if(triangle.lborderA==triangle.lborderB&amp;&amp;triangle.lborderB==triangle.lborderC) <BR><BR>strType = "等边三角形"; <BR><BR>//判断是否是不等边三角形 <BR><BR>else if((triangle.lborderA!=triangle.lborderB)&amp;&amp; <BR><BR>(triangle.lborderB!=triangle.lborderC)&amp;&amp; <BR><BR>(triangle.lborderA!=triangle.lborderC)) <BR><BR>strType = "不等边三角形"; <BR><BR>else <BR><BR>strType="等腰三角形"; <BR><BR>} <BR><BR>return strType; <BR><BR>} <BR><BR>} <BR><BR><BR><BR>ExampleTest.java <BR><BR>import junit.framework.*; <BR><BR>/** <BR><BR>* Some tests. <BR><BR>* <BR><BR>*/ <BR><BR>public class ExampleTest extends TestCase { <BR><BR>public Triangle triangle; <BR><BR>//初始化 <BR><BR>protected void setUp() { <BR><BR>triangle=new Triangle(10,2,9); <BR><BR>} <BR><BR><BR><BR>public static Test suite() { <BR><BR>return new TestSuite(ExampleTest.class); <BR><BR>} <BR><BR>//函数isTriangle()的测试用例 <BR><BR>public void testIsTriangle() { <BR><BR>assertTrue(triangle.isTriangle(triangle)); <BR><BR>} <BR><BR>//函数isType()的测试用例 <BR><BR>public void testIsType() <BR><BR>{ <BR><BR>assertEquals("这次测试",triangle.isType(triangle),"不等边三角形"); <BR><BR>} <BR><BR><BR><BR>//执行测试 <BR><BR>public static void main (String[] args) { <BR><BR>//文本方式 <BR><BR>junit.textui.TestRunner.run(suite()); <BR><BR>//Swingui方式 <BR><BR>//junit.swingui.TestRunner.run(suite().getClass()); <BR><BR>//awtui方式 <BR><BR>//junit.awtui.TestRunner.run(suite().getClass()); <BR><BR><BR><BR>} <BR><BR>}<img src ="http://www.blogjava.net/jackybu/aggbug/2896.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-04-07 10:42 <a href="http://www.blogjava.net/jackybu/articles/2896.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>