web-dev-qa-db-ja.com

予想される例外がgoogle-truthを使用してスローされていることをテストするにはどうすればよいですか?

特定のメッセージの例外がgoogle-truthを使用してスローされているかどうかをテストしたいだけです。

@Test(expected=を使用してjunitを使用してそれを行うのは非常に簡単ですが、真実でそれを行う方法を理解することはできません。 ThrowableSubject の周りにサンプルはありません。

この種のテストでは、プレーンなJUnitを使用する必要がありますか?

17
Imanol

[更新しました]

Truthの作成者は、JUnit 4.13/5のassertThrows()メカニズムを使用することをお勧めします。これは、Truthでのサポートを実際に必要としないためです。これは次のようになります。

_SpecificException e = 
    assertThrows(SpecificException.class, () -> doSomethingThatThrows());
assertThat(e).hasMessageThat().contains("blah blah blah");
assertThat(e).hasCauseThat().isInstanceOf(IllegalStateException.class);
assertThat(e).hasCauseThat().hasMessageThat().contains("blah");
_

これは、try/fail/catchよりも簡潔であり、「失敗の欠落」の問題を回避し、TruthのThrowableSubjectを使用してアサートできるオブジェクトを返すため、推奨されます。

assertThrows()がない場合は、try/fail/catchパターンを使用してください。これは明確で、明示的です。

_try {
  doSomethingThatThrows(); 
  fail("method should throw");
} catch (SpecificException e) {
  // ensure that e was thrown from the right code-path
  // especially important if it's something as frequent
  // as an IllegalArgumentException, etc.
  assertThat(e).hasMessage("blah blah blah");
}
_

_@Rule ExpectedException_と@Test(exception=...)はJUnitに存在しますが、合格するが失敗するはずのテストを書くことができる微妙な(そして微妙ではない)方法がある限り、これらは真理チームによって推奨されません。 。

これはtry/fail/catchにも当てはまりますが、内部的にGoogleは error-prone を使用してこれを軽減します。これは、このパターンが失敗を省略しないことを確認する静的コンパイル時チェックを提供します。 ()など。エラーが発生しやすい、または他の静的分析チェックを使用してこれらをキャッチすることを強くお勧めします。残念ながら、ルールベースおよびアノテーションベースのメソッドは、このtry/catchブロックほど静的分析に適していません。

17

ここでの更新として、Christianが説明したパターンから離れ、 Issue#219 は閉じられ、JUnitの expectThrows() (coming 4.1 では、同様のメソッドが TestNGのAssert )にすでに存在します。

expectThrows()と連携して、Truthを使用して スローされた例外に関するアサーション を作成できます。したがって、クリスチャンの例は次のようになります。

SpecificException expected = expectThrows(
    SpecificException.class, () -> doSomethingThatThrows());
assertThat(expected).hasMessageThat().contains("blah blah blah");
3
dimo414

現在、予想されるExceptiongoogle-truthで検証する組み込みの方法はありません。次のいずれかを実行できます。

google-truthには、同様の機能はないと思います。 Java 1.6 をサポートしているからです。

import com.google.common.truth.FailureStrategy;
import com.google.common.truth.Subject;
import com.google.common.truth.SubjectFactory;
import org.junit.Test;

import Java.util.concurrent.Callable;

import static com.google.common.truth.Truth.assertAbout;

public class MathTest {
    @Test
    public void addExact_throws_ArithmeticException_upon_overflow() {
        assertAbout(callable("addExact"))
            .that(() -> Math.addExact(Integer.MAX_VALUE, 1))
            .willThrow(ArithmeticException.class);
    }

    static <T> SubjectFactory<CallableSubject<T>, Callable<T>> callable(String displaySubject) {
        return new SubjectFactory<CallableSubject<T>, Callable<T>>() {
            @Override public CallableSubject<T> getSubject(FailureStrategy fs, Callable<T> that) {
                return new CallableSubject<>(fs, that, displaySubject);
            }
        };
    }

    static class CallableSubject<T> extends Subject<CallableSubject<T>, Callable<T>> {
        private final String displaySubject;

        CallableSubject(FailureStrategy failureStrategy, Callable<T> callable, String displaySubject) {
            super(failureStrategy, callable);
            this.displaySubject = displaySubject;
        }

        @Override protected String getDisplaySubject() {
            return displaySubject;
        }

        void willThrow(Class<?> clazz) {
            try {
                getSubject().call();
                fail("throws a", clazz.getName());
            } catch (Exception e) {
                if (!clazz.isInstance(e)) {
                    failWithBadResults("throws a", clazz.getName(), "throws a", e.getClass().getName());
                }
            }
        }
    }
}
2
heenenee