我们使用的开发环境是Eclipse 3.2Q它已经自带了JUnit 4.1Q你需要将JUnit 4 Libraryd到项目用到的Library中。另外,必须使用JDK 5.0或更高版本?/p>
要在Eclipse环境之外q行JUnitQ需要下载JUnit 4.1?/p>
我们先看一个简单的Mathc:
注意exp()Ҏ(gu)是有Bug的,如果传入参数2, -1Q则期待的返回值应?.5FQ但实际q回gؓ1.0F?/p>
下面我们看看传统的JUnit的TestCaseQ?/p>
JUnit依赖反射来执行每个以test开头的Ҏ(gu)。然而,在最新的JUnit 4中,׃有了Annotation的支持,我们的测试方法不需要再以testXxx标识了,而是写上一个@Test标注卛_。例如:
甚至MathTestcM不必l承自TestCase。你也许会想刎ͼ不承自TestCase无法调用assertXxxҎ(gu)了,正因为如此,所有的assertXxxҎ(gu)全部以静态方法被攑օ了Assertc,使用Assert.assertXxx()调用。如果?/p>
则原有的代码不必改动?/p>
setUp()和tearDown()Ҏ(gu)也依赖@Before和@After标记Q这样做的最大的好处是在l承体系内不必担心忘C在setUp()Ҏ(gu)中调用父cȝsuper.setUp()Ҏ(gu)QJUnit框架会自动处理父cȝ@Before和@After标记的方法?/p>
q且QJUnit框架对@Before和@After的调用顺序类gcȝ构造方法和析构Ҏ(gu)Q即@Before按照父类到子cȝ序调用Q@After则相反,q样保证了资源的正确获取和释放?/p>
当然Q不再强q必M用setUp和tearDown作ؓҎ(gu)名,可以使用更有意义的方法名Q例如:initDatabase()和closeDatabase()Q只要它们被标注了@Before和@After卛_?/p>
来看看用Annotation的MathTestQ?/p>
Ҏ(gu)试异常,JUnit 4可以?font face="Courier New" color="#ff0000">expected=Exception.class来期待一个预期的异常Q而不必编?/p>
来看看doDiv0试Q我们期待一个除Cؓ0的ArithmeticExceptionQ因此编写如下测试方法:
对于非常耗时的测试,@Testq有一个timeout来标识该Ҏ(gu)最长执行时_过此时间即表示该测试方法失败:
以上Ҏ(gu)若执行时间超q?ms则测试失败,׃依赖CPU的执行速度Q在不同的机器上试l果也不同?/p>
JUnit 4另一个较大的变化是引入了@BeforeClass和@AfterClassQ它们在一个Testcȝ所有测试方法执行前后各执行一ơ。这是ؓ了能在@BeforeClass中初始化一些昂늚资源Q例如数据库q接Q然后执行所有的试Ҏ(gu)Q最后在@AfterClass中释放资源?/p>
正如你能惛_的,׃@BeforeClass和@AfterClass仅执行一ơ,因此它们只能标记静态方法,在所有测试方法中׃n的资源也必须是静态引用:
最后执行测试用例,可以看到l果Q?/p>
各个Ҏ(gu)执行序如下Q?/p>
call @BeforeClass and init database connection
new MathTest instance.
call @Before before a test method
call @After after a test method
new MathTest instance.
call @Before before a test method
call @After after a test method
...
call @AfterClass to release database connection
可以看到Q@BeforeClass是在实例化MathTest之前调用的,因此不能在构造方法中初始化共享资源?/p>
最后需要注意的是由于Java 5的自动Box/UnboxҎ(gu),在调用assertEquals()时要特别注意Q如果你传入Q?/p>
assertEquals(100F, 100);
则按照自动Box变ؓQ?/p>
assertEquals(new Float(100F), new Integer(100));
试p|Q因为FloatcdIntegercM是同一cd?/p>
因此要特别注意float和double的测试。事实上对float和double应?/p>
assertEquals(float, float, float delta);
assertEquals(double, double, double delta);
delta指定了两个作比较的QҎ(gu)的相差范_在此范围内的两个点数将认ؓ相等。可以传入一个很的C?.0001F?nbsp;
JUnit 4非常适合使用Java 5的开发h员,但是无法在Java 1.4中获得这些好处,q且Q也不与以前的版本兼宏V因此,如果你正在用Java 5Q就可以考虑使用JUnit 4来编写测试?br />
此文章来自:http://www.javaeedev.com/blog/article.jspx?articleId=ff80808112e766ee011312f144520061
TDD的基本思\是通过试来推动整个开发的q行。而测试驱动开发技术ƈ不只是单U的试工作?/span>
需求向来就是Y件开发过E中感觉最不好明确描述、易变的东西。这里说的需求不只是指用L需求,q包括对代码的用需求。很多开发h员最x的是后期q要修改某个cL者函数的接口q行修改或者扩展,Z么会发生q样的事情就是因部分代码的用需求没有很好的描述。测试驱动开发就是通过~写试用例Q先考虑代码的用需求(包括功能、过E、接口等Q,而且q个描述是无二义的,可执行验证的?/span>
通过~写q部分代码的试用例Q对其功能的分解、用过E、接口都q行了设计。而且q种从用角度对代码的设计通常更符合后期开发的需求。可试的要求,对代码的内聚性的提高和复用都非常有益。因此测试驱动开发也是一U代码设计的q程?/span>
开发h员通常对编写文档非常厌烦,但要使用、理解别人的代码旉常又希望能有文档进行指对{而测试驱动开发过E中产生的测试用例代码就是对代码的最好的解释?/span>
快乐工作的基是对自己有信心Q对自己的工作成果有信心。当前很多开发h员却l常在担心:“代码是否正确Q?#8221;“辛苦~写的代码还有没有严重bugQ?#8221;“修改的新代码对其他部分有没有影响Q?#8221;。这U担心甚臛_致某些代码应该修改却不敢修改的地步。测试驱动开发提供的试集就可以作ؓ你信心的来源?/span>
当然试驱动开发最重要的功能还在于保障代码的正性,能够q速发现、定位bug。而迅速发现、定位bug是很多开发h员的梦想。针对关键代码的试集,以及不断完善的测试用例,速发现、定位bug提供了条件?/span>
我的一D功能非常复杂的代码使用TDD开发完成,真实环境应用中只发现几个bugQ而且很快被定位解冟뀂?zhn)在应用后Q也一定会为那U自信的开发过E,功能不断增加、完善的感觉Q迅速发现、定位bug的能力所感染Q喜Ƣ这个技术的?/span>
十一、测试驱动开发(TDDQ?font style="background-color: #ffffff">原理Q?/span>
试驱动开发的基本思想是在开发功能代码之前,先编写测试代码。也是说在明确要开发某个功能后Q首先思考如何对q个功能q行试Qƈ完成试代码的编写,然后~写相关的代码满些测试用例。然后@环进行添加其他功能,直到完全部功能的开发?/span>
我们q里把这个技术的应用领域从代码编写扩展到整个开发过E。应该对整个开发过E的各个阶段q行试驱动Q首先思考如何对q个阶段q行试、验证、考核Qƈ~写相关的测试文档,然后开始下一步工作,最后再验证相关的工作。下图是一个比较流行的试模型QV试模型?/span>
在开发的各个阶段Q包括需求分析、概要设计、详l设计、编码过E中都应该考虑相对应的试工作Q完成相关的试用例的设计、测试方案、测试计划的~写。这里提到的开发阶D只是D例,Ҏ(gu)实际的开发活动进行调整。相关的试文档也不一定是非常详细复杂的文档,或者什么Ş式,但应?span style="background-color: yellow">L试驱动的习?/span>?/span>
关于试模型Q还有X试模型。这个测试模型,我认为,是对详细阶段和编码阶D进行徏模,应该说更详细的描qC详细设计和编码阶D늚开发行为。及针对某个功能q行对应的测试驱动开发?/span>
软g开发其他阶D늚试驱动开发,Ҏ(gu)试驱动开发的思想完成对应的测试文档即可。下面针对详l设计和~码阶段q行介绍。测试驱动开发的基本q程如下Q?br /> 1Q?明确当前要完成的功能。可以记录成一?TODO 列表?br /> 2Q?快速完成针Ҏ(gu)功能的测试用例编写?br /> 3Q?试代码~译不通过?br /> 4Q?~写对应的功能代码?br /> 5Q?试通过?br /> 6Q?对代码进行重构,q保证测试通过?br /> 7Q?循环完成所有功能的开发?/p>
开发过E中Q通常把测试代码和功能代码分开存放Q这里提供一个简单的试框架使用例子Q?zhn)可以通过它了解测试框架的使用。下面是文g列表?/span>
project/ 目ȝ?
project/test 试目ȝ?
project/test/testSeq.cpp 试seq_t 的测试文Ӟ对其他功能文件的试文g复制后修改即?
project/test/testSeq.h
project/test/Makefile 试目?Makefile
project/test/main.cpp 试目的主文gQ不需要修?
project/main.cpp 目的主文g
project/seq_t.h 功能代码Q被试文g
project/Makefile 目?Makefile
十二、测试驱动开发(TDDQ原则:试隔离。不同代码的试应该怺隔离。对一块代码的试只考虑此代码的试Q不要考虑其实现细节(比如它用了其他cȝ边界条gQ?/span>
一帽子。开发h员开发过E中要做不同的工作,比如Q编写测试代码、开发功能代码、对代码重构{。做不同的事Q承担不同的角色。开发h员完成对应的工作时应?br /> 保持注意力集中在当前工作上,而不要过多的考虑其他斚w的细节,保证头上只有一帽子。避免考虑无关l节q多Q无谓地增加复杂度?/span>
试列表。需要测试的功能点很多。应该在M阶段x加功能需求问题时Q把相关功能点加到测试列表中Q然后l手头工作。然后不断的完成对应的测试用例、功?br /> 代码、重构。一是避免疏漏,也避免干扰当前进行的工作?/span>
试驱动。这个比较核心。完成某个功能,某个c,首先~写试代码Q考虑其如何用、如何测试。然后在对其q行设计、编码?/span>
先写断言。测试代码编写时Q应该首先编写对功能代码的判断用的断a语句Q然后编写相应的辅助语句?/span>
可测试性。功能代码设计、开发时应该h较强的可试性。其实遵循比较好的设计原则的代码都具备较好的试性。比如比较高的内聚性,量依赖于接口等?/span>
及时重构。无论是功能代码q是试代码Q对l构不合理,重复的代码等情况Q在试通过后,及时q行重构?/span>
步前进。Y件开发是个复杂性非帔R的工作,开发过E中要考虑很多东西Q包括代码的正确性、可扩展性、性能{等Q很多问题都是因为复杂性太大导致的。极限编E?br />
提出了一个非常好的思\是步前进。把所有的规模大、复杂性高的工作,分解成小的Q务来完成。对于一个类来说Q一个功能一个功能的完成Q如果太?br />
隑ְ再分解。每个功能的完成p试代码Q功能代码-试Q重?/span>的@环。通过分解降低整个pȝ开发的复杂性。这L效果非常明显。几个小的功能代?br />
完成后,大的功能代码几乎是不用调试就可以通过。一个个cL法的实现Q很快就看到整个cd快就完成啦。本来感觉很多特性需要增加,很快׃看到没有
几个啦。你甚至会ؓq个速度感到震惊。(我理解,是大q度减少调试、出错的旉产生的这U速度感)
十三、测试驱动开发(TDDQ测试技术:
1. 试范围、粒?br />
对哪些功能进行测试?会不会太J琐Q什么时候可以停止测试?q些问题比较常见。按大师 Kent Benk 的话Q对那些你认为应该测试的代码q行试。就是说Q要怿自己的感觉,自己的经验。那些重要的功能、核心的代码应该重Ҏ(gu)试。感到疲力_应该停下来休息一下。感觉没有必要更详细的测试,停止本轮测试?/span>
试驱动开发强调测试ƈ不应该是负担Q而应该是帮助我们减轻工作量的Ҏ(gu)。而对于何时停止编写测试用例,也是应该Ҏ(gu)你的l验Q功能复杂、核心功能的代码应该编写更全面、细致的试用例Q否则测试流E即可?/span>
试范围没有静态的标准Q同时也应该可以随着旉改变。对于开始没有编写够的试的功能代码,随着bug的出玎ͼҎ(gu)bug补齐相关的测试用例即可?/span>
步前进的原则,要求我们对大的功能块试Ӟ应该先分拆成更小的功能块q行试Q比如一个类A使用了类B、CQ就应该~写到A使用B、C功能的测试代码前Q完成对B、C的测试和开发。那么是不是每个类或者小函数都应该测试哪Q我认ؓ没有必要。你应该q用你的l验Q对那些可能出问题的地方重点试Q感觉不可能出问题的地方q它真正出问题的时候再补测试吧?br />
2. 怎么~写试用例
试用例的编写就用上了传l的试技术?/span>