zoukankan      html  css  js  c++  java
  • 使用JUnit测试预期异常

    开发人员常常使用单元测试来验证的一段儿代码的操作,很多时候单元测试可以检查抛出预期异常(expected exceptions)的代码。在Java语言中,JUnit是一套标准的单元测试方案,它提供了很多验证抛出的异常的机制。本文就探讨一下他们的优点。

    我们拿下面的代码作为例子,写一个测试,确保canVote() 方法返回true或者false, 同时你也能写一个测试用来验证这个方法抛出的IllegalArgumentException异常。

    public class Student {
      public boolean canVote(int age) {
          if (i<=0) throw new IllegalArgumentException("age should be +ve");
          if (i<18) return false;
          else return true;
      }
    }

    (Guava类库中提供了一个作参数检查的工具类–Preconditions类,也许这种方法能够更好的检查这样的参数,不过这个例子也能够检查)。

    检查抛出的异常有三种方式,它们各自都有优缺点:

    1.@Test(expected…)

    @Test注解有一个可选的参数,”expected”允许你设置一个Throwable的子类。如果你想要验证上面的canVote()方法抛出预期的异常,我们可以这样写:

    @Test(expected = IllegalArgumentException.class)
    public void canVote_throws_IllegalArgumentException_for_zero_age() {
        Student student = new Student();
        student.canVote(0);
    }

    简单明了,这个测试有一点误差,因为异常会在方法的某个位置被抛出,但不一定在特定的某行。

    2.ExpectedException

    如果要使用JUnit框架中的ExpectedException类,需要声明ExpectedException异常。

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

    然后你可以使用更加简单的方式验证预期的异常。

    @Test
    public void canVote_throws_IllegalArgumentException_for_zero_age() {
        Student student = new Student();
        thrown.expect(IllegalArgumentException.class);
        student.canVote(0);
    }

    或者可以设置预期异常的属性信息。

    @Test
    public void canVote_throws_IllegalArgumentException_for_zero_age() {
        Student student = new Student();
        thrown.expect(IllegalArgumentException.class);
        thrown.expectMessage("age should be +ve");
        student.canVote(0);
    }

    除了可以设置异常的属性信息之外,这种方法还有一个优点,它可以更加精确的找到异常抛出的位置。在上面的例子中,在构造函数中抛出的未预期的 (unexpected) IllegalArgumentException 异常将会引起测试失败,我们希望它在canVote()方法中抛出。

    从另一个方面来说,如果不需要声明就更好了

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

    它就像不需要的噪音一样,如果这样就很好了

    expect(RuntimeException.class)

    或者:

    expect(RuntimeException.class, “Expected exception message”)

    或者至少可以将异常和信息当做参数传进去

    thrown.expect(IllegalArgumentException.class, “age should be +ve”);

    3.Try/catch with assert/fail

    在JUnit4之前的版本中,使用try/catch语句块检查异常

    @Test
    public void canVote_throws_IllegalArgumentException_for_zero_age() {
        Student student = new Student();
        try {
            student.canVote(0);
        } catch (IllegalArgumentException ex) {
            assertThat(ex.getMessage(), containsString("age should be +ve"));
        }
        fail("expected IllegalArgumentException for non +ve age");
    }

    尽管这种方式很老了,不过还是非常有效的。主要的缺点就是很容易忘记在catch语句块之后需要写fail()方法,如果预期异常没有抛出就会导致信息的误报。我曾经就犯过这样的错误。

    总之,这三种方法都可以测试预期抛出的异常,各有优缺点。对于我个人而言,我会选择第二种方法,因为它可以非常精确、高效的测试异常信息。

  • 相关阅读:
    53. Maximum Subarray
    64. Minimum Path Sum
    28. Implement strStr()
    26. Remove Duplicates from Sorted Array
    21. Merge Two Sorted Lists
    14. Longest Common Prefix
    7. Reverse Integer
    412. Fizz Buzz
    linux_修改域名(centos)
    linux_redis常用数据类型操作
  • 原文地址:https://www.cnblogs.com/Lightning-Kid/p/3629313.html
Copyright © 2011-2022 走看看