单元测试用于验证一段代码是否按照开发人员的预期运行。 有时,这意味着检查代码是否也会引发预期的异常。 JUnit是Java单元测试的标准,并提供了几种验证抛出异常的机制。 本文探讨了这些选项及其相对优点。
以下面的简单代码段为例。 除了编写测试以确保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;}}
( 番石榴前提条件可能更适合这些参数检查,但该示例仍然有效)。
有3种常见的方法可以检查是否引发了异常,每种方法都有其自身的优缺点。
1)@Test(预期…)
@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:
@Rulepublic ExpectedException thrown= ExpectedException.none();
然后,您可以使用仅指定预期异常的更简单方法:
@Testpublic void canVote_throws_IllegalArgumentException_for_zero_age() {Student student = new Student();thrown.expect(NullPointerException.class);student.canVote(0);}
或者也可以指定预期的异常消息:
@Testpublic void canVote_throws_IllegalArgumentException_for_zero_age() {Student student = new Student();thrown.expect(IllegalArgumentException.class);thrown.expectMessage("age should be +ve");student.canVote(0);}
除了可以指定预期的异常消息之外,此ExpectedException方法还具有使您可以更精确地了解预期在何处引发异常的优点。 在上面的示例中,在构造函数中引发意外的IllegalArgumentException会导致测试失败,因为我们希望测试会在canVote()方法中引发。
附带一提,如果不需要声明,那就太好了:
@Rule public ExpectedException thrown= ExpectedException.none();
好像是不必要的噪音。 能够做的很好
expect(RuntimeException.class)
要么
expect(RuntimeException.class, “Expected exception message”)
或至少能够在一次对ExpectedException的调用中传递异常和消息:
thrown.expect(IllegalArgumentException.class, “age should be +ve”);
3)尝试/抓住断言/失败
在JUnit4之前,检查异常的方法是使用try / catch块。
@Testpublic 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");}
尽管这是一种较旧的方法,但仍然完全有效。 主要缺点是很容易忘记将fail()放在catch后面,如果未引发预期的异常,则会导致误报。 我过去肯定犯了这个错误!
总之,有三种主要的方法可以测试预期的异常情况,每种方法都有其自身的优缺点。 就我个人而言,由于它的精确度和测试异常消息的能力,我通常倾向于ExpectedException方法。
翻译自: https://www.javacodegeeks.com/2014/02/testing-for-expected-exceptions-in-junit.html