免费高清特黄a大片,九一h片在线免费看,a免费国产一级特黄aa大,国产精品国产主播在线观看,成人精品一区久久久久,一级特黄aa大片,俄罗斯无遮挡一级毛片

分享

JUnit4 詳解

 思邁爾圖書(shū)館 2013-12-11

JUnit4是JUnit框架有史以來(lái)的最大改進(jìn),其主要目標(biāo)便是利用Java5的Annotation特性簡(jiǎn)化測(cè)試用例的編寫(xiě)。

先簡(jiǎn)單解釋一下什么是Annotation,這個(gè)單詞一般是翻譯成元數(shù)據(jù)。元數(shù)據(jù)是什么?元數(shù)據(jù)就是描述數(shù)據(jù)的數(shù)據(jù)。也就是說(shuō),這個(gè)東西在Java里面可以用來(lái)和public、static等關(guān)鍵字一樣來(lái)修飾類(lèi)名、方法名、變量名。修飾的作用描述這個(gè)數(shù)據(jù)是做什么用的,差不多和public描述這個(gè)數(shù)據(jù)是公有的一樣。想具體了解可以看Core    Java2。廢話(huà)不多說(shuō)了,直接進(jìn)入正題。

我們先看一下在JUnit 3中我們是怎樣寫(xiě)一個(gè)單元測(cè)試的。比如下面一個(gè)類(lèi):
public class AddOperation {
      public int add(int x,int y){
          return x+y;
      }
}

我們要測(cè)試add這個(gè)方法,我們寫(xiě)單元測(cè)試得這么寫(xiě):
import junit.framework.TestCase;
import static org.junit.Assert.*;
public class AddOperationTest extends TestCase{

      public void setUp() throws Exception {
      }

      public void tearDown() throws Exception {
      }

      public void testAdd() {
          System.out.println(\"add\");
          int x = 0;
          int y = 0;
          AddOperation instance = new AddOperation();
          int expResult = 0;
          int result = instance.add(x, y);
          assertEquals(expResult, result);
      }
}

可以看到上面的類(lèi)使用了JDK5中的靜態(tài)導(dǎo)入,這個(gè)相對(duì)來(lái)說(shuō)就很簡(jiǎn)單,只要在import關(guān)鍵字后面加上static關(guān)鍵字,就可以把后面的類(lèi)的static的變量和方法導(dǎo)入到這個(gè)類(lèi)中,調(diào)用的時(shí)候和調(diào)用自己的方法沒(méi)有任何區(qū)別。


我們可以看到上面那個(gè)單元測(cè)試有一些比較霸道的地方,表現(xiàn)在:
1.單元測(cè)試類(lèi)必須繼承自TestCase。
2.要測(cè)試的方法必須以test開(kāi)頭。

如果上面那個(gè)單元測(cè)試在JUnit 4中寫(xiě)就不會(huì)這么復(fù)雜。代碼如下:
import junit.framework.TestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

/**
*
* @author bean
*/
public class AddOperationTest extends TestCase{
    
      public AddOperationTest() {
      }

      @Before
      public void setUp() throws Exception {
      }

      @After
      public void tearDown() throws Exception {
      }

