• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • JUnit源碼分析(三)

    發表于:2007-07-01來源:作者:點擊數: 標簽:
    三、微觀執行流程與代碼風格 來過一遍JUnit的執行流程吧,這樣你就能對JUnit有個清晰的認識,雖然作為一個使用者這完全是不必要的。從《JUnit in Action》直接拿來一張JUnit流程圖。 哦,也許你看暈了,我來當下導游好了。上面已經提到了TestRunner是BaseTes

    三、微觀——執行流程與代碼風格











    來過一遍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方法,并使用裝飾模式獨有的調用方式來使用它就可以了。 



    在閱讀的過程中,代碼風格上給我最明顯的感覺就是,代碼基本上全多做到了細化,將每個功能點單獨提取到一個方法中,這樣提高了代碼的可復用性??墒窃陂喿x的時候,在方法間頻繁的跳躍,實在不是件好事,如果沒有IDE的幫助,我非要暈掉不可。











    因此我認為在提高代碼重用上還是要堅持這樣的一條原則:到必要的時候再下手。就是說,在你剛開始寫代碼的時候不要考慮什么重用和擴展,只有當你真正需要復用某段代碼或者擴展系統時,在動手吧(記得在某位牛人的書上是這么來比喻的:讓第一顆子彈打中你)。











    JUnit中使用的是老版本java collection,這大概是因為JUnit最初版本出現的時候還沒有新版collection推出。這種代碼不應該出現在我們現在編寫的代碼中了,請注意。












     四、總結








     四、總結









     四、總結










        好了,基本上分析完了JUnit的代碼,不知道你學到了什么。希望本文能夠起到拋磚引玉的作用。

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>