??xml version="1.0" encoding="utf-8" standalone="yes"?> ~辑 ? ? ? ? ? ? 如果你不能很好地回答q个问题Q那么编写代码——或者测试——完全就是在费旉?/span> 在代码的整个生命期中Q“正”的定义可能?x)不断在变;但是无论如何Q你臛_需要确认代码所做的和你的期望是一致的?/span> 对于许多有大量测试数据的试Q你可能?x)考虑用一个独立的数据文g来存储这些测试数据,然后让单元测试读取该文g?/span> 多注意一下测试数据。经验告诉我们,试数据比代码更有可能是错的Q特别是人工计算的,或者来自原有系l计结果的试数据。因此,当测试数据显C有错误发生的时_(d)你应该在怀疑代码前先对试数据(g)查两三遍?/span> 一个原则是Q对于验证被方法是正确的这件事情,如果某些做法能够使它变得更加Ҏ(gu)Q那么就采纳它吧?/span> 找边界条件是做单元测试中最有h(hun)值的工作之一Q因?/span>bug一般就出现在边界上。一些需要你考虑得条件有?/span> ·完全伪造或者不一致的输入数据Q例如一个名为?/span>!*W:X\&Gi/w~>g/h#WQ@”的文g?/span> ·格式错误的数据,例如没有层域名的电(sh)子邮件地址像fred@foobarq样的?/span> ·控制或者不完整的|?/span>0, 0.0, “?/span>?/span>nullQ?/span> ·一些与意料中的合理值相ȝq的数倹{例如一个h的岁Cؓ(f)10000岁?/span> ·如果要求的是一个不允许出现重复数值的listQ但是传入的是一个存在重复数值的list?/span> ·如果要求的是一个有?/span>listQ但是传入的是一个无序的listQ或者反之。例如,l一个要求排好序的算法传入一个未排序?/span>list——甚至一个反序的list?/span> ·事情到达的次序是错误的,或者碰巧和期望的次序不一致。例如,在未dpȝ之前Q就试打印文档?/span> 一个向导可能的边界条gCORRECT。对于其中的每一条,都应该想惛_是否与存在于被测Ҏ(gu)中的某个条g非常cMQ而当q些条g被违反的Ӟ出现的又是什么情c(din)?/span> ·ConformanceQ一致性)(j)——值是否和预期的一致?/span> ·OrderingQ顺序性)(j)——值是否如应该的那P是有序或者无序的?/span> ·RangeQ区间性)(j)——值是否位于合理的最值和最大g内?/span> ·ReferenceQ依赖性)(j)——代码是否引用了(jin)一些不再代码本w控制范围之内的外部资源?/span> ·ExistenceQ存在性)(j)——值是否存在(例如Q是否是?/span>nullQ非0Q再一个集合中{等Q?/span> ·CardinatityQ基数性)(j)——是否恰好有_的| ·TimeQ相Ҏ(gu)者绝对的旉性)(j)——所有事情的发生是否是有序的Q是否是在正的时刻Q是否恰好及(qing)Ӟ 对于一些方法,我们可以使用反向的逻辑关系来验证它们?/span> 要注意的是:(x)当你同时~写?jin)原?gu)和它的反向测试时Q一?/span>bug可能?x)被在两个函C都出现的错误所掩盖。在可能的情况下Q应该用不同的原理来编写反向测试?/span> 通常而言Q计一个量?x)有一U以上的法。我们可能会(x)Zq行效率或者其他的Ҏ(gu),来选择法。那是我们要在品中使用的;但是在测试用的系l中Q可以用剩下算法中的一个来交叉试l果。当实存在一U经q验证ƈ能完成Q务的法Q只是由于速度太慢或者太不灵z而没有在产品代码中用,q种交叉(g)查的技术将非常有效?/span> 另一U办法就是:(x)使用cLw不同组成部分的数据Qƈ且确信它们能和“合h”?/span> 在真实世界中Q错误L?x)发生?x)盘?x)慢Q网l连U会(x)断开Q电(sh)子邮件会(x)多的像掉q了(jin)黑洞Q而程序会(x)崩溃。你应当能够通过强制引发错误Q来试你的代码是如何处理所有这些真实世界中的问题的?/span> 一个检查v来会(x)很有益处的部分是性能Ҏ(gu),而不是性能本n?/span> 你也?dng)R要一些测试辅助工兗它们嫩构提供对单个试q行计时Q模拟告负在情况之类的功能,比如免费?/span>JUnitPerf?/span>
本文档从Eclipse软g上整理,是列Z(jin)标准的快捷键Q未列出Emacs快捷键?BR>转脓(chung)h明作者和出处?/P>
作用?功能 快捷?BR>全局 查找q替?Ctrl+F
文本~辑?查找上一?Ctrl+Shift+K
文本~辑?查找下一?Ctrl+K
全局 撤销 Ctrl+Z
全局 复制 Ctrl+C
全局 恢复上一个选择 Alt+Shift+?BR>全局 剪切 Ctrl+X
全局 快速修?Ctrl1+1
全局 内容辅助 Alt+/
全局 全部选中 Ctrl+A
全局 删除 Delete
全局 上下文信?Alt+Q?BR>Alt+Shift+?
Ctrl+Shift+Space
Java~辑?昄工具提示描述 F2
Java~辑?选择装元素 Alt+Shift+?BR>Java~辑?选择上一个元?Alt+Shift+?BR>Java~辑?选择下一个元?Alt+Shift+?BR>文本~辑?增量查找 Ctrl+J
文本~辑?增量逆向查找 Ctrl+Shift+J
全局 _脓(chung) Ctrl+V
全局 重做 Ctrl+Y
查看
作用?功能 快捷?BR>全局 攑֤ Ctrl+=
全局 ~小 Ctrl+-
H口
作用?功能 快捷?BR>全局 Ȁzȝ辑器 F12
全局 切换~辑?Ctrl+Shift+W
全局 上一个编辑器 Ctrl+Shift+F6
全局 上一个视?Ctrl+Shift+F7
全局 上一个透视?Ctrl+Shift+F8
全局 下一个编辑器 Ctrl+F6
全局 下一个视?Ctrl+F7
全局 下一个透视?Ctrl+F8
文本~辑?昄标尺上下文菜?Ctrl+W
全局 昄视图菜单 Ctrl+F10
全局 昄pȝ菜单 Alt+-
D
作用?功能 快捷?BR>Java~辑?打开l构 Ctrl+F3
全局 打开cd Ctrl+Shift+T
全局 打开cd层次l构 F4
全局 打开声明 F3
全局 打开外部javadoc Shift+F2
全局 打开资源 Ctrl+Shift+R
全局 后退历史记录 Alt+?BR>全局 前进历史记录 Alt+?BR>全局 上一?Ctrl+,
全局 下一?Ctrl+.
Java~辑?昄大纲 Ctrl+O
全局 在层ơ结构中打开cd Ctrl+Shift+H
全局 转至匚w的括?Ctrl+Shift+P
全局 转至上一个编辑位|?Ctrl+Q
Java~辑?转至上一个成?Ctrl+Shift+?BR>Java~辑?转至下一个成?Ctrl+Shift+?BR>文本~辑?转至?Ctrl+L
搜烦(ch)
作用?功能 快捷?BR>全局 出现在文件中 Ctrl+Shift+U
全局 打开搜烦(ch)对话?Ctrl+H
全局 工作Z的声?Ctrl+G
全局 工作Z的引?Ctrl+Shift+G
文本~辑
作用?功能 快捷?BR>文本~辑?改写切换 Insert
文本~辑?上滚?Ctrl+?BR>文本~辑?下滚?Ctrl+?/P>
文g
作用?功能 快捷?BR>全局 保存 Ctrl+X
Ctrl+S
全局 打印 Ctrl+P
全局 关闭 Ctrl+F4
全局 全部保存 Ctrl+Shift+S
全局 全部关闭 Ctrl+Shift+F4
全局 属?Alt+Enter
全局 新徏 Ctrl+N
目
作用?功能 快捷?BR>全局 全部构徏 Ctrl+B
源代?BR>作用?功能 快捷?BR>Java~辑?格式?Ctrl+Shift+F
Java~辑?取消注释 Ctrl+\
Java~辑?注释 Ctrl+/
Java~辑?d导入 Ctrl+Shift+M
Java~辑?l织导入 Ctrl+Shift+O
Java~辑?使用try/catch块来包围 未设|,太常用了(jin)Q所以在q里列出,自己讄?BR>也可以用Ctrl+1自动修正?/P>
q行
作用?功能 快捷?BR>全局 单步q回 F7
全局 单步跌 F6
全局 单步跛_ F5
全局 单步跛_选择 Ctrl+F5
全局 调试上次启动 F11
全局 l箋 F8
全局 使用qo(h)器单步执?Shift+F5
全局 d/去除断点 Ctrl+Shift+B
全局 昄 Ctrl+D
全局 q行上次启动 Ctrl+F11
全局 q行臌 Ctrl+R
全局 执行 Ctrl+U
重构
作用?功能 快捷?BR>全局 撤销重构 Alt+Shift+Z
全局 抽取Ҏ(gu) Alt+Shift+M
全局 抽取局部变?Alt+Shift+L
全局 内联 Alt+Shift+I
全局 Ud Alt+Shift+V
全局 重命?Alt+Shift+R
全局 重做 Alt+Shift+Y
]]>4.1 l果是否正确 Right-BICEP
如果代码能够q行正确Q我要怎么才知道它是正的?/span>
·使用数据文g
4.2 边界条g Right-BICEP
4.3 (g)查反向关?/span> Right-BICEP
4.4 使用其他手段来实C叉检?/span> Right-BICEP
4.5 强制产生错误条g Right-BICEP
4.6 性能Ҏ(gu)?/span> Right-BICEP
]]>
单元试是开发者编写的一段代码Q用于检验被代码的一个很的、很明确的功能是否正。通常而言Q一个单元测试是用于判断某个特定条gQ或者场景)(j)下某个特定函数的行ؓ(f)?/span>
单元试不但?x)你的工作完成得更LQ而且?x)o(h)你的设计变得更好。甚臛_大减你花在调试上面的时间?/span>
~写单元试太花旉?/span>
q行试的时间太长了(jin)
试代码q不是我的工?/span>
我ƈ不清楚代码的行ؓ(f)Q所以也无从测?/span>
但是q些代码都能够编译通过
公司h来试我是Z(jin)写代码,而不是写试
如果我让试员或?/span>QA人员没有工作Q那么我?x)觉得很内?/span>
我的公司q不?x)让我在真实pȝ中运行单元测?/span>
试代码必须要做以下几g事情Q?/span>
·准备试所需要的各种条gQ创建所有必ȝ对象Q分配必要的资源{等Q?/span>
·调用要测试的Ҏ(gu)?/span>
·验证被测试方法的行ؓ(f)和期望是否一致?/span>
·完成后清理各U资源?/span>
JUnit提供?jin)一些辅助函敎ͼ用于帮助你确定某个被试函数是否工作正常。通常而言Q我们把所有这些函数统UCؓ(f)断言。断a是单元测试最基本的组成部分?/span>
当一个失败或错误出现的时候,当前试Ҏ(gu)的执行流E将?x)被U植Q但是(位于同一个测试类中的Q其他测试将?x)l运行?/span>
assertEquals([String message],
expected,
actual)
q是使用得最多的断言形式。在上面的参CQ?/span>expected是你的期望|通常都是编码的Q,actual是被试代码实际产生的|message是一个可选的消息Q如果提供的话,会(x)在发生错误的时候报告这个消息。当?dng)你完全可以不提供q个message参数Q而只提供expected?/span>valueq两个倹{?/span>
M对象都可以拿来做相等性测试:(x)适当的相{性判断方法会(x)被用来做q样的比较。值得注意的是使用原生数组?/span>equalsҎ(gu)Ӟ它ƈ不是比较数组的内容,而只是比较数l引用本w,而这大概不是你希望的吧?/span>
计算机ƈ不能_地表C所有的点敎ͼ通常都会(x)有一些偏差。因而,如果你想用断a来比较QҎ(gu)Q在Java中,是类型ؓ(f)float或?/span>double的数Q,则需要制定一个额外的误差参数。它表明你需要多接近才能认ؓ(f)两数“相{”?/span>
assertEquals([String message],
expected,
actual,
tolerance)
assertNull([String message], java.lang.Object object)
assertNotNull([String message], java.lang.Object object)
验证一个给定的对象是否?/span>nullQ或者ؓ(f)?/span>nullQ,如果{案为否Q则会(x)p|?/span>message参数是可选的?/span>
assertSame([String message], expected, actual)
验证expected参数?/span>actual参数所引用的是否ؓ(f)同一个对象,如果不是的话Q将?x)失败?/span>message参数是可选的?/span>
assertNotSame([String message], expected, actual)
验证expected参数?/span>actual参数所应用的是否ؓ(f)不同的对象,如果是相同的话,会(x)p|?/span>message参数是可选的?/span>
assertTrue([String message], Boolean condition)
验证l定的二元条件是否ؓ(f)真,如果为假的话Q将?x)失败?/span>meesage参数是可选的?/span>
如果你发现测试代码像下面q样Q宛如废话一般:(x)
asserTrue(true);
那么你就该好好想惌些代码了(jin)。对于这U写法,除非是被用于认某个分支Q或者一场逻辑才有可能是正的选择Q否则的话,很可能就是一个糟p的L?/span>
assertFalse([String message], Boolean condition)
上面的代码用于验证给定的二元条g是否为假。如果不是的话,该测试将?x)失败?/span>
fail([String message])
上面的断a会(x)使测试立卛_败,其中message参数是可选的。这U断a通常被用于标记某个不应该被到辄分支Q譬如,在一个与预期发生的异怹后)(j)?/span>
·使用断言
一般而言Q一个测试方法会(x)包含有多个断aQ因Z需要验证该Ҏ(gu)的多个方面以?qing)内在的多种联系?/span>
当有试p|的时候,无论如何都不能给原有代码再添加新的特性!此时你应该尽快地修复q个错误Q直到让所有的试都能利通过?/span>
每个包含试的类都必d所C那L(fng)TestCasel承而来。基c?/span>TestCase提供?jin)我们所需的大部分单元试功能Q包括所有在前面讲述q的断言Ҏ(gu)?/span>
基类需要一个以String为参数的构造函敎ͼ因而我们必调?/span>super以传递这么一个名字?/span>
试cd含了(jin)名ؓ(f)test?/span>的方法。而所有以test开头的Ҏ(gu)都会(x)?/span>JUnit自动q行。你q可以通过定义suiteҎ(gu)制定Ҏ(gu)的函数来q行?/span>
一个测试类包含一些测试方法;每个Ҏ(gu)包含一个或者多个断a语句。但是测试类也能调用其它试c:(x)单独的类、包、甚臛_整的一个系l。可以通过创徏test suite来取得。Q何测试类都能包含一个名?/span>suite的静态方法?/span>
public static Test suite();
你可以提?/span>suite()Ҏ(gu)来返回Q何你惌的测试集合(没有suite()Ҏ(gu)Q?/span>JUnit?x)自动运行所有的test?/span>Ҏ(gu)Q。但是你可能需要手工添加特D的试Q包括其?/span>suite?/span>
· Per-method?/span>Setup?/span>Tear-down
JUnit?/span>TestCase基类提供两个Ҏ(gu)供你改写Q分别用于环境的建立和清理:(x)
protected void setup();
protected void teardown();
· Per-suite Setup?/span>Tear-down
一般而言Q你只须针对每个Ҏ(gu)讄q行环境Q但是在某些情况下,你须为整?/span>test suite讄一些环境,以及(qing)?/span>test suite中的所有方法都执行完成后做一些清理工作。要辑ֈq种效果Q你需?/span>per-suite setup?/span>per-suite teardown?/span>
Per-suite?/span>setup要复杂一些。你需要提供所需试的一?/span>suiteQ无论通过什么样的方式)(j)q且把它包装q一?/span>TestSetup对象?/span>
注意你可以在同一个类中同时?/span>per-sutie?/span>per-test?/span>setup()?/span>teardown?/span>
如果你有需要在整个目中共享的断言或者公׃码,你也?dng)R要考虑?/span>TestCasel承一个类q且使用q个字类来进行所有的试?/span>
事实上,开始新目时L从自q自定义基cȝ承而不直接?/span>JUnit的类l承通常是一个好L——即便你的基cd一开始没有添加Q何额外的功能。这样做的好处是当你需要添加一个所有测试类都需要的Ҏ(gu)或者能力时Q可以简单地~辑你的基类而不需要改动项目中的所?/span>test case?/span>
对于试而言Q下面两U异常是我们可能?x)感兴趣的?x)
1Q?span style="font-family: "Times New Roman"; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"> 从测试代码抛出的可预异常?/span>
2Q?span style="font-family: "Times New Roman"; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"> ׃某个模块Q或代码Q发生严重错误,而抛出的不可预测异常?/span>
M?/span>assertTrue(true)的用都应该被翻译ؓ(f)“我预期控制程?x)达到这个地方”。这对将来可能的误解来说?x)v到强有力的文的作用。然而,不要忘记一?/span>assertTrue(true)没有被调用不?x)生Q何错误的?/span>
通常而言Q对于方法中每个被期望的异常Q你都应该写一个专门的试来确认该Ҏ(gu)在应该抛出异常的时候确实会(x)抛出异常?/span>
对于处于Z意料的异常,你最好简单的改变你的试Ҏ(gu)的声明让它能抛出可能的异常?/span>JUnit框架可以捕获M异常Qƈ且把它报告ؓ(f)一个错误,q些都不需要你的参与?/span>
如果~写?jin)一个测试,但是实现代码q没有准备好Q可以将以?/span>test”打头的试Ҏ(gu)名米功能为别的,譬如把?/span>test”去掉,然后{准备好?jin)要来运行测试的时候再改回来?/span>
无论如何Q你要避免养成忽略“失败的试l果”的?fn)惯?/span>
?/span>JUnit写测试真正所需要的׃件事Q?/span>
1Q?span style="font-family: "Times New Roman"; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"> 一?/span>import语句引入所?/span>junit.framework.*下的cR?/span>
2Q?span style="font-family: "Times New Roman"; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"> 一?/span>extends语句让你的类?/span>TestCasel承?/span>
3Q?span style="font-family: "Times New Roman"; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"> 一个调?/span>super(string)的构造函数?/span>
Eclipse官方主页Q?A >http://www.eclipse.org
MyeclipseQ一个基于Eclipse的很全面好用的J2EE开发^収ͼ需付费使用Q?BR>主页Q?A >http://www.myeclipseide.com
VE EditorQ图形化的开发GUI界面的插件?BR>主页Q?A >http://www.eclipse.org/vep/
先决条g是安装EMF和GET?BR> EMFQ?A >http://www.eclipse.org/emf/
GEFQ?A >www.eclipse.org/gef/
XMLBuddyQ很不错的开发XML插g?BR>主页Q?A >http://xmlbuddy.com
LombozQ开发J2EE首选插件?BR>主页Q?A >http://www.objectlearn.com/
sysdeo Tomcat PluginQ一个方便实用的tomcat插g?BR>主页Q?A >http://www.sysdeo.com/eclipse/tomcatPlugin.html
UML2Q一个支持UML开发的插g?BR>主页Q?A >http://www.eclipse.org/uml2/
先决条g是安装EMF?BR> EMFQ?A >http://www.eclipse.org/emf/
Easy StrutsQ开发struts的插件?BR>主页Q?A >http://easystruts.sourceforge.net/
JIntoQ开发资源文件的一个插件?BR>主页Q?A >http://www.guh-software.de/jinto_en.html
KeePresidentQ加快Eclipse速度的插件。(仅适用于Windowsq_Q?BR>主页Q?A >http://suif.stanford.edu/pub/keepresident/
JBossIDEQ在JBOSS服务器上的开发J2EE的插件?BR>主页Q?A >http://www.jboss.com/products/jbosside
如果想采取link方式安装插gQ可看这文章(点击q里Q?BR>一些介leclipse插g使用的地方(点击q里Q?/P>
你有什么好用的插g吗?留言告诉我,大家一起分享吧Q)(j)
直接在struts-config.xml中右键data-sources然后New?/P>
默认的type是:(x)
org.apache.struts.util.GenericDataSource
struts自带的一个数据库q接池?/P>
然后正确输入各种property的value?/P>
试Q好用?/P>
如果type选择为:(x)
org.apache.commons.dbcp.BasicDataSource
q个DBCP的数据库q接池?/P>
然后键入正确的value?/P>
试Q提C各U异?amp;找不到Driver?/P>
查看DBCP的文,发现MYECLIPSE生成的配|XML元素有问题?/P>
DBCP需要的是driverClassName和usernameq两个propertys?/P>
而Myeclipse自动生成的是driverClass和userq两个propertys?/P>
改过来之后发现DBCP的数据库q接池也好用?jin)?x)Q?/P>
q应该算是MYECLIPSE开发struts的一个BUG吧,数据库连接池的配|是按照struts默认的GenericDataSource来的。如果能动态的在选择数据库连接池的时候,扑֯set()/get()Ҏ(gu)来生成属性的名字应该更好?/P>
也看出来不同的数据库q接池在命名规则斚w存在的一些差异?/P>
其实很简单的东西Q我却花费了(jin)半天的时_(d)原因是我太相信工具了(jin)Q以为生成的东西一定是正确的,所以一直在x不是别的斚w出错?jin)。得到这ơ教训之后,要更加清晰的对工h怀疑态度?jin)。不能太q相信和依靠Q还是自己对q些技术的?jin)解最重要?/P>
PSQTOMCAT有自带DBCP。不q我是自׃jakarta上面下的commons dbcp攑ֈ自己的lib里面的,当然Q官方doc上面有这L(fng)说明Q?/P>
Commons-DBCP depends at runtime on commons-pool and commons-collections .
所以记得要把这两项也下回来和dbcp的jar文g一hqlib才能保证不出错?/P>
MQ认真+?j)细Q才能更好的解决问题?/P>
本文环境Q?BR>Win2003 + jdk1.5.0_01
Tomcat 5.5 + MySql4.1
Eclipse 3.0.1 + Myeclipse 3.8.4
本文提到的一些Y件的下蝲地址Q?/P>
J2SE 5.0QSUN弄的q些׃八糟的名字真讨厌Qq感觉Q:(x)
http://java.sun.com/j2se/1.5.0/download.jsp
TomcatQ?BR>http://jakarta.apache.org/site/downloads/downloads_tomcat-5.cgi
MySql4.1Q?BR>http://dev.mysql.com/downloads/
EclipseQ?BR>http://www.eclipse.org/downloads/index.php
Jakarta commonsQDBCP和其所需要的commons pool和commons collections都是在这里下Q:(x)
http://jakarta.apache.org/site/downloads/downloads_commons.html