      @Test
      public void add() {
          System.out.println(\"add\");
          int x = 0;
          int y = 0;
          AddOperation instance = new AddOperation();
          int expResult = 0;
          int result = instance.add(x, y);
          assertEquals(expResult, result);
      }
    
}
我們可以看到,采用Annotation的JUnit已經(jīng)不會(huì)霸道的要求你必須繼承自TestCase了,而且測(cè)試方法也不必以test開(kāi)頭了,只要以@Test元數(shù)據(jù)來(lái)描述即可。
從上面的例子可以看到在JUnit 4中還引入了一些其他的元數(shù)據(jù),下面一一介紹:
@Before:
使用了該元數(shù)據(jù)的方法在每個(gè)測(cè)試方法執(zhí)行之前都要執(zhí)行一次。

@After:
使用了該元數(shù)據(jù)的方法在每個(gè)測(cè)試方法執(zhí)行之后要執(zhí)行一次。

注意:@Before和@After標(biāo)示的方法只能各有一個(gè)。這個(gè)相當(dāng)于取代了JUnit以前版本中的setUp和tearDown方法,當(dāng)然你還可以繼續(xù)叫這個(gè)名字,不過(guò)JUnit不會(huì)霸道的要求你這么做了。

@Test(expected=*.class)
在JUnit4.0之前,對(duì)錯(cuò)誤的測(cè)試,我們只能通過(guò)fail來(lái)產(chǎn)生一個(gè)錯(cuò)誤,并在try塊里面assertTrue(true)來(lái)測(cè)試?,F(xiàn)在,通過(guò)@Test元數(shù)據(jù)中的expected屬性。expected屬性的值是一個(gè)異常的類(lèi)型

@Test(timeout=xxx):
該元數(shù)據(jù)傳入了一個(gè)時(shí)間(毫秒)給測(cè)試方法,
如果測(cè)試方法在制定的時(shí)間之內(nèi)沒(méi)有運(yùn)行完,則測(cè)試也失敗。

@ignore:
該元數(shù)據(jù)標(biāo)記的測(cè)試方法在測(cè)試中會(huì)被忽略。當(dāng)測(cè)試的方法還沒(méi)有實(shí)現(xiàn),或者測(cè)試的方法已經(jīng)過(guò)時(shí),或者在某種條件下才能測(cè)試該方法(比如需要一個(gè)數(shù)據(jù)庫(kù)聯(lián)接,而在本地測(cè)試的時(shí)候,數(shù)據(jù)庫(kù)并沒(méi)有連接),那么使用該標(biāo)簽來(lái)標(biāo)示這個(gè)方法。同時(shí),你可以為該標(biāo)簽傳遞一個(gè)String的參數(shù),來(lái)表明為什么會(huì)忽略這個(gè)測(cè)試方法。比如:@lgnore(“該方法還沒(méi)有實(shí)現(xiàn)”),在執(zhí)行的時(shí)候,僅會(huì)報(bào)告該方法沒(méi)有實(shí)現(xiàn),而不會(huì)運(yùn)行測(cè)試方法。


 


在Eclipse中使用JUnit4進(jìn)測(cè)試(初級(jí)

 

我們?cè)诰帉?xiě)大型程序的時(shí)候,需要寫(xiě)成千上萬(wàn)個(gè)方法或函數(shù),這些函數(shù)的功能可能很強(qiáng)大,但我們?cè)诔绦蛑兄挥玫皆摵瘮?shù)的一小部分功能,并且經(jīng)過(guò)調(diào)試可以確定,這一小部分功能是正確的。但是,我們同時(shí)應(yīng)該確保每一個(gè)函數(shù)都完全正確,因?yàn)槿绻覀兘窈笕绻麑?duì)程序進(jìn)行擴(kuò)展,用到了某個(gè)函數(shù)的其他功能,而這個(gè)功能有bug的話(huà),那絕對(duì)是一件非常郁悶的事情。所以說(shuō),每編寫(xiě)完一個(gè)函數(shù)之后,都應(yīng)該對(duì)這個(gè)函數(shù)的方方面面進(jìn)行測(cè)試,這樣的測(cè)試我們稱(chēng)之為單元測(cè)試。傳統(tǒng)的編程方式,進(jìn)行單元測(cè)試是一件很麻煩的事情,你要重新寫(xiě)另外一個(gè)程序,在該程序中調(diào)用你需要測(cè)試的方法,并且仔細(xì)觀察運(yùn)行結(jié)果,看看是否有錯(cuò)。正因?yàn)槿绱寺闊?,所以程序員們編寫(xiě)單元測(cè)試的熱情不是很高。于是有一個(gè)牛人推出了單元測(cè)試包,大大簡(jiǎn)化了進(jìn)行單元測(cè)試所要做的工作,這就是JUnit4。本文簡(jiǎn)要介紹一下在Eclipse3.2中使用JUnit4進(jìn)行單元測(cè)試的方法。

 

首先,我們來(lái)一個(gè)傻瓜式速成教程,不要問(wèn)為什么,F(xiàn)ollow Me,先來(lái)體驗(yàn)一下單元測(cè)試的快感!

 

