web-dev-qa-db-ja.com

junit @ Rule、expectCause()、hamcrestマッチャーを使用する

私にはテストがあります:

@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 testメソッドを介して実行すると、エラーが発生します。

Java.lang.NoSuchMethodError:org.junit.rules.ExpectedException.expectCause(Lorg/hamcrest/Matcher;)V

テストは問題なくコンパイルされます。

助けてください、例外の原因をテストする方法がわかりませんか?

25
Alexandr

このようにしてみてください:

@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および/または必要に応じて例外メッセージの共マッピングによって原因をチェックしないことを検討してください。 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));
}
24
Harmlezz

ここで説明されているカスタムマッチャー( 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"));
}
17
lazlev

静的インポートを使用し、クラスと原因例外のメッセージの両方をチェックして、もう少し簡単に説明します。

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」メソッドをテストしたりすることもできます。

17
borjab

JUnitのバージョンの問題です。

ExpectedException.expectCause()4.11 以降です。

4.1 以下では、そのようなメソッドはありません。

ランタイムJUnitバージョン> = 4.11は、コンパイルバージョンと同じにする必要があります。

すべてを要約します。

JUnit 4(hamcrest 1.3、注意してください、JUnit 4はorg.hamcrest.beansパッケージを含まないhamcrest-coreに依存しています)

したがって、インポートする必要があります:

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

Hamcrestのany(Class <T>)マッチャーはうまく機能します。

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

通常、私は以下の構造の方が好きです:

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

4
wikier

組み込みマッチャー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);
        }
    }
}
0
migwellian

インポート

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

原因のサブタイプでも機能します。他の解決策では、彼らがスーパータイプを受け入れることを観察しましたが、それは私の意見では間違っています。

メッセージは等しいか、原因のエラーメッセージに含まれている必要があります。

0
JeanValjean

Kotlin言語でメッセージとスローされた例外の原因を確認する例:

@get:Rule
val exceptionRule: ExpectedException = ExpectedException.none()

@Test
fun `test method`() {
    exceptionRule.expect(NestedServletException::class.Java)
    exceptionRule.expectMessage("error msg")
    exceptionRule.expectCause(instanceOf(IllegalStateException::class.Java))
    // ...
0
naXa