快精灵印艺坊 您身边的文印专家
广州名片 深圳名片 会员卡 贵宾卡 印刷 设计教程
产品展示 在线订购 会员中心 产品模板 设计指南 在线编辑
 首页 名片设计   CorelDRAW   Illustrator   AuotoCAD   Painter   其他软件   Photoshop   Fireworks   Flash  

 » 彩色名片
 » PVC卡
 » 彩色磁性卡
 » 彩页/画册
 » 个性印务
 » 彩色不干胶
 » 明信片
   » 明信片
   » 彩色书签
   » 门挂
 » 其他产品与服务
   » 创业锦囊
   » 办公用品
     » 信封、信纸
     » 便签纸、斜面纸砖
     » 无碳复印纸
   » 海报
   » 大篇幅印刷
     » KT板
     » 海报
     » 横幅

JUnit源码分析(三)


三、微观——执行流程与代码风格











来过一遍JUnit的执行流程吧,这样你就能对JUnit有个清楚的熟悉,虽然作为一个使用者这完全是不必要的。从《JUnit in Action》直接拿来一张JUnit流程图。



哦,也许你看晕了,我来当下导游好了。上面已经提到了TestRunner是BaseTestRunner的子类,在三个不同的ui包中各有一个TestRunner。这里我们仅以junit.textui包中的为例。











TestRunner作为入口程序是怎么被启动的呢?习惯了使用容器的我们现在也许很少考虑这个问题。那我们在TestRunner类里面找找吧,你看,你发现了这个:











public static void main(String args[]) {











这不是我们写小桌面程序时常常打交道的main方式么?对,就这么简朴。











从这个main方式入口,首先JUnit将要分析命令行的参数,然后将检查测试类是否包含符合标准的suite方式,假如有就将执行方式中的内容(见图中0、1部分);假如没有找到将自动生成一个TestSuite,这样就跳过了图中的0部分,并将测试用例类作为参数传入(见图中1部分)。











上面得到了一个TestSuite类型的对象,现在就可以运行测试了,不过在运行前要先加载TestResult和TestListener的对象(见图中2部分),用来监听和记录测试结果信息。剩下的在图中可以很轻易的看懂了,你可以参照源码浏览一遍。 



这里提出我的一点疑问。注重到JUnit实践中提示将测试类中每个测试方式公用的初始化步骤放到setup方式中。这好像会给你一种错觉,那就是你会认为setup与tearDown中的语句对于一个测试类中的所有测试方式只会运行一次。但是实际上JUnit在实现上却出乎意料,setup对于测试类中的每个测试方式都回运行一遍。意思就是说,你把公用的初始化代码放到setup方式中仅仅是在代码结构上实现了重用,而没有起到任何优化系统的作用。比如你在setUp中初始化数据库连接,那么这个过程将被执行不只一次,这可有点……。我们来看下代码:











//theClass为得到的TestCase类,name为此类其中的一个方式











static public Test createTest(Class theClass, String name) {











       Constructor constructor;











       try {











              constructor= getTestConstructor(theClass);











       ……











       Object test;











       try {











//以下内容为获得一个TestCase对象,并将方式名称传入这个对象











              if (constructor.getParameterTypes().length == 0) {











                     test= constructor.newInstance(new Object[0]);











                     if (test instanceof TestCase)











                            ((TestCase) test).setName(name);











              } else {











                     test= constructor.newInstance(new Object[]{name});











              }











       ……











       //返回这个对象











       return (Test) test;











}











再看下运行处的代码,下面的方式是运行在setUp和tearDown中间的











protected void runTest() throws Throwable {











       //fName就是testcase对象所拥有的那个方式的名称











       assertNotNull(fName);











       Method runMethod= null;











       try {











              //根据方式名由反射得到方式











              runMethod= getClass().getMethod(fName, null);











       }











       ……











              //执行测试方式











              runMethod.invoke(this, new Class[0]);











……











       }











这样每执行一个测试方式就要运行一遍setUp和tearDown方式,大概就是这样一个过程:



恩……,也许这是为了兼容老的版本,也许是……。还好,JUnit提供了一个补救的扩展类,那就是我们上面提到的TestSetup,在这里类里面真正的实现了setUp、tearDown方式的提取使用。你在使用的时候,通过继续来实现自己的setUp、tearDown方式,并使用装饰模式独有的调用方法来使用它就可以了。 



在阅读的过程中,代码风格上给我最明显的感觉就是,代码基本上全多做到了细化,将每个功能点单独提取到一个方式中,这样提高了代码的可复用性。可是在阅读的时候,在方式间频繁的跳跃,实在不是件好事,假如没有IDE的帮助,我非要晕掉不可。











因此我认为在提高代码重用上还是要坚持这样的一条原则:到必要的时候再下手。就是说,在你刚开始写代码的时候不要考虑什么重用和扩展,只有当你真正需要复用某段代码或者扩展系统时,在动手吧(记得在某位牛人的书上是这么来比喻的:让第一颗子弹打中你)。











JUnit中使用的是老版本java collection,这大概是因为JUnit最初版本出现的时候还没有新版collection推出。这种代码不应该出现在我们现在编写的代码中了,请注重。












 四、总结








 四、总结









 四、总结










    好了,基本上分析完了JUnit的代码,不知道你学到了什么。希望本文能够起到抛砖引玉的作用。



返回类别: 教程
上一教程: 【JSF心得】JAVA的对象传递是引用传递
下一教程: Java入门:理解构造器 (转)

您可以阅读与"JUnit源码分析(三)"相关的教程:
· JUnit源码分析(二)
· WebWork2源码分析
· WebWork2源码分析续三
· Java源码分析:深入探讨Iterator模式
· WebWork2源码分析续一
    微笑服务 优质保证 索取样品