首先新建一個(gè)項(xiàng)目叫JUnit_Test,我們編寫(xiě)一個(gè)Calculator類(lèi),這是一個(gè)能夠簡(jiǎn)單實(shí)現(xiàn)加減乘除、平方、開(kāi)方的計(jì)算器類(lèi),然后對(duì)這些功能進(jìn)行單元測(cè)試。這個(gè)類(lèi)并不是很完美,我們故意保留了一些Bug用于演示,這些Bug在注釋中都有說(shuō)明。該類(lèi)代碼如下:

 

package andycpp;

 

public class Calculator ...{

    private static int result; // 靜態(tài)變量,用于存儲(chǔ)運(yùn)行結(jié)果

    public void add(int n) ...{

        result = result + n;

    }

    public void substract(int n) ...{

        result = result - 1;  //Bug: 正確的應(yīng)該是 result =result-n

    }

    public void multiply(int n) ...{

    }         // 此方法尚未寫(xiě)好

    public void divide(int n) ...{

        result = result / n;

    }

    public void square(int n) ...{

        result = n * n;

    }

    public void squareRoot(int n) ...{

        for (; ;) ;            //Bug : 死循環(huán)

    }

    public void clear() ...{     // 將結(jié)果清零

        result = 0;

    }

    public int getResult() ...{

        return result;

    }

}

 

 

第二步,將JUnit4單元測(cè)試包引入這個(gè)項(xiàng)目:在該項(xiàng)目上點(diǎn)右鍵,點(diǎn)“屬性”,如圖:

 

 

 

 

 

在彈出的屬性窗口中,首先在左邊選擇“Java Build Path”,然后到右上選擇“Libraries”標(biāo)簽,之后在最右邊點(diǎn)擊“Add Library…”按鈕,如下圖所示:

 

 

然后在新彈出的對(duì)話(huà)框中選擇JUnit4并點(diǎn)擊確定,如上圖所示,JUnit4軟件包就被包含進(jìn)我們這個(gè)項(xiàng)目了。

 

    第三步,生成JUnit測(cè)試框架:在Eclipse的Package Explorer中用右鍵點(diǎn)擊該類(lèi)彈出菜單,選擇“New à JUnit Test Case”。如下圖所示:

 

 

 

在彈出的對(duì)話(huà)框中,進(jìn)行相應(yīng)的選擇,如下圖所示:

 

 

    點(diǎn)擊“下一步”后,系統(tǒng)會(huì)自動(dòng)列出你這個(gè)類(lèi)中包含的方法,選擇你要進(jìn)行測(cè)試的方法。此例中,我們僅對(duì)“加、減、乘、除”四個(gè)方法進(jìn)行測(cè)試。如下圖所示:

 

 

 

之后系統(tǒng)會(huì)自動(dòng)生成一個(gè)新類(lèi)CalculatorTest,里面包含一些空的測(cè)試用例。你只需要將這些測(cè)試用例稍作修改即可使用。完整的CalculatorTest代碼如下:

 

package andycpp;

 

import static org.junit.Assert.*;

import org.junit.Before;

import org.junit.Ignore;

import org.junit.Test;

 

public class CalculatorTest ...{

 

    private static Calculator calculator = new Calculator();

   

    @Before

    public void setUp() throws Exception ...{

        calculator.clear();

    }

 

    @Test

    public void testAdd() ...{

        calculator.add(2);

        calculator.add(3);

        assertEquals(5, calculator.getResult());

    }

 

    @Test

    public void testSubstract() ...{

        calculator.add(10);

        calculator.substract(2);

        assertEquals(8, calculator.getResult());

    }

 

    @Ignore("Multiply() Not yet implemented")

    @Test

    public void testMultiply() ...{

    }

 

    @Test

    public void testDivide() ...{

        calculator.add(8);

        calculator.divide(2);

        assertEquals(4, calculator.getResult());

    }

}

 

第四步,運(yùn)行測(cè)試代碼:按照上述代碼修改完畢后,我們?cè)贑alculatorTest類(lèi)上點(diǎn)右鍵,選擇“Run As à JUnit Test”來(lái)運(yùn)行我們的測(cè)試,如下圖所示:

 

 

 

運(yùn)行結(jié)果如下:

 

 

 

 

 

