qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

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(NullPointerException.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()方法,如果预期异常没有抛出就会导致信息的误报。我曾经就犯过这样的错误。
  总之,这三种方法都可以测试预期抛出的异常,各有优缺点。对于我个人而言,我会选择第二种方法,因为它可以非常精确、高效的测试异常信息。
English »
 

posted on 2014-10-08 09:12 顺其自然EVO 阅读(182) 评论(0)  编辑  收藏 所属分类: 测试学习专栏


只有注册用户登录后才能发表评论。


网站导航:
 
<2014年10月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