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块,即使他们觉得笨重. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