進(jìn)度條是紅顏色表示發(fā)現(xiàn)錯(cuò)誤,具體的測(cè)試結(jié)果在進(jìn)度條上面有表示“共進(jìn)行了4個(gè)測(cè)試,其中1個(gè)測(cè)試被忽略,一個(gè)測(cè)試失敗”

 

            至此,我們已經(jīng)完整體驗(yàn)了在Eclipse中使用JUnit的方法。在接下來(lái)的文章中,我會(huì)詳細(xì)解釋測(cè)試代碼中的每一個(gè)細(xì)節(jié)!


在Eclipse中使用JUnit4進(jìn)測(cè)試(中級(jí)

 

我們繼續(xù)對(duì)初級(jí)篇中的例子進(jìn)行分析。初級(jí)篇中我們使用Eclipse自動(dòng)生成了一個(gè)測(cè)試框架,在這篇文章中,我們來(lái)仔細(xì)分析一下這個(gè)測(cè)試框架中的每一個(gè)細(xì)節(jié),知其然更要知其所以然,才能更加熟練地應(yīng)用JUnit4。

 

一、包含必要地Package

 

在測(cè)試類(lèi)中用到了JUnit4框架,自然要把相應(yīng)地Package包含進(jìn)來(lái)。最主要地一個(gè)Package就是org.junit.*。把它包含進(jìn)來(lái)之后,絕大部分功能就有了。還有一句話(huà)也非常地重要“import static org.junit.Assert.*;”,我們?cè)跍y(cè)試的時(shí)候使用的一系列assertEquals方法就來(lái)自這個(gè)包。大家注意一下,這是一個(gè)靜態(tài)包含(static),是JDK5中新增添的一個(gè)功能。也就是說(shuō),assertEquals是Assert類(lèi)中的一系列的靜態(tài)方法,一般的使用方式是Assert. assertEquals(),但是使用了靜態(tài)包含后,前面的類(lèi)名就可以省略了,使用起來(lái)更加的方便。

 

二、測(cè)試類(lèi)的聲明

 

大家注意到,我們的測(cè)試類(lèi)是一個(gè)獨(dú)立的類(lèi),沒(méi)有任何父類(lèi)。測(cè)試類(lèi)的名字也可以任意命名,沒(méi)有任何局限性。所以我們不能通過(guò)類(lèi)的聲明來(lái)判斷它是不是一個(gè)測(cè)試類(lèi),它與普通類(lèi)的區(qū)別在于它內(nèi)部的方法的聲明,我們接著會(huì)講到。

 

三、創(chuàng)建一個(gè)待測(cè)試的對(duì)象。

 

你要測(cè)試哪個(gè)類(lèi),那么你首先就要?jiǎng)?chuàng)建一個(gè)該類(lèi)的對(duì)象。正如上一篇文章中的代碼:

 

private static Calculator calculator = new Calculator();

 

 

為了測(cè)試Calculator類(lèi),我們必須創(chuàng)建一個(gè)calculator對(duì)象。

 

四、測(cè)試方法的聲明

 

在測(cè)試類(lèi)中,并不是每一個(gè)方法都是用于測(cè)試的,你必須使用“標(biāo)注”來(lái)明確表明哪些是測(cè)試方法?!皹?biāo)注”也是JDK5的一個(gè)新特性,用在此處非常恰當(dāng)。我們可以看到,在某些方法的前有@Before、@Test、@Ignore等字樣,這些就是標(biāo)注,以一個(gè)“@”作為開(kāi)頭。這些標(biāo)注都是JUnit4自定義的,熟練掌握這些標(biāo)注的含義非常重要。

 

五、編寫(xiě)一個(gè)簡(jiǎn)單的測(cè)試方法。

 

首先,你要在方法的前面使用@Test標(biāo)注,以表明這是一個(gè)測(cè)試方法。對(duì)于方法的聲明也有如下要求:名字可以隨便取,沒(méi)有任何限制,但是返回值必須為void,而且不能有任何參數(shù)。如果違反這些規(guī)定,會(huì)在運(yùn)行時(shí)拋出一個(gè)異常。至于方法內(nèi)該寫(xiě)些什么,那就要看你需要測(cè)試些什么了。比如:

 

 

    @Test

 

    public void testAdd() ...{

 

          calculator.add(2);

 

          calculator.add(3);

 

          assertEquals(5, calculator.getResult());

 

    }

 

 

