java – 如何验证是否抛出异常
在我使用Mockito的单元测试中,我想验证是否没有抛出NullPointerException.
public void testNPENotThrown{ Calling calling= Mock(Calling.class); testClass.setInner(calling); testClass.setThrow(true); testClass.testMethod(); verify(calling,never()).method(); } 我的测试设置了testClass,设置了Calling对象和属性,以便该方法将抛出NullPointerException. 我验证Calling.method()从不被调用. public void testMethod(){ if(throw) { throw new NullPointerException(); } calling.method(); } 我想要一个失败的测试,因为它抛出一个NullPointerException,然后我想写一些代码来解决这个问题. 我注意到的是,测试总是通过,因为异常从来没有被抛出测试方法. 解决方法
TL;博士
> pre-JDK8:我会推荐旧的好的try-catch块. 漫长的故事 可以自己写一个自己尝试catch块或使用JUnit工具(@Test(expected = …)或@Rule ExpectedException JUnit规则功能). 但是这些方式并不那么优雅,并不能很好地与其他工具混合良好的可读性. > try-catch块你必须围绕被测试的行为写入块,并在断块中写入断言,可能很好,但是很多查找taht这种风格会中断测试的读取流程.此外,您需要在try块的末尾写一个Assert.fail,否则测试可能会错过该断言的一边; PMD,findbugs或Sonar将会发现这样的问题. >如果测试需要检查异常的其他事情,如原因或消息(良好的异常消息非常重要,具有精确的异常类型可能不够). @Test(expected = WantedException.class) public void call2_should_throw_a_WantedException__not_call1() { // init tested tested.call1(); // may throw a WantedException // call to be actually tested tested.call2(); // the call that is supposed to raise an exception } > ExpectedException规则也是尝试修复以前的注意事项,但使用它感觉有点尴尬,因为它使用期望风格,EasyMock用户非常了解这种风格.一些可能是方便的,但是如果遵循行为驱动开发(BDD)或安排行为断言(AAA)原则,ExpectedException规则将不适合这些写作风格.除此之外,它可能像@Test的方式一样受到同样的问题的影响,取决于你所期待的地方. @Rule ExpectedException thrown = ExpectedException.none() @Test public void call2_should_throw_a_WantedException__not_call1() { // expectations thrown.expect(WantedException.class); thrown.expectMessage("boom"); // init tested tested.call1(); // may throw a WantedException // call to be actually tested tested.call2(); // the call that is supposed to raise an exception } 即使预期的异常放在测试语句之前,如果测试遵循BDD或AAA,则会破坏您的阅读流程. 另请参阅这个comment问题在JUnit上的ExpectedException的作者. 所以这些上面的选项都有它们所有的注意事项,显然不能免除编码器的错误. >在创建这个看起来很有前途的答案后,我发现了一个项目,这是catch-exception. 正如该项目的描述所示,它使编码器写入流畅的代码行捕获异常并提供此异常以供稍后断言.您也可以使用任何断言库,如Hamcrest或AssertJ. 从主页获取的快速例子: // given: an empty list List myList = new ArrayList(); // when: we try to get the first element of the list when(myList).get(1); // then: we expect an IndexOutOfBoundsException then(caughtException()) .isInstanceOf(IndexOutOfBoundsException.class) .hasMessage("Index: 1,Size: 0") .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,因为它可能不仅仅是断言异常. 和AssertJ的样品测试: @Test public void test_exception_approach_1() { ... assertThatExceptionOfType(IOException.class) .isThrownBy(() -> someBadIOOperation()) .withMessage("boom!"); } @Test public void test_exception_approach_2() { ... assertThatThrownBy(() -> someBadIOOperation()) .isInstanceOf(Exception.class) .hasMessageContaining("boom"); } @Test public void test_exception_approach_3() { ... // when Throwable thrown = catchThrowable(() -> someBadIOOperation()); // then assertThat(thrown).isInstanceOf(Exception.class) .hasMessageContaining("boom"); } >随着JUnit 5的接近完全重写,断言已经是improved,他们可能会被证明是一个开箱即用的方式来证明有效的例外.但是真正的断言API仍然有点差, @Test @DisplayName("throws EmptyStackException when peeked") void throwsExceptionWhenPeeked() { Throwable t = assertThrows(EmptyStackException.class,() -> stack.peek()); Assertions.assertEquals("...",t.getMessage()); } 当你注意到assertEquals仍然返回void,因此不允许链接断言如AssertJ. 此外,如果您记住与Matcher或Assert的名称冲突,请准备与Assertions相同的冲突. 我想得出结论,今天(2017-03-03)AssertJ的易用性,可发现的API,快速的开发速度和事实上的测试依赖性是JDK8的最佳解决方案,无论测试框架如何(JUnit或不是)因此,以前的JDK应该依靠try-catch块,即使他们觉得笨重. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |