在我的使用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; dr
JDK8之后:使用 AssertJ 或自定义lambda来声明 异常 行为。
JDK8之前的版本:我将html" target="_blank">推荐旧的好try
- catch
块。( 不要忘记fail()
在该catch
块之前添加一个断言)
无论是Junit 4还是JUnit 5。
长话
可以自己编写自己 做的代码 try
- catch
阻止或使用JUnit工具(@Test(expected = ...)
或@Rule ExpectedException
JUnit规则功能)。
但是这些方法并不那么优雅,并且在 可读性方面没有 与其他工具很好地融合在一起。而且,JUnit工具确实存在一些陷阱。
在try
- catch
块,你必须写周围的测试行为块,写在catch块的断言,这可能是罚款,但很多人觉得这种风格中断测试的阅读流程。另外,您需要Assert.fail
在代码try
块的末尾写一个。否则,测试可能会遗漏断言的某一方面; PMD , findbugs 或 Sonar 会发现此类问题。
该@Test(expected = ...)
功能很有趣,因为您可以编写更少的代码,然后编写此测试的代码据说不那么容易出错。 但是 在某些领域缺少这种方法。
@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,它也会破坏您的阅读流程。
另外,请参见的作者关于JUnit的注释问题ExpectedException
。JUnit
4.13-beta-2
甚至不赞成使用此机制:
拉取请求#1519:弃用ExpectedException
Assert.assertThrows方法提供了一种验证异常的更好方法。另外,与其他规则(如TestWatcher)一起使用时,ExpectedException的使用容易出错,因为在这种情况下,规则的顺序很重要。
因此,以上所有这些选项都有很多警告,并且显然无法避免编码错误。
正如该项目的描述所言,它使编码人员可以流畅地编写一行代码以捕获该异常,并为后者的断言提供此异常。而且,您可以使用任何断言库,例如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();
如您所见,代码确实非常简单,您可以在特定行上捕获异常,该then
API是将使用AssertJ API的别名(类似于using
assertThat(ex).hasNoCause()...
)。 在某些时候,该项目依赖于FEST-声明AssertJ的祖先 。 编辑:
似乎该项目正在酝酿对Java 8 Lambdas的支持。
当前,该库有两个缺点:
* 在撰写本文时,值得注意的是,该库基于Mockito 1.x,因为它创建了幕后测试对象的模拟。由于Mockito仍未更新, **因此该库无法使用最终类或最终方法** 。即使它基于当前版本的Mockito 2,这也需要声明一个全局模拟制作器(`inline-mock-maker`),这可能不是您想要的,因为该模拟制作器与常规模拟制作器有不同的缺点。
* 它需要另一个测试依赖项。
一旦库支持lambda,这些问题将不再适用。但是,该功能将由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");
}
assertThrows
。 @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)不论测试框架(JUnit )是什么, AssertJ 的易用性,可发现的API,快速的开发速度以及
事实上的 测试依赖性是使用JDK8的最佳解决方案。还是不可以),即使以前的JDK 感到笨拙,也应该改用 try
-catch
块。
我正在创建一个Spring Boot项目来测试我的rest API(非常非常小的项目)。该项目包含三个文件。 1)app.java(主程序)2)AppConfig(配置文件)3)主控制器(简单Rest控制器) 我添加了Spring-boot-starter-parent(1.4.0.release)和spring-boot-starter-web作为依赖项。 但是在执行时,会得到如下所示的异常。
当我尝试测试此方法时 使用以下测试 也是如此。 是否可以使用AssertJ测试静态方法实际上抛出未检查的异常?我应该在考试中改变什么?
例子: 我如何在mockito中执行此操作,并在强制抛出异常1后验证是否得到了异常2?
问题内容: 如果参数无效,如何使用JSR-303验证方法参数并引发异常? 例如像这样:? 现在,我检查方法主体中的每个方法参数,例如 而且我觉得这很丑。 PS作为参考实现,我使用Hibernate-validator 4.1.0.Final 问题答案: 如果可以升级到Hibernate Validator 4.2.0或更高版本,则可以使用其方法验证功能,该功能为方法参数和返回值的验证提供支持。 可
在测试中,我使用的是mockobject: 我试图验证其方法的使用: 但它抛出以下异常: 组织。莫基托。例外情况。滥用。UnfinishedVerificationException:此处缺少验证(模拟)的方法调用: 这一行的例外点是: setMaxRows接受一个int。 当我注释掉这一行时,测试成功了。调试程序时,我可以看到正在设置的setMaxRows方法: BrandLabels是一个Li
我正在尝试使用@Valid验证我的JPA实体,如下所示: 它工作了一段时间,但现在它停止工作,我不知道为什么。我试着在< code>persist方法中手动执行,它按预期工作: 可能会发生什么情况,或者我该如何调试?