我們想測(cè)試一下“加法”功能時(shí)候正確,就在測(cè)試方法中調(diào)用幾次add函數(shù),初始值為0,先加2,再加3,我們期待的結(jié)果應(yīng)該是5。如果最終實(shí)際結(jié)果也是5,則說(shuō)明add方法是正確的,反之說(shuō)明它是錯(cuò)的。assertEquals(5, calculator.getResult());就是來(lái)判斷期待結(jié)果和實(shí)際結(jié)果是否相等,第一個(gè)參數(shù)填寫(xiě)期待結(jié)果,第二個(gè)參數(shù)填寫(xiě)實(shí)際結(jié)果,也就是通過(guò)計(jì)算得到的結(jié)果。這樣寫(xiě)好之后,JUnit會(huì)自動(dòng)進(jìn)行測(cè)試并把測(cè)試結(jié)果反饋給用戶(hù)。

 

六、忽略測(cè)試某些尚未完成的方法。

 

如果你在寫(xiě)程序前做了很好的規(guī)劃,那么哪些方法是什么功能都應(yīng)該實(shí)現(xiàn)定下來(lái)。因此,即使該方法尚未完成,他的具體功能也是確定的,這也就意味著你可以為他編寫(xiě)測(cè)試用例。但是,如果你已經(jīng)把該方法的測(cè)試用例寫(xiě)完,但該方法尚未完成,那么測(cè)試的時(shí)候一定是“失敗”。這種失敗和真正的失敗是有區(qū)別的,因此JUnit提供了一種方法來(lái)區(qū)別他們,那就是在這種測(cè)試函數(shù)的前面加上@Ignore標(biāo)注,這個(gè)標(biāo)注的含義就是“某些方法尚未完成,暫不參與此次測(cè)試”。這樣的話(huà)測(cè)試結(jié)果就會(huì)提示你有幾個(gè)測(cè)試被忽略,而不是失敗。一旦你完成了相應(yīng)函數(shù),只需要把@Ignore標(biāo)注刪去,就可以進(jìn)行正常的測(cè)試。

 

七、Fixture(暫且翻譯為“固定代碼段”)

 

Fixture的含義就是“在某些階段必然被調(diào)用的代碼”。比如我們上面的測(cè)試,由于只聲明了一個(gè)Calculator對(duì)象,他的初始值是0,但是測(cè)試完加法操作后,他的值就不是0了;接下來(lái)測(cè)試減法操作,就必然要考慮上次加法操作的結(jié)果。這絕對(duì)是一個(gè)很糟糕的設(shè)計(jì)!我們非常希望每一個(gè)測(cè)試都是獨(dú)立的,相互之間沒(méi)有任何耦合度。因此,我們就很有必要在執(zhí)行每一個(gè)測(cè)試之前,對(duì)Calculator對(duì)象進(jìn)行一個(gè)“復(fù)原”操作,以消除其他測(cè)試造成的影響。因此,“在任何一個(gè)測(cè)試執(zhí)行之前必須執(zhí)行的代碼”就是一個(gè)Fixture,我們用@Before來(lái)標(biāo)注它,如前面例子所示:

 

 

      @Before

 

      public void setUp() throws Exception ...{

 

           calculator.clear();

 

      }

 

 

這里不在需要@Test標(biāo)注,因?yàn)檫@不是一個(gè)test,而是一個(gè)Fixture。同理,如果“在任何測(cè)試執(zhí)行之后需要進(jìn)行的收尾工作”也是一個(gè)Fixture,使用@After來(lái)標(biāo)注。由于本例比較簡(jiǎn)單,沒(méi)有用到此功能。

 


在Eclipse中使用JUnit4進(jìn)測(cè)試(高級(jí)

 

一、高級(jí)Fixture

 

上一篇文章中我們介紹了兩個(gè)Fixture標(biāo)注,分別是@Before和@After,我們來(lái)看看他們是否適合完成如下功能:有一個(gè)類(lèi)是負(fù)責(zé)對(duì)大文件(超過(guò)500兆)進(jìn)行讀寫(xiě),他的每一個(gè)方法都是對(duì)文件進(jìn)行操作。換句話(huà)說(shuō),在調(diào)用每一個(gè)方法之前,我們都要打開(kāi)一個(gè)大文件并讀入文件內(nèi)容,這絕對(duì)是一個(gè)非常耗費(fèi)時(shí)間的操作。如果我們使用@Before和@After,那么每次測(cè)試都要讀取一次文件,效率及其低下。這里我們所希望的是在所有測(cè)試一開(kāi)始讀一次文件,所有測(cè)試結(jié)束之后釋放文件,而不是每次測(cè)試都讀文件。JUnit的作者顯然也考慮到了這個(gè)問(wèn)題,它給出了@BeforeClass 和 @AfterClass兩個(gè)Fixture來(lái)幫我們實(shí)現(xiàn)這個(gè)功能。從名字上就可以看出,用這兩個(gè)Fixture標(biāo)注的函數(shù),只在測(cè)試用例初始化時(shí)執(zhí)行@BeforeClass方法,當(dāng)所有測(cè)試執(zhí)行完畢之后,執(zhí)行@AfterClass進(jìn)行收尾工作。在這里要注意一下,每個(gè)測(cè)試類(lèi)只能有一個(gè)方法被標(biāo)注為@BeforeClass 或 @AfterClass,并且該方法必須是Public和Static的。

 

二、限時(shí)測(cè)試。

 

還記得我在初級(jí)篇中給出的例子嗎,那個(gè)求平方根的函數(shù)有Bug,是個(gè)死循環(huán):

 

 

    public void squareRoot(int n) ...{

 

        for (; ;) ;                 //Bug : 死循環(huán)

 

    }

 

 

如果測(cè)試的時(shí)候遇到死循環(huán),你的臉上絕對(duì)不會(huì)露出笑容。因此,對(duì)于那些邏輯很復(fù)雜,循環(huán)嵌套比較深的程序,很有可能出現(xiàn)死循環(huán),因此一定要采取一些預(yù)防措施。限時(shí)測(cè)試是一個(gè)很好的解決方案。我們給這些測(cè)試函數(shù)設(shè)定一個(gè)執(zhí)行時(shí)間,超過(guò)了這個(gè)時(shí)間,他們就會(huì)被系統(tǒng)強(qiáng)行終止,并且系統(tǒng)還會(huì)向你匯報(bào)該函數(shù)結(jié)束的原因是因?yàn)槌瑫r(shí),這樣你就可以發(fā)現(xiàn)這些Bug了。要實(shí)現(xiàn)這一功能,只需要給@Test標(biāo)注加一個(gè)參數(shù)即可,代碼如下:

 

@Test(timeout = 1000)

public void squareRoot() ...{

        calculator.squareRoot(4);

        assertEquals(2, calculator.getResult());

}

 

Timeout參數(shù)表明了你要設(shè)定的時(shí)間,單位為毫秒,因此1000就代表1秒。

 

三、 測(cè)試異常

JAVA中的異常處理也是一個(gè)重點(diǎn),因此你經(jīng)常會(huì)編寫(xiě)一些需要拋出異常的函數(shù)。那么,如果你覺(jué)得一個(gè)函數(shù)應(yīng)該拋出異常,但是它沒(méi)拋出,這算不算Bug呢?這當(dāng)然是Bug,并JUnit也考慮到了這一點(diǎn),來(lái)幫助我們找到這種Bug。例如,我們寫(xiě)的計(jì)算器類(lèi)有除法功能,如果除數(shù)是一個(gè)0,那么必然要拋出“除0異?!?。因此,我們很有必要對(duì)這些進(jìn)行測(cè)試。代碼如下:

  @Test(expected = ArithmeticException.class)

  public void divideByZero() ...{

calculator.divide(0);

   }

 

如上述代碼所示,我們需要使用@Test標(biāo)注的expected屬性,將我們要檢驗(yàn)的異常傳遞給他,這樣JUnit框架就能自動(dòng)幫我們檢測(cè)是否拋出了我們指定的異常。

 

四、     Runner (運(yùn)行器)

