<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    An early look at JUnit 4

    Upcoming release promises evolution in testing

    難度級(jí)別: 中

    Elliotte Harold (elharo@metalab.unc.edu), Adjunct Professor, Polytechnic University

    2005-9-15 (譯)

    原文:http://www-128.ibm.com/developerworks/java/library/j-junit4.html

    JUnit 是JAVA語言事實(shí)上的標(biāo)準(zhǔn)測(cè)試庫(kù)。JUnit 4是三年以來最具里程碑意義的一次發(fā)布。它的新特性主要是針對(duì)JAVA5中的標(biāo)記(annotation)來簡(jiǎn)化測(cè)試,而不是利用子類、反射或命名機(jī)制。本文將講述如何使用JUnit 4,當(dāng)前前提是你最好具有JUnit的使用經(jīng)驗(yàn).

    JUnit, 由Kent Beck?和 Erich Gamma開發(fā),幾乎是JAVA開發(fā)最重要的第三方工具。正如Martin Fowler 所說,“在軟件開發(fā)領(lǐng)域,從來就沒有如此少的代碼起到了如此重要的作用“。由于JUnit,JAVA代碼變得更健壯,更可靠,BUG也比以前更少。由于JUnit (由Smalltalk's的SUnit得來) 的出現(xiàn),隨后產(chǎn)生了許多xUnit的測(cè)試工具,如nUnit (.NET), pyUnit (Python), CppUnit (C++), dUnit (Delphi) 和其它不同平臺(tái)及語言的測(cè)試相關(guān)的工具。

    雖然JUnit也只是一個(gè)工具,但其產(chǎn)生的思想和技術(shù)卻較其架構(gòu)更意義重大。單元測(cè)試,測(cè)試先行的編程方式,測(cè)試驅(qū)動(dòng)的開發(fā)方式,并非必須由JUNIT實(shí)現(xiàn),也不一定要用SWing實(shí)現(xiàn)GUI界面。JUNIT最近的一次更新是在三年前,但它比其它大多數(shù)有BUG的框架都要健壯,更重要的是,JAVA一直在改進(jìn)。現(xiàn)在JAVA支持泛型,枚舉,可變長(zhǎng)度參數(shù),以及標(biāo)記語言(開創(chuàng)了開發(fā)可重用框架的新局面)。

    JUnit's的停滯不前使得那些想要變革的開發(fā)人員換其它測(cè)試工具.挑戰(zhàn)者有Bill Venners的Artima SuiteRunner和Cedric Beust的TestNG.這些工具庫(kù)雖然有值得推薦的功能,但沒有任何一款的地位能與JUNIT相比,沒有任何一款工具被其它業(yè)界產(chǎn)品如Ant, Maven, Eclipse廣泛支持.因此Beck 和Gamma雙開始利用JAVA5的新特性來開發(fā)新版的JUNIT,目的是利用JAVA5中的標(biāo)記特性使得單元測(cè)試開發(fā)更容易。Beck說:“JUNIT4的主要目的是通過簡(jiǎn)化JUNIT的使用鼓勵(lì)更多的開發(fā)人員寫更多的測(cè)試”。雖然會(huì)與以前的版本兼容,但JUNIT4與從JUNIT1.0就開始的版本相比會(huì)有一個(gè)非常大的變化.

    注意: 修改基本框架是一把雙刃劍,雖然JUNIT4的目的是清晰的,但細(xì)節(jié)仍有許多不同,因此本文只是一個(gè)簡(jiǎn)單的介紹,并不是最終文檔.

    測(cè)試方法

    以前所有版本的JUNIT都使用命名機(jī)制和反射來定位測(cè)試,下面的代碼測(cè)試1+1= 2:

    import junit.framework.TestCase;
    
    public class AdditionTest extends TestCase {
    
      private int x = 1;
      private int y = 1;
      
      public void testAddition() {
        int z = x + y;
        assertEquals(2, z);
      }
    
    }

    而在JUNIT 4中,測(cè)試方法由@Test 標(biāo)記說明,如下:

    import org.junit.Test;
    import junit.framework.TestCase;
    
    public class AdditionTest extends TestCase {
    
      private int x = 1;
      private int y = 1;
      
      @Test public void testAddition() {
        int z = x + y;
        assertEquals(2, z);
      }
    
    }

    使用標(biāo)記的好處是你不用將所有測(cè)試方法命名為 testFoo(), testBar()等等以"test"開頭的方法,下面的方法也同樣可以工作:

    import org.junit.Test;
    import junit.framework.TestCase;
    
    public class AdditionTest extends TestCase {
    
      private int x = 1;
      private int y = 1;
      
      @Test public void additionTest() {
        int z = x + y;
        assertEquals(2, z);
      }
    
    }

    下面的代碼也同樣正確:

    import org.junit.Test;
    import junit.framework.TestCase;
    
    public class AdditionTest extends TestCase {
    
      private int x = 1;
      private int y = 1;
      
      @Test public void addition() {
        int z = x + y;
        assertEquals(2, z);
      }
    
    }

    這種命名機(jī)制最大的優(yōu)點(diǎn)是更適合你的待測(cè)試類或方法名稱,例如,你可以使用ListTEst.contains()測(cè)試 List.contains();使用ListTest.addAll()測(cè)試 List.add()等等.

    TestCase還可以繼續(xù)使用,但你沒有必須再擴(kuò)展為子類,只要你聲明了@Test,你可以將測(cè)試方法放在任何類中,當(dāng)然如要訪問assert等方法,你必須要引用junit.Assert類,如下:

    import org.junit.Assert;
    
    public class AdditionTest {
    
      private int x = 1;
      private int y = 1;
      
      @Test public void addition() {
        int z = x + y;
        Assert.assertEquals(2, z);
      }
    
    }

    你也可以使用JDK5中的新特性(static import)使得跟以前版本一樣簡(jiǎn)單:

    import static org.junit.Assert.assertEquals;
    
    public class AdditionTest {
    
      private int x = 1;
      private int y = 1;
      
      @Test public void addition() {
        int z = x + y;
        assertEquals(2, z);
      }
    
    }

    這種方法測(cè)試受保護(hù)的方法非常容易,因?yàn)槟憧梢栽跍y(cè)試類中繼承有受保護(hù)方法的類.



    Back to top


    SetUp 和TearDown

    JUnit 3 中test runners 會(huì)在每個(gè)測(cè)試之前自動(dòng)調(diào)用 setUp()方法。此方法主要用于初始化變量,打開日志,重置環(huán)境變量等。下面是XOM's XSLTransformTest中的 setUp()方法:

    protected void setUp() {
            
        System.setErr(new PrintStream(new ByteArrayOutputStream()));
            
        inputDir = new File("data");
        inputDir = new File(inputDir, "xslt");
        inputDir = new File(inputDir, "input");
            
    }

    在JUnit 4中,你仍然可以在每個(gè)測(cè)試前初始化變量和配置環(huán)境,,然而,這些操作可以不用在Setup()中完成,你可以在初始化方法前面添加@Beforer 來表示,如下:

    @Before protected void initialize() {
            
        System.setErr(new PrintStream(new ByteArrayOutputStream()));
            
        inputDir = new File("data");
        inputDir = new File(inputDir, "xslt");
        inputDir = new File(inputDir, "input");
            
    }

    你也可以有多個(gè)方法標(biāo)記有@Before,所有方法都會(huì)在每個(gè)測(cè)試之前執(zhí)行:

    @Before protected void findTestDataDirectory() {
        inputDir = new File("data");
        inputDir = new File(inputDir, "xslt");
        inputDir = new File(inputDir, "input");
    }
        
     @Before protected void redirectStderr() {
        System.setErr(new PrintStream(new ByteArrayOutputStream()));
    }

    清除環(huán)境與JUNIT3 差不多,在JUNIT3中使用 tearDown()方法,下面的代碼是結(jié)束測(cè)試時(shí)回收內(nèi)存:

    protected void tearDown() {
      doc = null;
      System.gc();   
    } 

    在JUnit 4中,你還可以使用@After標(biāo)記來說明:

    @After protected void disposeDocument() {
      doc = null;
      System.gc();   
    } 

    @Before一樣,你也可以有多個(gè)標(biāo)記有 @After的清除方法,每個(gè)都會(huì)在執(zhí)行完每個(gè)測(cè)試后執(zhí)行。

    最后,你不需要在父類中明確調(diào)用這些初始化或清除方法.test runner會(huì)自動(dòng)調(diào)用這些標(biāo)記的方法.子類中的@Before方法在父類的@Before方法之后執(zhí)行(這與構(gòu)造函數(shù)的執(zhí)行順序一樣),而@After方法剛好相反,子類中的@After方法先執(zhí)行.然而,多個(gè)@Before和@After方法的執(zhí)行順序就是未知的.

    測(cè)試集范圍的初始化

    JUnit 4中引入了一項(xiàng)JUNIT3沒有的新特性,類級(jí)別的setUp()和tearDown(),即在一個(gè)類的所有測(cè)試前執(zhí)行初始化,并在所有測(cè)試完成后執(zhí)行清除。

    例如,一個(gè)測(cè)試類中的每個(gè)測(cè)試都要用到一個(gè)數(shù)據(jù)庫(kù)連接或網(wǎng)絡(luò)連接,或其它很耗資源初始化或釋放的資源,用不著在每個(gè)測(cè)試方法前后進(jìn)行操作,而只需要在測(cè)試類開始前后執(zhí)行即可。下面的示例是使用第三方的庫(kù)進(jìn)行錯(cuò)誤,在執(zhí)行所有測(cè)試前將錯(cuò)誤先重定向到非標(biāo)準(zhǔn)輸出,然后在所有測(cè)試結(jié)束后再輸出到需要的地方,這樣就不會(huì)影響到測(cè)試過程中產(chǎn)生的其它信息。

    // This class tests a lot of error conditions, which
    // Xalan annoyingly logs to System.err. This hides System.err 
    // before each test and restores it after each test.
    private PrintStream systemErr;
        
    @BeforeClass protected void redirectStderr() {
        systemErr = System.err; // Hold on to the original value
        System.setErr(new PrintStream(new ByteArrayOutputStream()));
    }
        
    @AfterClass protected void tearDown() {
        // restore the original value
        System.setErr(systemErr);
    }

    上面的操作沒有必須在每個(gè)測(cè)試前后執(zhí)行。然而要注意的是,這種方法可能影響測(cè)試間的結(jié)果,如果一個(gè)測(cè)試改變了初始化的對(duì)象,而這個(gè)對(duì)象可能是其它測(cè)試的輸入,那么測(cè)試的結(jié)果可能不正確,這種方法將依賴測(cè)試的順序并可能引入BUG。當(dāng)優(yōu)化測(cè)試性能,并且當(dāng)你改進(jìn)了配置和基準(zhǔn)測(cè)試后而仍然很慢時(shí),如數(shù)據(jù)庫(kù)連接或網(wǎng)絡(luò)問題,你才需要考慮使用這種方法。只有這樣,你才能每天執(zhí)行多次測(cè)試。



    Back to top


    異常測(cè)試

    異常測(cè)試是JUNIT4中的最大的改進(jìn),以前異常測(cè)試是通過try catch實(shí)現(xiàn),當(dāng)拋出異常時(shí),在try的最后添加一條fail()語句實(shí)現(xiàn).如下:

    public void testDivisionByZero() {
        
        try {
            int n = 2 / 0;
            fail("Divided by zero!");
        }
        catch (ArithmeticException success) {
            assertNotNull(success.getMessage());
        }
        
    }

    這種方法不僅難看,而且造成無論成功或失敗,代碼覆蓋工具都不能執(zhí)行某些代碼.而在JUnit 4中,你可以在要拋出異常的代碼中添加標(biāo)記來聲明一個(gè)異常是期望的:

    @Test(expected=ArithmeticException.class) public void divideByZero() {
        int n = 2 / 0;
    }

    如果沒有異常拋出,上面的測(cè)試則會(huì)失敗,如果你想知道異常的詳細(xì)信息或其它情況,你還是要使用try catch才行

    Back to top


    需要忽略的測(cè)試

    也許你有些測(cè)試需要很長(zhǎng)時(shí)間才能執(zhí)行完成,并非是這個(gè)測(cè)試應(yīng)該跑得快,而是它做的很復(fù)雜和很慢的工作造成的.如訪問遠(yuǎn)程網(wǎng)絡(luò)錯(cuò)誤,需要很久才能有反饋.如果你不想讓這種測(cè)試破壞你整個(gè)測(cè)試過程,你可能想跳過這個(gè)測(cè)試.當(dāng)然也有可能某個(gè)測(cè)試超出控制范圍而失敗.如W3C XInclude測(cè)試集中自動(dòng)識(shí)別一些JAVA不支持的Unicode代碼.為了防止這些測(cè)試總是通不過,可以使用標(biāo)記 @Ignore跳過這些測(cè),如下:

    // Java doesn't yet support the UTF-32BE and UTF32LE encodings
        @Ignore public void testUTF32BE() 
          throws ParsingException, IOException, XIncludeException {
          
            File input = new File(
              "data/xinclude/input/UTF32BE.xml"
            );
            Document doc = builder.build(input);
            Document result = XIncluder.resolve(doc);
            Document expectedResult = builder.build(
              new File(outputDir, "UTF32BE.xml")
            );
            assertEquals(expectedResult, result);
                    
        }

    test runner不會(huì)執(zhí)行這些測(cè)試,但會(huì)說明這些測(cè)試被跳過了。在命令行測(cè)試界面中,字母“I”會(huì)表示測(cè)試跳過,或“E”表示測(cè)試失敗,而不是用點(diǎn)”."表示成功.

    $ java -classpath .:junit.jar org.junit.runner.JUnitCore nu.xom.tests.XIncludeTest
    JUnit version 4.0rc1
    .....I..
    Time: 1.149
    
    OK (7 tests)

    要注意的是,假設(shè)這些測(cè)試由于某種理由放在最開始,如果你以后一直忽略這些測(cè)試,那些需要被測(cè)試的代碼可能有問題而不會(huì)被檢測(cè)到。因此忽略測(cè)試只是一個(gè)臨時(shí)解決方法,并不是一個(gè)解決任何問題的真正辦法。



    Back to top


    時(shí)間測(cè)試

    性能測(cè)試是單元測(cè)試中最頭疼的問題,JUnit 4也未完全解決此問題, 你可以在JUNIT4的測(cè)試方法中添加一個(gè)時(shí)間參數(shù)。如果測(cè)試時(shí)間超過參數(shù),則測(cè)試失敗。如下,如果測(cè)試時(shí)間超過0.5秒,則此測(cè)試失敗:

    
    @Test(timeout=500) public void retrieveAllElementsInDocument() {
        doc.query("http://*");
    } 

    除基準(zhǔn)性能測(cè)試外,時(shí)間測(cè)試在網(wǎng)絡(luò)測(cè)試方面也很有用.如果一個(gè)遠(yuǎn)端的主機(jī)或數(shù)據(jù)當(dāng)?shù)艋蛱憧梢蕴^此測(cè)試而不用阻塞在這里,好的測(cè)試集可以在作了一些改動(dòng)后很快的一遍一遍的執(zhí)行,可能一天數(shù)十次.設(shè)置一個(gè)超時(shí)讓測(cè)試更快的執(zhí)行,下面的示例中如果分析http://www.ibiblio.org/xml 的時(shí)間超過2秒,則測(cè)試失敗.

    
    @Test(timeout=2000) 
      public void remoteBaseRelativeResolutionWithDirectory()
       throws IOException, ParsingException {
          builder.build("http://www.ibiblio.org/xml");
      } 



    Back to top


    新的斷言

    JUnit 4 增加了兩上斷文方法用于比較數(shù)組:

    
    public static void assertEquals(Object[] expected, Object[] actual)
    public static void assertEquals(String message, Object[] expected, 
    Object[] actual)
    

    這兩個(gè)方法采用最直接方法比較,如果數(shù)組長(zhǎng)度相同,且每個(gè)對(duì)應(yīng)的元素相同,則比較成功,否則不成功.參數(shù)為空的情況也作了考慮.

    Back to top


    需要補(bǔ)充的地方

    JUnit 4是一個(gè)非常基本的框架,還不是以前版本的升級(jí)。JUNIT3的開發(fā)人員會(huì)發(fā)現(xiàn)有些功能沒有。

    • 最大的特點(diǎn)就是沒有GUI測(cè)試界面,當(dāng)測(cè)試正確時(shí)是綠色條,而出錯(cuò)時(shí)紅色的,你也可以在Eclipse中集成JUNIT使用,但JUNIT4既沒有AWT也沒有SWING的GUI測(cè)試界面;
    • 另一個(gè)讓人吃驚的是失敗(期望錯(cuò)誤)和錯(cuò)誤(未預(yù)計(jì)的異常錯(cuò)誤)沒有明顯區(qū)別,在JUNIT3中開發(fā)人員可以區(qū)分這兩種情況,而在JUNIT4中不行;
    • 最后一個(gè)特點(diǎn)是JUNIT中沒有用于建立一堆測(cè)試類的suite()方法,取而代之的是,采用變長(zhǎng)參數(shù)傳遞未知數(shù)量的測(cè)試給test runner。

    沒有GUI測(cè)試界面的確不方便,但其它改變簡(jiǎn)化了JUNIT的使用,從當(dāng)前JUNIT的操作手冊(cè)和FAQ的數(shù)量就知道,而JUNIT4的文檔將不會(huì)需要這么多。



    Back to top


    編譯和運(yùn)行JUnit 4

    現(xiàn)在JUnit 4還沒有發(fā)布編譯版本,如果想體驗(yàn)版本的樂趣,則需要從CVS中獲取源代碼。分支標(biāo)簽是"Version4" (see Resources ).要注意的是大部分文檔是根據(jù)JUNIT3編寫的,還未同步更新。需要Java 5才能編譯JUnit 4,因?yàn)榇罅渴褂昧藰?biāo)記,泛型其其它JDK5中的新特性。

    執(zhí)行測(cè)試的命令行方式與JUNIT3有點(diǎn)區(qū)別,你現(xiàn)在要使用 org.junit.runner.JUnitCore 類進(jìn)行測(cè)試,如下:

    
    $ java -classpath .:junit.jar org.junit.runner.JUnitCore 
      TestA TestB TestC...
    JUnit version 4.0rc1
    
    Time: 0.003
    
    OK (0 tests)

    兼容性

    Beck 和Gamma在努力保持后向和前向兼容性。JUnit 4可以直接運(yùn)行根據(jù)JUNIT3編寫的測(cè)試類,而不用任何修改,直接將各測(cè)試類的全名傳遞給test runner即可.test runner會(huì)根據(jù)不同的測(cè)試類調(diào)用不同的測(cè)試框架版本.

    后向兼容性有點(diǎn)麻煩,即在JUNIT3中執(zhí)行根據(jù)JUNIT4寫的測(cè)試類,之所以要這樣是因?yàn)樵谝粋€(gè)集成環(huán)境如Ecplise中,不需要升級(jí)到JUNIT4也可以測(cè)試JUNIT4的測(cè)試類,從而避免工具IDE的升級(jí)。為了讓JUNIT4的測(cè)試類在JUNI3中能執(zhí)行,你需要一個(gè)適配類JUnit4TestAdapter封裝JUNIT3的測(cè)試類,如下代碼:

    public static junit.framework.Test suite() {
      return new JUnit4TestAdapter(AssertionTest.class);    
    }

    而JAVA方面,JUNIT4一點(diǎn)兼容性都沒有,因?yàn)橥耆蕾囉贘DK5的新特性,因此不可能在JAVA1.4上面執(zhí)行JUNIT4。



    Back to top


    還有...

    JUnit 4遠(yuǎn)未結(jié)束,還有許多需要補(bǔ)充,如文檔,現(xiàn)在不推薦將以前的測(cè)試類升級(jí)到JUNIT4。當(dāng)然JUNIT4的開發(fā)速度很快,其計(jì)劃也很快會(huì)實(shí)現(xiàn),JAVA1.4的開發(fā)人員仍然可以使用JUNIT3.8,而使用JAVA5的人員可以考慮是否采用JUNIT4了,因?yàn)樵谔匦陨细m合。



    Back to top


    資源


    下載測(cè)試版本
    • JUnit 4: Download the newest version of JUnit the SourceForge CVS repository; be sure to use the branch tag "Version4."

    posted on 2005-09-15 18:02 Java,研究之路 閱讀(2068) 評(píng)論(4)  編輯  收藏
    Comments
    • # re: Junit4功能 先睹為快. (譯文)
      ^ Mustang ^
      Posted @ 2005-09-15 22:06
      好東西:)  回復(fù)  更多評(píng)論   
    • # re: Junit4功能 先睹為快. (譯文)
      emu
      Posted @ 2005-09-16 13:24
      好文章,值得一看!

      suite可以通過自嵌套來實(shí)現(xiàn)分層次遞降的測(cè)試每個(gè)包,用可變參數(shù)來管理的話能實(shí)現(xiàn)同樣的目的嗎?

        回復(fù)  更多評(píng)論   
    • # re: Junit4功能 先睹為快. (譯文)
      ghost
      Posted @ 2005-09-18 13:52
      check out的用戶名和密碼有么?
        回復(fù)  更多評(píng)論   
    • # re: Junit4功能 先睹為快. (譯文)
      margiex
      Posted @ 2005-09-19 16:11
      不好意思,我只是把文章翻譯了,,沒做過測(cè)試, 還沒來得及, JUNIT的站點(diǎn)上應(yīng)該有說明的吧.  回復(fù)  更多評(píng)論   

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
     
    主站蜘蛛池模板: 成人无码精品1区2区3区免费看| 国产午夜精品理论片免费观看 | 亚洲国产成人精品无码区二本| 免费人成在线观看网站品爱网日本| 亚洲精品偷拍视频免费观看| 久久精品国产亚洲AV高清热| 国产精品深夜福利免费观看 | 久视频精品免费观看99| 亚洲码欧美码一区二区三区| 国产精品亚洲二区在线观看| 一级毛片在线免费看| 亚洲精华国产精华精华液网站| 伊人婷婷综合缴情亚洲五月| 69成人免费视频| 久久精品无码专区免费| 久久久久精品国产亚洲AV无码| 亚洲精品国产va在线观看蜜芽| 91精品免费在线观看| v片免费在线观看| 亚洲无吗在线视频| 亚洲第一AV网站| 免费在线观看亚洲| 91频在线观看免费大全| 日韩精品无码免费专区午夜不卡| 亚洲精品永久在线观看| 亚洲一本综合久久| 亚洲人成电影网站国产精品| 18禁成年无码免费网站无遮挡| 国产猛男猛女超爽免费视频| 美女被免费网站视频在线| 91亚洲精品自在在线观看| 亚洲高清专区日韩精品| 亚洲国产精品一区二区九九 | 午夜免费福利在线| 久久99国产乱子伦精品免费| 国产97视频人人做人人爱免费| 在线观看国产一区亚洲bd| 亚洲影视自拍揄拍愉拍| 久久久无码精品亚洲日韩按摩 | 区三区激情福利综合中文字幕在线一区亚洲视频1 | 国产成人精品亚洲2020|