溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

利用junit4怎么實(shí)現(xiàn)一個(gè)單元測試功能

發(fā)布時(shí)間:2020-12-08 16:05:15 來源:億速云 閱讀:163 作者:Leah 欄目:編程語言

今天就跟大家聊聊有關(guān)利用junit4怎么實(shí)現(xiàn)一個(gè)單元測試功能,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

Junit單元測試框架是Java程序開發(fā)必備的測試?yán)?,現(xiàn)在最常用的就是Junit4了,在Junit4中所有的測試用例都使用了注解的形式,這比Junit3更加靈活與方便。之前在公司的關(guān)于單元測試的培訓(xùn)課程中,講師僅僅講述了Junit4的基本的與生命周期相關(guān)的注解的使用,主要包括@BeforeClass、@Before、@Test、@After、@AfterClass這些注解,這些在應(yīng)付普通簡單的單元測試已經(jīng)足夠,然而有很多更加復(fù)雜且也會(huì)經(jīng)常遇到的測試需求依靠這些生命周期注解并不能完成!因此這篇分享將為您呈現(xiàn)Junit4的另一片新大陸,且看陳述…

       其實(shí),在單元測試培訓(xùn)課程中,講師并沒有講到Junit4的核心,例如為什么Junit沒有main()方法就能運(yùn)行(因?yàn)槲覀冎罒o論是什么程序都必須得有一個(gè)程序入口,而它通常是main);在例如Junit的核心組成部分是什么?如何更改Junit在運(yùn)行單元測試時(shí)獲取數(shù)據(jù)和執(zhí)行測試的行為?更具體一點(diǎn),如果我要為一個(gè)需要兩個(gè)參數(shù)的方法進(jìn)行測試,如何使用我所提供的參數(shù)的所有排列組合對(duì)方法進(jìn)行測試?如果我需要在茫茫的測試用例中只測試與特定類相關(guān)的用例該怎么做…….

      在這之前,先糾正一點(diǎn)------Junit4可以直接運(yùn)行我們的某個(gè)方法,沒有main入口函數(shù)是斷然不行的。正如我之前給我們組的一個(gè)妹子講Spring的時(shí)候告訴她,在測試方法中,對(duì)測試方法所在的類添加Spring的 (Compent注解或者為該類的成員變量添加)Resource注解并沒有什么卵用,即Spring根本不會(huì)來掃描這個(gè)測試類,更不會(huì)為這個(gè)類注入屬性值。為什么這么說呢?因?yàn)镾pring是在測試類中由被@Before標(biāo)注的方法所啟動(dòng)的,這時(shí)候,JVM已經(jīng)將此測試類實(shí)例化了,而這并不是由Spring實(shí)例化的,Spring晚了一步,所以在Spring的容器中并沒有此類的實(shí)例。那么Junit4真的有main方法嗎?沒錯(cuò),既然它能直接運(yùn)行我們的方法,那它必然自己為JVM提供了程序入口。其實(shí)在org.junit.runner包下,有個(gè)JUnitCore.class,其中就有一個(gè) 標(biāo)準(zhǔn)的main方法,這就是JUnit入口函數(shù)。如此看來,它其實(shí)和我們直接在自己的main方法中跑我們要測試的方法在本質(zhì)上是一樣的。

     接下來,我要說的就是Junit測試框架的新大陸,或者說是其核心組件,也正是講師所沒有講到但卻十分有用的東西------Runner,即Junit的運(yùn)行器!

     Runner只是一個(gè)抽象類,表示用于運(yùn)行Junit測試用例的工具,通過它可以運(yùn)行測試并通知Notifier運(yùn)行的結(jié)果。通常我們可以在待測方法所在的類之上使用@RunWith注解來為這個(gè)測試類指定一個(gè)特定的Runner。不過在很多情況下,我們并沒有這么做,那是因?yàn)椋覀兪褂昧薐unit的默認(rèn)Runnner------BlockJunit4ClassRunner。當(dāng)我們不為測試類添加@RunWith注解的時(shí)候,其實(shí)使用的就是這個(gè)Runner,它作為默認(rèn)Runner只為我們提供了基本的基于Junit生命周期的測試注解。而有更多非常規(guī)的測試需求,則需要我們?yōu)闇y試類添加@RunWith注解并指定特定的Runner來完成!下面列出一些比較有用的Runner。

一、Suit------它可以一次生執(zhí)行全面在多個(gè)類中的測試用例,例如:

@RunWith(Suite.class)
@SuiteClasses({Person.class, People.class})
public class TestSuitMain{
 //雖然這個(gè)類是空的,但依然可以運(yùn)行Junit測試,運(yùn)行時(shí),它會(huì)將Person.class和//People.class中的所有測試用命都執(zhí)行一遍!
}

二、Parameterized------在普通的單元測試中被@Test注解標(biāo)注的測試方法只能是public void的,且不能有任何輸入?yún)?shù)。而這時(shí)常會(huì)給我們造成困擾,因?yàn)橛袝r(shí)候我們需要為測試方法輸入?yún)?shù),甚至是批量指定多個(gè)待測參數(shù)。這時(shí)Parameterized這個(gè)Runner就能滿足我們的要求,用法如下:

@RunWith(Parameterized.class)
public class TestGenerateParams{
  private String greeting;
  public TestGenerateParams(String greeting){
    super();
    this.greeting = greeting;
  }
  @Test
  public void testParams(){    System.out.println(greeting);
  }
  /**
   * 這里的返回的應(yīng)該是一個(gè)可迭代數(shù)組,且方法必須是public static
   * @return
   */
  @Parameters
  public static List getParams(){
    return Arrays.asList(new String[][]{{"hello"},{"hi"},{"good morning"},{"how are you"}});
  }
}

