Использование junit @Rule, expectCause() и hamcrest matchers

У меня есть тест:

@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();
}

При запуске через mvn метод проверки, я получаю ошибку:

java.lang.NoSuchMethodError: org.junit.rules.ExpectedException.expectCause(Lorg/Hamcrest/Сличитель;) В

Тестовый компилятор отлично.

Пожалуйста, помогите мне, не можете понять, как проверить причину исключения?

Ответы

Ответ 1

Вы можете использовать пользовательский матчи, как описано здесь (http://www.javacodegeeks.com/2014/03/junit-expectedexception-rule-beyond-basics.html), чтобы проверить причину исключения.

Пользовательский сокет

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"));
}

Ответ 2

Попробуйте так:

@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);
}

Считайте, что не следует проверять причину на равных, но IsInstanceOf и/или компилировать сообщение об исключении, если это необходимо. Сравнивая причину на равных, проверьте также стек, что может быть больше, чем вы хотели бы проверить/проверить. Например, например:

@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

Проблема с версией JUnit.

ExpectedException.expectCause() с тех пор 4.11.

Нет такого метода в 4.10 или ниже.

Вы должны обеспечить свою версию JUnit версии >= 4.11, такую ​​же, как ваша компиляционная версия.

Ответ 4

Немного короче со статическим импортом и проверкой как класса, так и сообщения об исключении причины:

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"));
}

Вы даже можете использовать совпадение hasProperty для утверждения вложенных причин или для проверки метода getLocalizedMessage.

Ответ 5

Любой (класс <T> ) счётчик от hamcrest прекрасно работает:

@Rule
public ExpectedException thrown = ExpectedException.none();
...
@Test
public void testMethod()
{
    thrown.expect(RuntimeException.class);
    thrown.expectCause(org.hamcrest.Matchers.any(IllegalStateException.class));
}

Ответ 6

Подводя итог всем.

С JUnit 4 (hamcrest 1.3, и будьте осторожны, JUnit 4 зависит от ядра hamcrest, который не включает пакет org.hamcrest.beans)

Итак, вам нужно импортировать:

<dependency>
  <groupId>org.hamcrest</groupId>
  <artifactId>hamcrest-all</artifactId>
  <version>1.3</version>
  <scope>test</scope>
</dependency>

код:

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"));
}

Ответ 7

Обычно мне больше нравится следующая конструкция:

expectedException.expectCause(isA(NullPointerException.class));

Ответ 8

Импорт

<dependency>
  <groupId>it.ozimov</groupId>
  <artifactId>java7-hamcrest-matchers</artifactId>
  <version>1.3.0</version>
  <scope>test</scope>
</dependency>

И затем:

@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();
}

Он также работает с подтипом причины. В других решениях я заметил, что они принимают супертип, это неправильно, по моему мнению.

Сообщение должно быть равно или содержать сообщение об ошибке причины.