Java JUnit 测试构造函数测试

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18967964/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 12:57:56  来源:igfitidea点击:

JUnit Testing Constructor Testing

javajunit

提问by user1569891

Guys I am new to JUnit testing and trying to get a good grip on it, right now I am writing JUnit tests for a constructor (for Digraph Class that creates a directed graph) that throws IllegalArgumentException when it reads negative int value and creates a graph if everything is ok (number of node value) is greater than zero.

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

Digraph Class:

有向图类:

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

Below is the test that I am trying to write:

以下是我正在尝试编写的测试:

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

How should I test both of the cases using one (or two) test cases? If there's no -ve value detected by "in" I get java.lang.AssertionError otherwise test passes. Thanks in advance

我应该如何使用一个(或两个)测试用例来测试这两种情况?如果“in”没有检测到 -ve 值,我会得到 java.lang.AssertionError 否则测试通过。提前致谢

回答by Claudiu

You shoud have many testcases. It is good to have one for each exception.

你应该有很多测试用例。每个例外都有一个是很好的。

Each test you perform is different and should be treated differently.

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

A good reference is this: Junit Cookbook.

一个很好的参考是:Junit Cookbook

Actually I saw an error in your code. In your test cases you may mock the collaborators as below. I made a mock that returns at each call different values using 'mockito' mocks library.

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

You basically need something like:

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

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

This way test code is cleaner and easy to read.

这种方式测试代码更清晰且易于阅读。

回答by Tobb

When you are testing a method you actually call it, which will make it execute. The test can only verify one exception per test, since the exception will cancel the remainder of the processing of the method. Thus, you need one test for each of the places where an exception can be thrown.

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

When verifying that an exception is thrown with a unit-test, there are basically 3 ways to do it:

在使用单元测试验证是否抛出异常时,基本上有 3 种方法可以做到:

A try-catch block:

一个 try-catch 块:

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

The expected-attribute of the @Test-annotation:

expected对的-attribute @Test-annotation:

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

and ExpectedException:

ExpectedException

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

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

    myClass.myMethod(42);
}

In your example, your trying to use all three.

在您的示例中,您尝试使用所有三个。

If we compare the methods of testing for exceptions, only the first and third are actually able to make verifications on the exception being thrown, which makes them preferable for testing methods where the same type of exception can be thrown from multiple places, you can then use the exception message to verify that the exception was thrown from the place you ment it to.

如果我们对比测试异常的方法,实际上只有第一种和第三种能够对抛出的异常进行验证,这使得它们更适合可以从多个地方抛出相同类型异常的测试方法,则可以使用异常消息来验证异常是从您指向它的地方抛出的。

The second one is by far the most readable, but does not allow you to distinguish between the exceptions being thrown by the method under test, it does not provide as much value as the other two in most cases.

第二个是迄今为止最具可读性的,但不允许您区分被测方法抛出的异常,在大多数情况下它没有提供与其他两个一样多的价值。

Of the first and the third, the third is by far the most readable, and also my personal favorite.

在第一个和第三个中,第三个是迄今为止最易读的,也是我个人最喜欢的。

Since the method under test can only throw one exception per execution, it should have one test method for each of the places where an exception may be thrown:

由于被测方法每次执行只能抛出一个异常,所以对于每个可能抛出异常的地方,它应该有一个测试方法:

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

}

}