三、Category------繼承自Suit,更強(qiáng)大,它可以讓我們對(duì)測試類中被測試的方法進(jìn)行分類執(zhí)行,例如Person對(duì)象具有一些屬性,這些屬性擁有g(shù)et/set方法,同時(shí)還有一些普通方法。我們可以將獲取屬性的get方法和普通方法進(jìn)行分類測試。如:

public class PersonTest{
  @Category(AttributeFun.class)
  @Test
  public void testGetAge(){
    int age = person.getAge();
    assertEquals(3, age);
  }
  @Category(AttributeFun.class)
  @Test
  public void testGetName(){
    String name = person.getName();
    assertEquals("Willard", name);
  }
  @Category(BehaviorFun.class)
  @Test
  public void testTalk(){
    String message = person.talkTo("Jimy");
    assertNotNull(message);
  }
  @Category(BehaviorFun.class)
  @Test(timeout=200)
  public void testWalk(){
    person.walk();
  }
}
//對(duì)應(yīng)的測試執(zhí)行代碼如下:
@RunWith(Categories.class)
@SuiteClasses(PersonTest.class)
@IncludeCategory(AttributeFun.class)
public class CategoryTest{
 //注意,如果不加@IncludeCategory注解,那么就和使用Suit具有一樣的效果了。
}

四、Theories------雖意為原理或推測的意思,但我在這里以更直觀的方式表述它:提供一組參數(shù)的排列組合值作為待沒方法的輸入?yún)?shù)。同時(shí)注意到在使用Theories這個(gè)Runner的時(shí)候,我們的待測方法可以擁有輸入?yún)?shù),而這在其它的Runner中的測試方法是不成的。下面是一個(gè)例子:

@RunWith(Theories.class)public class TheoriesTest{
  @DataPoint
  public static String nameValue1 = "Tony";
  @DataPoint
  public static String nameValue2 = "Jim";
  @DataPoint  public static int ageValue1 = 10;
  @DataPoint
  public static int ageValue2 = 20;
  @Theory
  public void testMethod(String name, int age){
    System.out.println(String.format("%s's age is %s", name, age));
  }
}

上面的代碼的意思是,將”Tony”、”Jim”、10、20四個(gè)參數(shù)以類型合法的排列組合傳給待沒方法。因此輸出的結(jié)果必然也有2x2=4種:

  Tony's age is 10
  Tony's age is 20
  Jim's age is 10
  Jim's age is 20

不過,為了簡單,我們除了可以使用@DataPoint注解來提供參數(shù)之外,還可以通過@DataPoints注解來提供參數(shù),參照上述代碼,只需要將@DataPoint注解標(biāo)注的四個(gè)字段參數(shù)替換為如下的兩個(gè)即可:

@DataPoints
public static String[] names = {"Tony", "Jim"};
@DataPoints
public static int[] ageValue1 = {10, 20};

上展示了四個(gè)Junit運(yùn)行器的使用示例,有這個(gè)四個(gè)運(yùn)行器的支持,基本上大部分的測試需求得可以得到解決。當(dāng)然Junit提供的功能遠(yuǎn)不止這些。除此之外,我們還可以使用Junit4提供的Rule/Assume/Assert等。
其中使用Rule可以為單元測試指定測試規(guī)則,下面展示了這些可用的Rule:

       Verifier: 驗(yàn)證測試執(zhí)行結(jié)果的正確性。

       ErrorCollector: 收集測試方法中出現(xiàn)的錯(cuò)誤信息,測試不會(huì)中斷,如果有錯(cuò)誤發(fā)生測試結(jié)束后會(huì)標(biāo)記失敗。

       ExpectedException: 提供靈活的異常驗(yàn)證功能。

      Timeout: 用于測試超時(shí)的Rule。

      ExternalResource: 外部資源管理。

     TemporaryFolder: 在JUnit的測試執(zhí)行前后,創(chuàng)建和刪除新的臨時(shí)目錄。

     TestWatcher: 監(jiān)視測試方法生命周期的各個(gè)階段。

     TestName: 在測試方法執(zhí)行過程中提供獲取測試名字的能力。

此外,Assume表示假設(shè),但它實(shí)際是對(duì)待沒方法的參數(shù)進(jìn)行合法性校驗(yàn)的,如果校驗(yàn)不合格則直接拋異常,而不執(zhí)行測試。這和Guava中的Predictions類似。Assume提供的校驗(yàn)規(guī)則如下:

      assumeTrue/assumeFalse、 assumeNotNull、 assumeThat、 assumeNoException

例如:(通過下述代碼也可以看到,要使用參數(shù),則應(yīng)使用@Theory注解)

@Theory
public void printAge(String name, int age){
    Assume.assumeTrue(age > 0);//如果參數(shù)age<=0,會(huì)拋AssumptionViolatedException異常
    System.out.println(String.format("%s's Name is %s.", name, age));
}

Assert是Junit提供的斷言,與Assume不同,Assert是對(duì)測試結(jié)果的校驗(yàn),它提供的檢驗(yàn)規(guī)則如下:

      AssertTrue、AssertFalse:結(jié)果的true、false。

      AssertThat:使用Matcher做自定義的校驗(yàn)。

      AssertEquals、AssertNotEquals:判斷兩個(gè)對(duì)象是否相等。

      AssertNull、AssertNotNull:判斷對(duì)象是否為空。

      AssertSame:判斷兩個(gè)對(duì)象是否為同一個(gè),不同于equals這里是使用“==”判斷。

      AssertArrayEquals:判斷兩個(gè)數(shù)組是否相等。

看完上述內(nèi)容,你們對(duì)利用junit4怎么實(shí)現(xiàn)一個(gè)單元測試功能有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI