java – 如何验证是否抛出异常

前端之家收集整理的这篇文章主要介绍了java – 如何验证是否抛出异常前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在我使用Mockito的单元测试中,我想验证是否没有抛出NullPointerException.
  1. public void testNPENotThrown{
  2. Calling calling= Mock(Calling.class);
  3. testClass.setInner(calling);
  4. testClass.setThrow(true);
  5.  
  6. testClass.testMethod();
  7.  
  8. verify(calling,never()).method();
  9. }

我的测试设置了testClass,设置了Calling对象和属性,以便该方法将抛出NullPointerException.

我验证Calling.method()从不被调用.

  1. public void testMethod(){
  2. if(throw) {
  3. throw new NullPointerException();
  4. }
  5.  
  6. calling.method();
  7. }

我想要一个失败的测试,因为它抛出一个NullPointerException,然后我想写一些代码解决这个问题.

我注意到的是,测试总是通过,因为异常从来没有被抛出测试方法.

解决方法

TL;博士

> pre-JDK8:我会推荐旧的好的try-catch块.
> post-JDK8:使用AssertJ或custom lambdas来表示异常行为.

漫长的故事

可以自己写一个自己尝试catch块或使用JUnit工具(@Test(expected = …)或@Rule ExpectedException JUnit规则功能).

但是这些方式并不那么优雅,并不能很好地与其他工具混合良好的可读性.

> try-catch块你必须围绕被测试的行为写入块,并在断块中写入断言,可能很好,但是很多查找taht这种风格会中断测试的读取流程.此外,您需要在try块的末尾写一个Assert.fail,否则测试可能会错过该断言的一边; PMD,findbugs或Sonar将会发现这样的问题.
> @Test(expected = …)功能很有趣,因为您可以编写更少的代码,然后编写此测试据说不太容易出现编码错误.但这种做法缺乏一些方面.

>如果测试需要检查异常的其他事情,如原因或消息(良好的异常消息非常重要,具有精确的异常类型可能不够).
>另外,由于期望在方法中放置,取决于测试代码的编写方式,所以测试代码错误部分可以抛出异常,导致错误的正测试,我不知道PMD,findbugs或Sonar将会提供这样的代码提示.

  1. @Test(expected = WantedException.class)
  2. public void call2_should_throw_a_WantedException__not_call1() {
  3. // init tested
  4. tested.call1(); // may throw a WantedException
  5.  
  6. // call to be actually tested
  7. tested.call2(); // the call that is supposed to raise an exception
  8. }

> ExpectedException规则也是尝试修复以前的注意事项,但使用它感觉有点尴尬,因为它使用期望风格,EasyMock用户非常了解这种风格.一些可能是方便的,但是如果遵循行为驱动开发(BDD)或安排行为断言(AAA)原则,ExpectedException规则将不适合这些写作风格.除此之外,它可能像@Test的方式一样受到同样的问题的影响,取决于你所期待的地方.

  1. @Rule ExpectedException thrown = ExpectedException.none()
  2.  
  3. @Test
  4. public void call2_should_throw_a_WantedException__not_call1() {
  5. // expectations
  6. thrown.expect(WantedException.class);
  7. thrown.expectMessage("boom");
  8.  
  9. // init tested
  10. tested.call1(); // may throw a WantedException
  11.  
  12. // call to be actually tested
  13. tested.call2(); // the call that is supposed to raise an exception
  14. }

即使预期的异常放在测试语句之前,如果测试遵循BDD或AAA,则会破坏您的阅读流程.

另请参阅这个comment问题在JUnit上的ExpectedException的作者.

所以这些上面的选项都有它们所有的注意事项,显然不能免除编码器的错误.

>在创建这个看起来很有前途的答案后,我发现了一个项目,这是catch-exception.

正如该项目的描述所示,它使编码器写入流畅的代码行捕获异常并提供此异常以供稍后断言.您也可以使用任何断言库,如HamcrestAssertJ.

从主页获取快速例子:

  1. // given: an empty list
  2. List myList = new ArrayList();
  3.  
  4. // when: we try to get the first element of the list
  5. when(myList).get(1);
  6.  
  7. // then: we expect an IndexOutOfBoundsException
  8. then(caughtException())
  9. .isInstanceOf(IndexOutOfBoundsException.class)
  10. .hasMessage("Index: 1,Size: 0")
  11. .hasNoCause();

正如你可以看到代码真的很简单,你可以捕获特定行上的异常,然后API是一个别名,它将使用AssertJ API(类似于使用assertThat(ex).hasNoCause()…)).在某些时候,项目依靠FEST-Assert AssertJ的祖先.编辑:似乎该项目正在酝酿Java 8 Lambdas支持.

目前这个图书馆有两个缺点:

>在撰写本文时,值得注意的是,这个库基于Mockito 1.x,因为它在场景后面创建了被测对象的模拟.由于Mockito尚未更新,因此该库无法使用最终类或最终方法.即使它是基于当前版本的mockito 2,这将需要声明一个全球模拟制造商(内联制造商),这可能不是你想要的,因为这个模拟器具有不同的缺点,即常规模拟器.
>它需要另一个测试依赖.

一旦图书馆支持lambdas,这些问题就不会适用,但AssertJ工具集将会复制这些功能.

考虑到如果你不想使用catch-exception工具,我会推荐try-catch块的旧的好方法,至少到JDK7.对于JDK 8用户,您可能更喜欢使用AssertJ,因为它可能不仅仅是断言异常.
>使用JDK8,羊羔进入测试场景,它们被证明是一种有趣的方式来证明异常行为. AssertJ已经更新,以提供一个很好的流畅的API来表示异常行为.

AssertJ的样品测试:

  1. @Test
  2. public void test_exception_approach_1() {
  3. ...
  4. assertThatExceptionOfType(IOException.class)
  5. .isThrownBy(() -> someBadioOperation())
  6. .withMessage("boom!");
  7. }
  8.  
  9. @Test
  10. public void test_exception_approach_2() {
  11. ...
  12. assertThatThrownBy(() -> someBadioOperation())
  13. .isInstanceOf(Exception.class)
  14. .hasMessageContaining("boom");
  15. }
  16.  
  17. @Test
  18. public void test_exception_approach_3() {
  19. ...
  20. // when
  21. Throwable thrown = catchThrowable(() -> someBadioOperation());
  22.  
  23. // then
  24. assertThat(thrown).isInstanceOf(Exception.class)
  25. .hasMessageContaining("boom");
  26. }

>随着JUnit 5的接近完全重写,断言已经是improved,他们可能会被证明是一个开箱即用的方式来证明有效的例外.但是真正的断言API仍然有点差,assertThrows以外没有什么.

  1. @Test
  2. @DisplayName("throws EmptyStackException when peeked")
  3. void throwsExceptionWhenPeeked() {
  4. Throwable t = assertThrows(EmptyStackException.class,() -> stack.peek());
  5.  
  6. Assertions.assertEquals("...",t.getMessage());
  7. }

当你注意到assertEquals仍然返回void,因此不允许链接断言如AssertJ.

此外,如果您记住与Matcher或Assert的名称冲突,请准备与Assertions相同的冲突.

我想得出结论,今天(2017-03-03)AssertJ的易用性,可发现的API,快速的开发速度和事实上的测试依赖性是JDK8的最佳解决方案,无论测试框架如何(JUnit或不是)因此,以前的JDK应该依靠try-catch块,即使他们觉得笨重.

猜你在找的Java相关文章