2014-09-29 27 views
0

我有一個函數在拋出無效輸入時拋出一個ParseException,我想爲它編寫一個單元測試。此測試旨在確保在所有無效輸入上引發異常。 (對於這個問題,只是假設,輸入被定義爲有效的,如果它有[開始,用]結束,沒有[的或]的任何地方都在裏面。)檢查junit中所有語句是否引發異常的最有效方法是什麼?

我現在有這測試:

@Test 
public void invalidListFromatShouldFail() {   
    final String[] tests = { 
      "[[]", 
      "[]]", 
      "[] hi", 
      "hi", 
      "[h]i", 
      "[hi []", 
      "[[]]" 
    }; 

    for(String toTest : tests) { 
     try { 
      ListUtil.parseList(toTest, TestEnum.class); 
     } catch (ParseException e) { 
      assertThat(e.getMessage(), startsWith(
        "§cList format is invalid: It must start with " + 
        "'[' and end with ']', and not have any '['" + 
        " or ']' anywhere else in it.")); 
      continue; 
     } 
     fail("Exception was not thrown for " + toTest + "!"); 
    } 
} 

它的工作,但它似乎不正確的方式。我嘗試使用ExpectedException,但代碼仍然立即退出。 (我想什麼是這樣的:

@Test 
public void invalidListFromatShouldFail() throws ParseException { 
    expected.expect(ParseException.class); 
    expected.expectMessage(startsWith(
        "§cList format is invalid: It must start with " + 
        "'[' and end with ']', and not have any '['" + 
        " or ']' anywhere else in it.")); 

    ListUtil.parseList("[[]", TestEnum.class); 
    ListUtil.parseList("[]]", TestEnum.class); 
    //ECT... 
} 

但只測試的第一個值;如果我把一個fail()在最後它仍然會成功,因爲發生異常)。

我的問題是:是否有更優雅的方式來編寫此測試,使用ExpectedException或其他方法?

回答

1

其實,你似乎需要兩件事情在這裏。一個是編寫一個測試,檢查是否引發異常,另一個是針對多個輸入運行相同的測試。

首先,開始參數化您的測試。在這種方法中,您的測試方法被編寫爲僅針對單個輸入運行,而其他代碼(通常爲註釋)使此方法可用於多個輸入。這使得您的代碼更簡單,因爲您不必編寫循環或將數據放入某個數組或列表中。您可以使用JUnit內置的Parameterized測試運行器(docs and example),但我個人覺得它的語法很麻煩。我的建議是讓你使用JUnitParams,它有非常簡潔和甜美的語法。

爲了檢查在測試單個輸入的方法中引發了異常,可以使用@Test批註中的expected參數。另一種方法是使用catch-exception library,如果你有更長的測試時更好。在這裏,我認爲內置是足夠好的。

因此,使用JUnitParams和expected標註的參數,你的測試看起來是這樣的:

@Test(expected = ParseException.class) 
@Parameters(
    "[[]", 
    "[]]", 
    "[] hi", 
    "hi", 
    "[h]i", 
    "[hi []", 
    "[[]]" 
) 
public void invalidListFromatShouldFail(String input) {   
    ListUtil.parseList(toTest, TestEnum.class); 
} 

這是很短的,可讀的爲好。

編輯:Here是使用Parameterized,其中還提到@Parameter註解,它允許您直接注入值到一個領域,而不需要建立在您的測試類的構造函數的一個更好的例子。儘管如此,在使用這兩者之後,我真的推薦JUnit Params超過Parameterized,因爲易用性和測試可讀性的差異非常大。

+0

只需確認一下,使用內置的參數化亞軍,最終會多次運行相同的代碼?這些參數中只有一個功能需要運行多次。 (我可能應該自己試試這個)。 – Pokechu22 2014-09-29 20:53:36

+1

使用方法非常相似,即:您編寫一個檢查單個輸入的方法,並且'Parameterized'運行器負責爲不同輸入運行此方法。你不必自己寫任何循環。與JUnitParams相比,將會有更多的代碼,但這個想法基本相同。然而,如果你想在你的類中使用幾個方法,一些參數化和一些非參數化方法採用不同的參數,JUnitParams比'Parameterized'使用起來要方便得多。 – 2014-09-29 21:15:02

-1

你需要來註釋測試:

@Test(expected = YourException.class) 

這裏有一個很好的教程:http://www.mkyong.com/unittest/junit-4-tutorial-2-expected-exception-test/

也看看參數化測試:https://github.com/junit-team/junit/wiki/Parameterized-tests

+0

這不是我想要的。我試圖讓它在多種情況下進行測試。這與使用ExpectedException完全相同,只檢查第一個值。 – Pokechu22 2014-09-29 18:52:55

+0

讓我完成請... – Lucas 2014-09-29 18:53:16

+0

如果只有你的人是如此快速地發佈答案,因爲你是downvoting ... – Lucas 2014-09-29 18:53:53

2

使用JUnit參數測試:https://github.com/junit-team/junit/wiki/Parameterized-tests

作爲替代方案,您可以使用JUnitParams:https://github.com/Pragmatists/junitparams

乾杯,

+0

也分割無效輸入的有效輸入。然後在參數化測試中使用@Test(expected = YourException.class),您預期會失敗 – 2014-09-29 19:08:53

+0

事實上,儘可能簡化您的測試。使用兩個單獨的@Test方法:一個在提供有效輸入時測試代碼的行爲,另一個在提供無效輸入時測試行爲。第一個應該期望None.class,第二個應該期望ParseException.class。 – Kraal 2014-09-29 19:19:51

相關問題