大家有沒(méi)有想過(guò)這個(gè)問(wèn)題,當(dāng)你把測(cè)試代碼提交給JUnit框架后,框架如何來(lái)運(yùn)行你的代碼呢?答案就是——Runner。在JUnit中有很多個(gè)Runner,他們負(fù)責(zé)調(diào)用你的測(cè)試代碼,每一個(gè)Runner都有各自的特殊功能,你要根據(jù)需要選擇不同的Runner來(lái)運(yùn)行你的測(cè)試代碼??赡苣銜?huì)覺(jué)得奇怪,前面我們寫(xiě)了那么多測(cè)試,并沒(méi)有明確指定一個(gè)Runner???這是因?yàn)镴Unit中有一個(gè)默認(rèn)Runner,如果你沒(méi)有指定,那么系統(tǒng)自動(dòng)使用默認(rèn)Runner來(lái)運(yùn)行你的代碼。換句話(huà)說(shuō),下面兩段代碼含義是完全一樣的:

import org.junit.internal.runners.TestClassRunner;

import org.junit.runner.RunWith;

 

//使用了系統(tǒng)默認(rèn)的TestClassRunner,與下面代碼完全一樣

public class CalculatorTest ...{...} 

 

@RunWith(TestClassRunner.class)

public class CalculatorTest ...{...}

 

從上述例子可以看出,要想指定一個(gè)Runner,需要使用@RunWith標(biāo)注,并且把你所指定的Runner作為參數(shù)傳遞給它。另外一個(gè)要注意的是,@RunWith是用來(lái)修飾類(lèi)的,而不是用來(lái)修飾函數(shù)的。只要對(duì)一個(gè)類(lèi)指定了Runner,那么這個(gè)類(lèi)中的所有函數(shù)都被這個(gè)Runner來(lái)調(diào)用。最后,不要忘了包含相應(yīng)的Package哦,上面的例子對(duì)這一點(diǎn)寫(xiě)的很清楚了。接下來(lái),我會(huì)向你們展示其他Runner的特有功能。

 

五、 參數(shù)化測(cè)試。

你可能遇到過(guò)這樣的函數(shù),它的參數(shù)有許多特殊值,或者說(shuō)他的參數(shù)分為很多個(gè)區(qū)域。比如,一個(gè)對(duì)考試分?jǐn)?shù)進(jìn)行評(píng)價(jià)的函數(shù),返回值分別為“優(yōu)秀,良好,一般,及格,不及格”,因此你在編寫(xiě)測(cè)試的時(shí)候,至少要寫(xiě)5個(gè)測(cè)試,把這5中情況都包含了,這確實(shí)是一件很麻煩的事情。我們還使用我們先前的例子,測(cè)試一下“計(jì)算一個(gè)數(shù)的平方”這個(gè)函數(shù),暫且分三類(lèi):正數(shù)、0、負(fù)數(shù)。測(cè)試代碼如下:

 

import org.junit.AfterClass;

import org.junit.Before;

import org.junit.BeforeClass;

import org.junit.Test;

import static org.junit.Assert.*;

 

public class AdvancedTest ...{

private static Calculator calculator = new Calculator();

    @Before

public void clearCalculator() ...{

        calculator.clear();

}

 

    @Test

public void square1() ...{

        calculator.square(2);

        assertEquals(4, calculator.getResult());

}    

 

@Test   

public void square2() ...{

        calculator.square(0);

        assertEquals(0, calculator.getResult());

}


    @Test   

public void square3() ...{

        calculator.square(-3);

        assertEquals(9, calculator.getResult());

}

 }

 

為了簡(jiǎn)化類(lèi)似的測(cè)試,JUnit4提出了“參數(shù)化測(cè)試”的概念,只寫(xiě)一個(gè)測(cè)試函數(shù),把這若干種情況作為參數(shù)傳遞進(jìn)去,一次性的完成測(cè)試。代碼如下:

 

import static org.junit.Assert.assertEquals;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.junit.runners.Parameterized;

import org.junit.runners.Parameterized.Parameters;

import java.util.Arrays;

import java.util.Collection;

 

@RunWith(Parameterized.class)

public class SquareTest ...{

    private static Calculator calculator = new Calculator();

private int param;

private int result;    

 

@Parameters   

public static Collection data() ...{

        return Arrays.asList(new Object[][]...{

                ...{2, 4},

                ...{0, 0},

                ...{-3, 9},

        });

}

 

//構(gòu)造函數(shù),對(duì)變量進(jìn)行初始化

public SquareTest(int param, int result) ...{

        this.param = param;
            this.result = result;

}

 

@Test   

public void square() ...{

        calculator.square(param);

        assertEquals(result, calculator.getResult());

    }

 }

 

