I have a test:
我有一个测试:
@Rule
public ExpectedException thrown = ExpectedException.none();
...
@Test
public void testMethod()
{
final String error = "error message";
Throwable expectedCause = new IllegalStateException(error);
thrown.expectCause(org.hamcrest.Matchers.<Throwable>equalTo(expectedCause));
someServiceThatTrowsException.foo();
}
When run via mvn the test method, I'm getting the error:
当通过mvn运行测试方法时,我收到错误:
java.lang.NoSuchMethodError: org.junit.rules.ExpectedException.expectCause(Lorg/hamcrest/Matcher;)V
java.lang.NoSuchMethodError:org.junit.rules.ExpectedException.expectCause(Lorg / hamcrest / Matcher;)V
Test compiles fine.
测试编译好。
Please help me, cannot understand how to test the cause of the exception?
请帮帮我,不明白如何测试异常的原因?
9 个解决方案
#1
15
You can use a custom matcher as described here (http://www.javacodegeeks.com/2014/03/junit-expectedexception-rule-beyond-basics.html) to test for the cause of an exception.
您可以使用此处所述的自定义匹配器(http://www.javacodegeeks.com/2014/03/junit-expectedexception-rule-beyond-basics.html)来测试异常的原因。
Custom matcher
private static class CauseMatcher extends TypeSafeMatcher<Throwable> {
private final Class<? extends Throwable> type;
private final String expectedMessage;
public CauseMatcher(Class<? extends Throwable> type, String expectedMessage) {
this.type = type;
this.expectedMessage = expectedMessage;
}
@Override
protected boolean matchesSafely(Throwable item) {
return item.getClass().isAssignableFrom(type)
&& item.getMessage().contains(expectedMessage);
}
@Override
public void describeTo(Description description) {
description.appendText("expects type ")
.appendValue(type)
.appendText(" and a message ")
.appendValue(expectedMessage);
}
}
Test case
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void verifiesCauseTypeAndAMessage() {
thrown.expect(RuntimeException.class);
thrown.expectCause(new CauseMatcher(IllegalStateException.class, "Illegal state"));
throw new RuntimeException("Runtime exception occurred",
new IllegalStateException("Illegal state"));
}
#2
14
Try it this way:
试试这种方式:
@Rule public ExpectedException thrown = ExpectedException.none();
@Test public void testMethod() throws Throwable {
final String error = "error message";
Throwable expectedCause = new IllegalStateException(error);
thrown.expectCause(IsEqual.equalTo(expectedCause));
throw new RuntimeException(expectedCause);
}
Consider not to check against the cause by equals but by IsInstanceOf and / or comapring the exception message if necessary. Comparing the cause by equals check the stacktrace as well, which may be more than you would like to test / check. Like this for example:
考虑不要通过equals检查原因,而是通过IsInstanceOf检查和/或在必要时将异常消息组合在一起。通过equals比较原因也检查堆栈跟踪,这可能比您想要测试/检查的更多。像这样举例如:
@Rule public ExpectedException thrown = ExpectedException.none();
@Test public void testMethod() throws Throwable {
final String error = "error message";
thrown.expectCause(IsInstanceOf.<Throwable>instanceOf(IllegalStateException.class));
thrown.expectMessage(error);
throw new RuntimeException(new IllegalStateException(error));
}
#3
12
A little bit more briefly with static imports and checking both the class and the message of the cause exception:
稍微简单介绍静态导入并检查原因异常的类和消息:
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
@Test
public void testThatThrowsNiceExceptionWithCauseAndMessages(){
expectedException.expect(RuntimeException.class );
expectedException.expectMessage("Exception message");
expectedException.expectCause(allOf(instanceOf(IllegalStateException.class),
hasProperty("message", is("Cause message"))) );
throw new RuntimeException("Exception message", new IllegalStateException("Cause message"));
}
You could even use the hasProperty matcher to assert nested causes or to test the "getLocalizedMessage" method.
您甚至可以使用hasProperty匹配器来断言嵌套原因或测试“getLocalizedMessage”方法。
#4
#5
4
To summarize all.
总结一下。
With JUnit 4 ( hamcrest 1.3 , and be careful, JUnit 4 depend on hamcrest-core which not include org.hamcrest.beans package)
使用JUnit 4(hamcrest 1.3,小心,JUnit 4依赖于hamcrest-core,不包括org.hamcrest.beans包)
So, you need to import:
所以,你需要导入:
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
Code:
码:
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testThatThrowsNiceExceptionWithCauseAndMessages(){
expectedException.expect(RuntimeException.class );
expectedException.expectMessage("Exception message");
expectedException.expectCause(
allOf(
isA(IllegalStateException.class),
hasProperty("message", is("Cause message"))
)
);
throw
new RuntimeException("Exception message",
new IllegalStateException("Cause message"));
}
#6
3
The any(Class<T>) matcher from hamcrest works nicely:
来自hamcrest的any(Class
@Rule
public ExpectedException thrown = ExpectedException.none();
...
@Test
public void testMethod()
{
thrown.expect(RuntimeException.class);
thrown.expectCause(org.hamcrest.Matchers.any(IllegalStateException.class));
}
#7
3
Normally I like more the following construction:
通常我更喜欢以下结构:
expectedException.expectCause(isA(NullPointerException.class));
expectedException.expectCause(ISA(NullPointerException.class));
#8
0
Import
进口
<dependency>
<groupId>it.ozimov</groupId>
<artifactId>java7-hamcrest-matchers</artifactId>
<version>1.3.0</version>
<scope>test</scope>
</dependency>
And then:
接着:
@Rule
public ExpectedException thrown = ExpectedException.none();
...
@Test
public void testMethod()
{
final String errorMessage = "error message";
Class<? extends Throwable> expectedCause = IllegalStateException.class;
thrown.expectCause(ExpectedException.exceptionWithMessage(expectedCause, errorMessage));
someServiceThatTrowsException.foo();
}
It works also with subtype of the cause. In other solutions I observed that they accept a supertype, that is wrong in my opinion.
它也适用于原因的子类型。在其他解决方案中,我观察到他们接受超类型,我认为这是错误的。
Message must be equal or contained in the cause's error message.
消息必须相等或包含在原因的错误消息中。
#9
0
You can do this entirely with built-in matchers org.hamcrest.Matchers.instanceOf
and org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage
:
您可以使用内置匹配器org.hamcrest.Matchers.instanceOf和org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage完全执行此操作:
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.both;
import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage;
public class temp {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void youCannotDivideByZero() {
expectedException.expect(RuntimeException.class);
expectedException.expectMessage(equalTo("Division exception"));
expectedException.expectCause(both(hasMessage(equalTo("/ by zero"))).and(instanceOf(ArithmeticException.class)));
divide(1, 0);
}
private float divide(int first, int second) {
try {
return first / second;
} catch(ArithmeticException e) {
throw new RuntimeException("Division exception", e);
}
}
}
#1
15
You can use a custom matcher as described here (http://www.javacodegeeks.com/2014/03/junit-expectedexception-rule-beyond-basics.html) to test for the cause of an exception.
您可以使用此处所述的自定义匹配器(http://www.javacodegeeks.com/2014/03/junit-expectedexception-rule-beyond-basics.html)来测试异常的原因。
Custom matcher
private static class CauseMatcher extends TypeSafeMatcher<Throwable> {
private final Class<? extends Throwable> type;
private final String expectedMessage;
public CauseMatcher(Class<? extends Throwable> type, String expectedMessage) {
this.type = type;
this.expectedMessage = expectedMessage;
}
@Override
protected boolean matchesSafely(Throwable item) {
return item.getClass().isAssignableFrom(type)
&& item.getMessage().contains(expectedMessage);
}
@Override
public void describeTo(Description description) {
description.appendText("expects type ")
.appendValue(type)
.appendText(" and a message ")
.appendValue(expectedMessage);
}
}
Test case
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void verifiesCauseTypeAndAMessage() {
thrown.expect(RuntimeException.class);
thrown.expectCause(new CauseMatcher(IllegalStateException.class, "Illegal state"));
throw new RuntimeException("Runtime exception occurred",
new IllegalStateException("Illegal state"));
}
#2
14
Try it this way:
试试这种方式:
@Rule public ExpectedException thrown = ExpectedException.none();
@Test public void testMethod() throws Throwable {
final String error = "error message";
Throwable expectedCause = new IllegalStateException(error);
thrown.expectCause(IsEqual.equalTo(expectedCause));
throw new RuntimeException(expectedCause);
}
Consider not to check against the cause by equals but by IsInstanceOf and / or comapring the exception message if necessary. Comparing the cause by equals check the stacktrace as well, which may be more than you would like to test / check. Like this for example:
考虑不要通过equals检查原因,而是通过IsInstanceOf检查和/或在必要时将异常消息组合在一起。通过equals比较原因也检查堆栈跟踪,这可能比您想要测试/检查的更多。像这样举例如:
@Rule public ExpectedException thrown = ExpectedException.none();
@Test public void testMethod() throws Throwable {
final String error = "error message";
thrown.expectCause(IsInstanceOf.<Throwable>instanceOf(IllegalStateException.class));
thrown.expectMessage(error);
throw new RuntimeException(new IllegalStateException(error));
}
#3
12
A little bit more briefly with static imports and checking both the class and the message of the cause exception:
稍微简单介绍静态导入并检查原因异常的类和消息:
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
@Test
public void testThatThrowsNiceExceptionWithCauseAndMessages(){
expectedException.expect(RuntimeException.class );
expectedException.expectMessage("Exception message");
expectedException.expectCause(allOf(instanceOf(IllegalStateException.class),
hasProperty("message", is("Cause message"))) );
throw new RuntimeException("Exception message", new IllegalStateException("Cause message"));
}
You could even use the hasProperty matcher to assert nested causes or to test the "getLocalizedMessage" method.
您甚至可以使用hasProperty匹配器来断言嵌套原因或测试“getLocalizedMessage”方法。
#4
11
It's JUnit version problem.
这是JUnit版本问题。
ExpectedException.expectCause()
is since 4.11.
ExpectedException.expectCause()从4.11开始。
No such method in 4.10 or lower.
在4.10或更低版本中没有这样的方法。
You should ensure your runtime JUnit version >= 4.11, same as your compile version.
您应确保运行时JUnit版本> = 4.11,与编译版本相同。
#5
4
To summarize all.
总结一下。
With JUnit 4 ( hamcrest 1.3 , and be careful, JUnit 4 depend on hamcrest-core which not include org.hamcrest.beans package)
使用JUnit 4(hamcrest 1.3,小心,JUnit 4依赖于hamcrest-core,不包括org.hamcrest.beans包)
So, you need to import:
所以,你需要导入:
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
Code:
码:
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testThatThrowsNiceExceptionWithCauseAndMessages(){
expectedException.expect(RuntimeException.class );
expectedException.expectMessage("Exception message");
expectedException.expectCause(
allOf(
isA(IllegalStateException.class),
hasProperty("message", is("Cause message"))
)
);
throw
new RuntimeException("Exception message",
new IllegalStateException("Cause message"));
}
#6
3
The any(Class<T>) matcher from hamcrest works nicely:
来自hamcrest的any(Class
@Rule
public ExpectedException thrown = ExpectedException.none();
...
@Test
public void testMethod()
{
thrown.expect(RuntimeException.class);
thrown.expectCause(org.hamcrest.Matchers.any(IllegalStateException.class));
}
#7
3
Normally I like more the following construction:
通常我更喜欢以下结构:
expectedException.expectCause(isA(NullPointerException.class));
expectedException.expectCause(ISA(NullPointerException.class));
#8
0
Import
进口
<dependency>
<groupId>it.ozimov</groupId>
<artifactId>java7-hamcrest-matchers</artifactId>
<version>1.3.0</version>
<scope>test</scope>
</dependency>
And then:
接着:
@Rule
public ExpectedException thrown = ExpectedException.none();
...
@Test
public void testMethod()
{
final String errorMessage = "error message";
Class<? extends Throwable> expectedCause = IllegalStateException.class;
thrown.expectCause(ExpectedException.exceptionWithMessage(expectedCause, errorMessage));
someServiceThatTrowsException.foo();
}
It works also with subtype of the cause. In other solutions I observed that they accept a supertype, that is wrong in my opinion.
它也适用于原因的子类型。在其他解决方案中,我观察到他们接受超类型,我认为这是错误的。
Message must be equal or contained in the cause's error message.
消息必须相等或包含在原因的错误消息中。
#9
0
You can do this entirely with built-in matchers org.hamcrest.Matchers.instanceOf
and org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage
:
您可以使用内置匹配器org.hamcrest.Matchers.instanceOf和org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage完全执行此操作:
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.both;
import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage;
public class temp {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void youCannotDivideByZero() {
expectedException.expect(RuntimeException.class);
expectedException.expectMessage(equalTo("Division exception"));
expectedException.expectCause(both(hasMessage(equalTo("/ by zero"))).and(instanceOf(ArithmeticException.class)));
divide(1, 0);
}
private float divide(int first, int second) {
try {
return first / second;
} catch(ArithmeticException e) {
throw new RuntimeException("Division exception", e);
}
}
}