それを行う1つの方法は、
@Test
public void foo(){
try{
//execute code that you expect not to throw Exceptions.
}
catch(Exception e){
fail("Should not have thrown any exception");
}
}
これを行うためのより明確な方法はありますか?(おそらくJUnitを使用してい@Rule
ますか?)
それを行う1つの方法は、
@Test
public void foo(){
try{
//execute code that you expect not to throw Exceptions.
}
catch(Exception e){
fail("Should not have thrown any exception");
}
}
これを行うためのより明確な方法はありますか?(おそらくJUnitを使用してい@Rule
ますか?)
回答:
あなたはこれに間違った方法で取り組んでいます。機能をテストするだけです。例外がスローされた場合、テストは自動的に失敗します。例外がスローされない場合、テストはすべて緑色になります。
この質問は時々興味を引くことに気づいたので、少し拡大します。
ユニットテストを行う場合は、作業の単位と見なすものを自分で定義することが重要です。基本的には、単一の機能を表す複数のメソッドまたはクラスを含む場合と含まない場合があるコードベースの抽出。
または、Art of Unit Testing、2nd Edition by Roy Osherove、11ページで定義されているように:
ユニットテストは、テストされている作業単位を呼び出し、そのユニットのシングルエンド結果に関するいくつかの仮定をチェックするコードを自動的に一枚です。ユニットテストは、ほとんどの場合、ユニットテストフレームワークを使用して記述されます。それは簡単に書くことができ、迅速に実行されます。信頼でき、読みやすく、保守可能です。量産コードが変更されていない限り、結果は一貫しています。
理解しておくべき重要なことは、1つの作業単位は通常1つの方法だけではなく、非常に基本的なレベルでは1つの方法であり、その後他の作業単位によってカプセル化されるということです。
理想的には、作業の個別の単位ごとにテストメソッドを用意して、どこで問題が発生しているのかを常に即座に確認できるようにする必要があります。この例では、getUserById()
ユーザーを返す基本的なメソッドが呼び出され、合計3ユニットの作品があります。
最初の作業単位では、有効な入力と無効な入力の場合に、有効なユーザーが返されるかどうかをテストする必要があります。
データソースによってスローされている例外はすべてここで処理する必要があります。ユーザーが存在しない場合、ユーザーが見つからないときに例外がスローされることを示すテストが必要です。このサンプルはIllegalArgumentException
、@Test(expected = IllegalArgumentException.class)
アノテーションでキャッチされたものである可能性があります。
この基本的な作業単位のすべてのユースケースを処理したら、レベルを上げます。ここでもまったく同じことを行いますが、現在のレベルのすぐ下のレベルからの例外のみを処理します。これにより、テストコードが適切に構造化され、どこにでも移動する必要がなく、アーキテクチャ全体をすばやく実行して、問題点を見つけることができます。
この時点で、これらの例外をどのように処理するかが明確になっているはずです。入力には、有効な入力と誤った入力の2種類があります(入力は厳密には有効ですが、正しくありません)。
有効な入力で作業するときは、作成したテストが機能するという暗黙の期待値を設定します。
このようなメソッド呼び出しは次のようになりますexistingUserById_ShouldReturn_UserObject
。このメソッドが失敗した場合(例:例外がスローされた場合)、問題が発生したことがわかり、掘り始めることができます。
誤った入力nonExistingUserById_ShouldThrow_IllegalArgumentException
を使用し、例外を予期する別のテスト()を追加することにより、メソッドが間違った入力で行うことになっていることをメソッドが実行するかどうかを確認できます。
テストで2つのことを実行しようとしました。有効な入力と誤った入力を確認してください。これを2つの方法に分割して、それぞれが1つのことを行うことで、テストがより明確になり、どこがうまくいかないのかについての概要が大幅に改善されます。
階層化された作業単位を覚えておくことで、階層の上位にあるレイヤーに必要なテストの量を減らすこともできます。これは、下位のレイヤーで問題が発生した可能性があるすべてのことを説明する必要がないためです。現在のレイヤーの下のレイヤーは、依存関係が機能するという事実上の保証であり、何か問題が発生した場合は、現在のレイヤーにあります(下位レイヤー自体がエラーをスローしない場合)。
expected
アノテーションを使用する必要があります。コードが失敗するシナリオをテストし、エラーが正しく処理されているかどうかを確認したい場合は、expected
アサートを使用して、解決されているかどうかを確認します。
throws IllegalArgumentException
テストに追加します。最後に必要なのは、例外がある場合、テストが赤くなることです。さて、何を推測しますか?書く必要はありませんfail()
。@Jeroen Vannevelが書いたように:「例外がスローされると、テストは自動的に失敗します。」
SonarQubeのルール「squid:S2699」:「このテストケースに少なくとも1つのアサーションを追加する」ので、私はこれに遭遇しました。
私は単純なテストをしましたが、その唯一の目的は例外をスローせずに通過することでした。
この単純なコードを考えてみましょう:
public class Printer {
public static void printLine(final String line) {
System.out.println(line);
}
}
このメソッドをテストするためにどのようなアサーションを追加できますか?確かに、その周りで試行錯誤を行うことはできますが、それはコードの肥大化にすぎません。
ソリューションはJUnit自体から来ています。
例外がスローされず、この動作を明示的に説明する場合expected
は、次の例のように追加するだけです。
@Test(expected = Test.None.class /* no exception expected */)
public void test_printLine() {
Printer.printLine("line");
}
Test.None.class
期待値のデフォルトです。
Assertions.assertThatCode(() -> toTest.method())
.doesNotThrowAnyException();
JUnit 5(Jupiter)には、例外の有無を確認するための3つの機能があります。
assertAll()
アサートすることを全て供給executables
例外をスローしません。
assertDoesNotThrow()
アサートの実行
供給をexecutable
/ supplier
スローしませんあらゆる種類の例外を。
この関数は
、JUnit 5.2.0(2018年4月29日)以降で使用できます。
assertThrows()
アサート付属の実行がexecutable
スローの例外expectedType
とリターンの例外を。
package test.mycompany.myapp.mymodule;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
class MyClassTest {
@Test
void when_string_has_been_constructed_then_myFunction_does_not_throw() {
String myString = "this string has been constructed";
assertAll(() -> MyClass.myFunction(myString));
}
@Test
void when_string_has_been_constructed_then_myFunction_does_not_throw__junit_v520() {
String myString = "this string has been constructed";
assertDoesNotThrow(() -> MyClass.myFunction(myString));
}
@Test
void when_string_is_null_then_myFunction_throws_IllegalArgumentException() {
String myString = null;
assertThrows(
IllegalArgumentException.class,
() -> MyClass.myFunction(myString));
}
}
Java 8ではこれがはるかに簡単になり、Kotlin / Scalaでは二重になっています。
少しユーティリティクラスを書くことができます
class MyAssertions{
public static void assertDoesNotThrow(FailingRunnable action){
try{
action.run()
}
catch(Exception ex){
throw new Error("expected action not to throw, but it did!", ex)
}
}
}
@FunctionalInterface interface FailingRunnable { void run() throws Exception }
そしてあなたのコードは単純になります:
@Test
public void foo(){
MyAssertions.assertDoesNotThrow(() -> {
//execute code that you expect not to throw Exceptions.
}
}
Java-8にアクセスできない場合は、痛々しいほど古いJava機能を使用します。任意のコードブロックと簡単なコメントです。
//setup
Component component = new Component();
//act
configure(component);
//assert
/*assert does not throw*/{
component.doSomething();
}
そして最後に、kotlinを使用して、最近好きになった言語は次のとおりです。
fun (() -> Any?).shouldNotThrow()
= try { invoke() } catch (ex : Exception){ throw Error("expected not to throw!", ex) }
@Test fun `when foo happens should not throw`(){
//...
{ /*code that shouldn't throw*/ }.shouldNotThrow()
}
あなたがこれをどのように表現したいかをいじくる余地はたくさんありますが、私は常に流暢な主張のファンでした。
について
あなたはこれに間違った方法で取り組んでいます。機能をテストするだけです。例外がスローされた場合、テストは自動的に失敗します。例外がスローされない場合、テストはすべて緑色になります。
これは原則として正しいですが、結論としては正しくありません。
Javaでは、制御フローの例外を許可しています。これはDouble.parseDouble
、a NumberFormatException
やPaths.get
を介したAPIなどのJREランタイム自体によって行われますInvalidPathException
。
Double.ParseDouble
多分正規表現、多分手書きのパーサー、または倍精度浮動小数点数の範囲を特定の何かに制限する他のドメインルールを埋め込むものを使用して、の数値文字列を検証するコンポーネントを作成した場合、これをテストする最善の方法成分?明らかなテストは、結果の文字列が解析されたときに例外がスローされないことを主張することだと思います。上記assertDoesNotThrow
または/*comment*/{code}
ブロックのいずれかを使用して、そのテストを記述します。何かのようなもの
@Test public void given_validator_accepts_string_result_should_be_interpretable_by_doubleParseDouble(){
//setup
String input = "12.34E+26" //a string double with domain significance
//act
boolean isValid = component.validate(input)
//assert -- using the library 'assertJ', my personal favourite
assertThat(isValid).describedAs(input + " was considered valid by component").isTrue();
assertDoesNotThrow(() -> Double.parseDouble(input));
}
私はまた、上でこのテストをパラメータ化することをお勧めしますinput
使用してTheories
またはParameterized
あなたがより簡単に他の入力のために、このテストを再利用できるようにします。または、エキゾチックなものにしたい場合は、テスト生成ツール(およびこれ)を使用できます。TestNGはパラメーター化されたテストをよりよくサポートしています。
私は特に嫌見つけることは使用しての勧告で@Test(expectedException=IllegalArgumentException.class)
、この例外が危険なほど広いです。テスト対象のコンポーネントのコンストラクターのようにコードが変更されif(constructorArgument <= 0) throw IllegalArgumentException()
、テストがその引数に0を提供していたのは便利であり、これは非常に一般的なことです。テストデータを適切に生成するのは驚くほど難しい問題です。何もテストしていなくても、緑色のバーになります。そのようなテストは役に立たないよりも悪いです。
Assert.assertThrows
して、一部のコードが例外をスローすることを確認できます。
コードのすべてのエラーをキャッチできるほど運が悪い場合。あなたは愚かにすることができます
class DumpTest {
Exception ex;
@Test
public void testWhatEver() {
try {
thisShouldThrowError();
} catch (Exception e) {
ex = e;
}
assertEquals(null,ex);
}
}
Exception ex
すべき= null;
です。
この投稿は現在6歳ですが、Junitの世界では多くの変化がありました。Junit5を使用すると、
org.junit.jupiter.api.Assertions.assertDoesNotThrow()
例:
public void thisMethodDoesNotThrowException(){
System.out.println("Hello There");
}
@Test
public void test_thisMethodDoesNotThrowException(){
org.junit.jupiter.api.Assertions.assertDoesNotThrow(
()-> thisMethodDoesNotThrowException()
);
}
Junit5の新しいバージョンを使用している人々の助けになることを願っています
Awaitility
「S untilAsserted(ThrowingRunnable assertion)
。テスト中のシステムは現在、提供するThrowingRunnableで特定の例外をスローしていますが、停止するまで少し時間がかかります。ただし、別の例外がスローされる場合は、テストがすぐに失敗するようにします。
テストターゲットが例外を消費するかどうかをテストする場合。テストは(jMock2を使用したコラボレーターのモック)のままにしておきます。
@Test
public void consumesAndLogsExceptions() throws Exception {
context.checking(new Expectations() {
{
oneOf(collaborator).doSth();
will(throwException(new NullPointerException()));
}
});
target.doSth();
}
ターゲットがスローされた例外を消費する場合、テストはパスします。そうでない場合、テストは失敗します。
例外消費ロジックをテストする場合、状況はさらに複雑になります。消費をあざける可能性のある協力者に委託することをお勧めします。したがって、テストは次のようになります。
@Test
public void consumesAndLogsExceptions() throws Exception {
Exception e = new NullPointerException();
context.checking(new Expectations() {
{
allowing(collaborator).doSth();
will(throwException(e));
oneOf(consumer).consume(e);
}
});
target.doSth();
}
ただし、ログに記録したいだけの場合は、過剰に設計されていることがあります。この場合には、この記事(http://java.dzone.com/articles/monitoring-declarative-transac、http://blog.novoj.net/2008/09/20/testing-aspect-pointcuts-is-there -an-easy-way /)この場合、tddを要求した場合に役立つことがあります。
@Test
public void foo() {
try {
//execute code that you expect not to throw Exceptions.
} catch (Exception e){
assertNull(e);
}
}
assertNull
はないため、も実行されません。しかし、すぐに読者は、スローされないケースを本当に検証するアサーションが作成されたという印象を受けます。言い換えると、catchブロックに到達した場合、例外は常にnull以外であり、単純なで置き換えることができますfail
。
assertNull(e)
記述e
できないようnull
に、テストが失敗したと報告しcatch
ます...マイクこれはただの奇妙なプログラミングです:-/。 ..はい、少なくともfail()
アンドレアスが言うように使用
ルールを作成することで、例外がスローされないことを期待できます。
@Rule
public ExpectedException expectedException = ExpectedException.none();
これは最善の方法ではないかもしれませんが、テストされているコードブロックから例外がスローされないことを確実にします。
import org.assertj.core.api.Assertions;
import org.junit.Test;
public class AssertionExample {
@Test
public void testNoException(){
assertNoException();
}
private void assertException(){
Assertions.assertThatThrownBy(this::doNotThrowException).isInstanceOf(Exception.class);
}
private void assertNoException(){
Assertions.assertThatThrownBy(() -> assertException()).isInstanceOf(AssertionError.class);
}
private void doNotThrowException(){
//This method will never throw exception
}
}
private val
?この言語はなんですか?明らかにJavaではありません; pそして、スクリーンショットとしてコードを提供しないでください、それは歓迎されません。
junitからのアサーションに基づいて、任意の種類の独自のアサーションを作成できます。
static void assertDoesNotThrow(Executable executable) {
assertDoesNotThrow(executable, "must not throw");
}
static void assertDoesNotThrow(Executable executable, String message) {
try {
executable.execute();
} catch (Throwable err) {
fail(message);
}
}
そしてテスト:
//the following will succeed
assertDoesNotThrow(()->methodMustNotThrow(1));
assertDoesNotThrow(()->methodMustNotThrow(1), "fail with specific message: facepalm");
//the following will fail
assertDoesNotThrow(()->methodMustNotThrow(2));
assertDoesNotThrow(()-> {throw new Exception("Hello world");}, "Fail: must not trow");
一般的に言えば、シナリオに関係なく、意味のある場所でテストを即座に失敗させる可能性があります( "bla bla bla")。たとえば、テストケースで何かがスローされた場合に失敗するように、try / catchブロックでそれを使用します。
try{methodMustNotThrow(1);}catch(Throwable e){fail("must not throw");}
//or
try{methodMustNotThrow(1);}catch(Throwable e){Assertions.fail("must not throw");}
これは私たちがテストするメソッドのサンプルです。特定の状況で失敗してはならないが、失敗する可能性があるメソッドがあると仮定します。
void methodMustNotThrow(int x) throws Exception{
if (x == 1) return;
throw new Exception();
}
上記の方法は簡単なサンプルです。しかし、これは障害がそれほど明白ではない複雑な状況で機能します。インポートがあります:
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import static org.junit.jupiter.api.Assertions.*;