下面我們對(duì)上述代碼進(jìn)行分析。首先,你要為這種測(cè)試專(zhuān)門(mén)生成一個(gè)新的類(lèi),而不能與其他測(cè)試共用同一個(gè)類(lèi),此例中我們定義了一個(gè)SquareTest類(lèi)。然后,你要為這個(gè)類(lèi)指定一個(gè)Runner,而不能使用默認(rèn)的Runner了,因?yàn)樘厥獾墓δ芤锰厥獾腞unner嘛。@RunWith(Parameterized.class)這條語(yǔ)句就是為這個(gè)類(lèi)指定了一個(gè)ParameterizedRunner。第二步,定義一個(gè)待測(cè)試的類(lèi),并且定義兩個(gè)變量,一個(gè)用于存放參數(shù),一個(gè)用于存放期待的結(jié)果。接下來(lái),定義測(cè)試數(shù)據(jù)的集合,也就是上述的data()方法,該方法可以任意命名,但是必須使用@Parameters標(biāo)注進(jìn)行修飾。這個(gè)方法的框架就不予解釋了,大家只需要注意其中的數(shù)據(jù),是一個(gè)二維數(shù)組,數(shù)據(jù)兩兩一組,每組中的這兩個(gè)數(shù)據(jù),一個(gè)是參數(shù),一個(gè)是你預(yù)期的結(jié)果。比如我們的第一組{2, 4},2就是參數(shù),4就是預(yù)期的結(jié)果。這兩個(gè)數(shù)據(jù)的順序無(wú)所謂,誰(shuí)前誰(shuí)后都可以。之后是構(gòu)造函數(shù),其功能就是對(duì)先前定義的兩個(gè)參數(shù)進(jìn)行初始化。在這里你可要注意一下參數(shù)的順序了,要和上面的數(shù)據(jù)集合的順序保持一致。如果前面的順序是{參數(shù),期待的結(jié)果},那么你構(gòu)造函數(shù)的順序也要是“構(gòu)造函數(shù)(參數(shù), 期待的結(jié)果)”,反之亦然。最后就是寫(xiě)一個(gè)簡(jiǎn)單的測(cè)試?yán)耍颓懊娼榻B過(guò)的寫(xiě)法完全一樣,在此就不多說(shuō)。

 

六、 打包測(cè)試。

通過(guò)前面的介紹我們可以感覺(jué)到,在一個(gè)項(xiàng)目中,只寫(xiě)一個(gè)測(cè)試類(lèi)是不可能的,我們會(huì)寫(xiě)出很多很多個(gè)測(cè)試類(lèi)??墒沁@些測(cè)試類(lèi)必須一個(gè)一個(gè)的執(zhí)行,也是比較麻煩的事情。鑒于此,JUnit為我們提供了打包測(cè)試的功能,將所有需要運(yùn)行的測(cè)試類(lèi)集中起來(lái),一次性的運(yùn)行完畢,大大的方便了我們的測(cè)試工作。具體代碼如下:

 

import org.junit.runner.RunWith;

import org.junit.runners.Suite;

 

@RunWith(Suite.class)

@Suite.SuiteClasses(...{CalculatorTest.class, SquareTest.class})

public class AllCalculatorTests ...{}

 

大家可以看到,這個(gè)功能也需要使用一個(gè)特殊的Runner,因此我們需要向@RunWith標(biāo)注傳遞一個(gè)參數(shù)Suite.class。同時(shí),我們還需要另外一個(gè)標(biāo)注@Suite.SuiteClasses,來(lái)表明這個(gè)類(lèi)是一個(gè)打包測(cè)試類(lèi)。我們把需要打包的類(lèi)作為參數(shù)傳遞給該標(biāo)注就可以了。有了這兩個(gè)標(biāo)注之后,就已經(jīng)完整的表達(dá)了所有的含義,因此下面的類(lèi)已經(jīng)無(wú)關(guān)緊要,隨便起一個(gè)類(lèi)名,內(nèi)容全部為空既可。

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多