J'ai un contrôle:
@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();
}
Lorsqu'il est exécuté via la méthode de test mvn, j'obtiens l'erreur suivante:
Java.lang.NoSuchMethodError: org.junit.rules.ExpectedException.expectCause (Lorg/hamcrest/Matcher;) V
Test compile bien.
S'il vous plaît, aidez-moi, vous ne pouvez pas comprendre comment tester la cause de l'exception?
Essayez de cette façon:
@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);
}
Envisagez de ne pas vérifier la cause par des égaux, mais par IsInstanceOf et/ou comapring le message d'exception si nécessaire. En comparant la cause par égaux, vérifiez également le stacktrace, qui peut être plus que ce que vous souhaitez tester/vérifier. Comme ceci par exemple:
@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));
}
Vous pouvez utiliser un matcher personnalisé comme décrit ici ( http://www.javacodegeeks.com/2014/03/junit-expectedexception-rule-beyond-basics.html ) pour rechercher la cause d'une exception.
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);
}
}
@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"));
}
Un peu plus brièvement avec les importations statiques et en vérifiant à la fois la classe et le message de l'exception de cause:
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"));
}
Vous pouvez même utiliser le matcher hasProperty pour affirmer des causes imbriquées ou pour tester la méthode "getLocalizedMessage".
Pour résumer tout.
Avec JUnit 4 (hamcrest 1.3, et soyez prudent, JUnit 4 dépend de hamcrest-core qui n'inclut pas le package org.hamcrest.beans)
Donc, vous devez importer:
<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"));
}
Normalement j'aime plus la construction suivante:
expectedException.expectCause(isA(NullPointerException.class));
Le quelconque (classe <T>) de hamcrest fonctionne très bien:
@Rule
public ExpectedException thrown = ExpectedException.none();
...
@Test
public void testMethod()
{
thrown.expect(RuntimeException.class);
thrown.expectCause(org.hamcrest.Matchers.any(IllegalStateException.class));
}
Vous pouvez le faire entièrement avec les corrélateurs intégrés org.hamcrest.Matchers.instanceOf
et 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);
}
}
}
Importation
<dependency>
<groupId>it.ozimov</groupId>
<artifactId>Java7-hamcrest-matchers</artifactId>
<version>1.3.0</version>
<scope>test</scope>
</dependency>
Et alors:
@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();
}
Cela fonctionne aussi avec le sous-type de la cause. Dans d'autres solutions, j'ai observé qu'ils acceptaient un supertype, ce qui est faux à mon avis.
Le message doit être égal ou contenu dans le message d'erreur de la cause.