2013-09-23 194 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); 
    } 

}