使用JUnit测试预期异常

本文介绍如何使用JUnit的不同方法来测试预期的异常,包括@Test(expected...)、ExpectedException和try/catch结合assert/fail的方法,并讨论了各自的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

source: http://www.importnew.com/10079.html


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

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

1
2
3
4
5
6
7
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()方法抛出预期的异常,我们可以这样写:

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

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

2.ExpectedException

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

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

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

1
2
3
4
5
6
@Test
public void canVote_throws_IllegalArgumentException_for_zero_age() {
     Student student = new Student();
     thrown.expect(IllegalArgumentException. class );
     student.canVote( 0 );
}

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

1
2
3
4
5
6
7
@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()方法中抛出。

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

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

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

1
expect(RuntimeException. class )

或者:

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

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

1
thrown.expect(IllegalArgumentException. class , “age should be +ve”);
3.Try/catch with assert/fail

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

1
2
3
4
5
6
7
8
9
10
@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()方法,如果预期异常没有抛出就会导致信息的误报。我曾经就犯过这样的错误。

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

原文链接:  javacodegeeks  翻译:  ImportNew.com  踏雁寻花
译文链接:  http://www.importnew.com/10079.html
转载请保留原文出处、译者和译文链接。 ]


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值