2013-09-23 242 views
0

夥計們我是JUnit測試的新手,並試圖抓住它,現在我正在爲構造函數編寫JUnit測試(用於創建有向圖的Digraph類),它在讀取時拋出IllegalArgumentException負int值,並且如果一切正常(節點值的數量)大於零,則創建一個圖形。JUnit測試構造函數測試

有向圖類:

In in = new In(); 
public Digraph(In in) { 
    try { 
    this.nodes = in.readInt(); 
    System.out.println("Total nodes in graph: "+ nodes); 
    if (nodes < 0) throw new IllegalArgumentException("Number of vertices must be > 0); 
    int E = in.readInt(); 
    if (E < 0) throw new IllegalArgumentException("Number of edges must be >0); 
    }catch (NoSuchElementException e) { 
    throw new InputMismatchException("Invalid input format in Digraph constructor"); 
    } 

下面是我試圖寫的測試:

@Rule 
    public ExpectedException exception = ExpectedException.none(); 

@Test(expected = IllegalArgumentException.class) 
public void DigraphIn() { 

    Digraph G = new Digraph(in.readInt()); 

    exception.expect(IllegalArgumentException.class); 
    exception.expectMessage("Vertices can't be nagative"); 
    exception.expectMessage("Invalid input format in Digraph constructor"); 
    exception.expectMessage("Number of edges in a Digraph must be nonnegative"); 
try{ 
}catch (AssertionError e){ 
    } 
} 

我應該如何使用一個(或兩個)測試用例測試這兩種情況?如果沒有「in」檢測到的-ve值,我會得到java.lang.AssertionError,否則測試通過。在此先感謝

回答

2

你應該有很多測試用例。 每個例外都有一個是很好的。

您執行的每個測試都是不同的,應該區別對待。

一個很好的參考是:Junit Cookbook

其實我在代碼中看到一個錯誤。 在您的測試案例中,您可以如下模擬協作者。我做了一個模擬,使用'mockito'mocks庫在每次調用時返回不同的值。

你基本上需要這樣的東西:

@Test(expected = IllegalArgumentException.class) 
public void DigraphInThatThrowsExceptionForVertices() { 
    In in = Mockito.mock(In.class); 
    when(in.readInt()).thenReturn(-1); 
    Digraph G = new Digraph(in); 
    fail(); 
} 

@Test(expected = IllegalArgumentException.class) 
public void DigraphInThatThrowsExceptionForEdges() { 
    In in = Mockito.mock(In.class); 
    when(in.readInt()).thenReturn(10).thenReturn(-1); 
    Digraph G = new Digraph(in); 
    fail(); 
} 

@Test 
public void DigraphInThatDoesNotThrowException() { 
    In in = Mockito.mock(In.class); 
    when(in.readInt()).thenReturn(10).thenReturn(15); 
    Digraph G = new Digraph(in.readInt()); 
} 

這樣的測試代碼是清潔,易於閱讀。

+0

csoroiu,所以有應該對每個異常進行單獨測試?因爲如果我不這樣做,我會得到AssertionError! – user1569891

+0

@ user1569891我更新了帖子,每個異常都需要一個方法。您可以模擬In類或創建一個爲每個測試返回'Digraph'構造函數所需的值以根據需要執行該測試的值。 – Claudiu

+1

使用'ExpectedException'更好,在這個測試中你不能驗證異常拋出的位置。 – Tobb

1

當你正在測試一個方法時,你實際調用了它,這會使它執行。該測試只能驗證每個測試的一個異常,因爲該異常將取消該方法的其餘處理。因此,您需要針對每個可引發異常的地方進行一次測試。

當驗證一個異常被拋出了單元測試,基本上有3種方式來做到這一點:

一個try-catch塊:

@Test 
public void myTest() { 
    try { 
     myClass.myMethod(42); 
     fail(); 
    } catch(final IllegalArgumentException e) { 
     assertEquals("something went wrong", e.getMessage()); 
    } 
} 

@Testexpected -attribute -annotation:

@Test(expected=IllegalArgumentException.class) 
public void myTest() { 
    myClass.myMethod(42); 
} 

ExpectedException

@Rule 
public ExpectedException expectedException = ExpectedException.none(); 

@Test 
public void myTest() { 
    expectedException.expect(IllegalArgument.class); 
    expectedException.expectMessage("something went wrong"); 

    myClass.myMethod(42); 
} 

在你的例子中,你試圖使用所有三個。

如果我們比較異常測試的方法,只有第一個和第三個實際上能夠對引發的異常進行驗證,這使得它們更適合於測試方法,其中可以從多個地方拋出相同類型的異常,然後可以使用異常消息來驗證異常是從您所在的位置拋出的。

第二個是迄今爲止最具可讀性的,但不允許區分被測試方法拋出的異常,它在大多數情況下不會提供與其他兩個值相同的值。

第一和第三,第三是迄今爲止最具可讀性,也是我個人的最愛。

由於被測方法只能拋出每執行一個例外,它應該有一個測試方法,對每個地方的可能拋出異常的地方:

public class DiagraphTest { 

    @Rule 
    public ExpectedException expectedException = ExpectedException.none(); 

    private Diagraph diagraph; 
    private In in; 

    @Before 
    public void setup() { 
     in = mock(In.class); 
    } 

    @Test 
    public void constructorShouldThrowExceptionWhenNumberOfVerticesIsLessThanOne() { 
     expectedException.expect(IllegalArgumentException.class); 
     expectedException.expectMessage("vertices must be > 0"); //expectMessage only needs a substring of the exception-message 

     doReturn(-1).when(in).readInt(); 

     new Diagraph(in); 
    } 

    @Test 
    public void constructorShouldThrowExceptionWhenNumberOfEdgesIsLessThanOne() { 
     expectedException.expect(IllegalArgumentException.class); 
     expectedException.expectMessage("edges must be > 0"); 

     when(in.readInt()).thenReturn(42, -1); 

     new Diagraph(in); 
    } 

    //as to the last exception, I really can't see that it will ever be thrown in that try-block, but here's a test for that as well.. 
    @Test 
    public void constructorShouldThrowInputMismatchExceptionIfReceivedNoSuchElementException() { 
     expectedException.expect(InputMismatchException.class); 
     expectedException.expectMessage("Invalid input format); 

     doThrow(new NoSuchElementException("phail")).when(in).readInt(); 

     new Diagraph(in); 
    } 

}