【问题标题】:JUnit Testing Constructor TestingJUnit 测试构造函数测试
【发布时间】:2013-09-28 20:43:44
【问题描述】:

伙计们,我是 JUnit 测试的新手并试图很好地掌握它,现在我正在为构造函数(用于创建有向图的 Digraph 类)编写 JUnit 测试,当它读取负 int 值时抛出 IllegalArgumentException 和如果一切正常(节点值的数量)大于零,则创建一个图。

有向图类:

 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 否则测试通过。提前致谢

【问题讨论】:

    标签: java junit


    【解决方案1】:

    你应该有很多测试用例。 最好为每个异常设置一个。

    您执行的每个测试都是不同的,应该区别对待。

    一个很好的参考是:Junit Cookbook

    实际上我在您的代码中看到了一个错误。 在您的测试用例中,您可以模拟如下协作者。我做了一个模拟,使用“mockito”模拟库在每次调用时返回不同的值。

    你基本上需要这样的东西:

    @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());
    }
    

    这种方式测试代码更简洁易读。

    【讨论】:

    • csoroiu,所以每个异常应该有单独的测试??因为如果我不这样做,我会得到 AssertionError!
    • @user1569891 我更新了帖子,每个异常都需要一种方法。您可以模拟 In 类或创建一个为每个测试返回 Digraph 构造函数所需的值的类,以根据该测试的需要运行。
    • 使用ExpectedException更好,在这个测试中你无法验证异常是在哪里抛出的..
    • @Tobb,我同意检查抛出了什么样的异常是件好事,只是想强调每个测试用例都有一个测试方法是件好事。
    【解决方案2】:

    当您测试一个方法时,您实际调用它,这将使它执行。该测试每次测试只能验证一个异常,因为该异常将取消该方法的其余处理。因此,您需要对可能引发异常的每个地方进行一次测试。

    当通过单元测试验证是否抛出异常时,基本上有 3 种方法可以做到这一点:

    try-catch 块:

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

    @Test-注解的expected-属性:

    @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);
        }
    

    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-15
      • 1970-01-01
      相关资源
      最近更新 更多