Java JUnit测试构造函数测试

Java JUnit测试构造函数测试,java,junit,Java,Junit,伙计们,我对JUnit测试还不熟悉,并试图很好地掌握它,现在我正在为一个构造函数(用于创建有向图的有向图类)编写JUnit测试,该构造函数在读取负int值时抛出IllegalArgumentException,如果一切正常(节点值的数目)大于零,则创建一个图 有向图类: In in = new In(); public Digraph(In in) { try { this.nodes = in.readInt(); System.out.println("Total n

伙计们,我对JUnit测试还不熟悉,并试图很好地掌握它,现在我正在为一个构造函数(用于创建有向图的有向图类)编写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");
  }

我应该如何使用一个(或两个)测试用例来测试这两个用例?如果“in”未检测到-ve值,则获取java.lang.AssertionError,否则测试通过。提前感谢

您应该有很多测试用例。 每个异常都有一个是很好的

您执行的每个测试都是不同的,应该以不同的方式对待

一个很好的参考是:

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

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

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

这样,测试代码更干净、更容易阅读。

您应该有许多测试用例。 每个异常都有一个是很好的

您执行的每个测试都是不同的,应该以不同的方式对待

一个很好的参考是:

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

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

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

这样,测试代码更干净、更容易阅读。

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

在验证是否通过单元测试引发异常时,基本上有3种方法:

一个try-catch块:

@Test
public void myTest() {
    try {
        myClass.myMethod(42);
        fail();
    } catch(final IllegalArgumentException e) {
        assertEquals("something went wrong", e.getMessage());
    }
}
@Test
-注释的
预期属性:

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

}

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

在验证是否通过单元测试引发异常时,基本上有3种方法:

一个try-catch块:

@Test
public void myTest() {
    try {
        myClass.myMethod(42);
        fail();
    } catch(final IllegalArgumentException e) {
        assertEquals("something went wrong", e.getMessage());
    }
}
@Test
-注释的
预期属性:

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

}

csoroiu,因此应对每个异常进行单独测试??因为如果我不这么做,我就会犯错误@user1569891我更新了帖子,每个异常都需要一个方法。您可以模拟类内或创建一个类,为每个测试返回
Digraph
构造函数所需的值,以便按照该测试的需要进行操作。使用
ExpectedException
更好,在此测试中,您无法验证引发异常的位置。@Tobb,我同意这样一个事实,即检查抛出的异常类型是好的,只是想强调,为每个testcase.csoroiu都有一个测试方法是好的,所以每个异常都应该有单独的测试??因为如果我不这么做,我就会犯错误@user1569891我更新了帖子,每个异常都需要一个方法。您可以模拟类内或创建一个类,为每个测试返回
Digraph
构造函数所需的值,以便按照该测试的需要进行操作。使用
ExpectedException
更好,在此测试中,您无法验证引发异常的位置。@Tobb,我同意这样一个事实,即检查抛出了什么样的异常是很好的,只是想强调,对于每个测试用例都有一个测试方法是很好的。