すでに長い間存在しているアプリケーションの単体テストを書いています。テストする必要があるメソッドのいくつかは、次のようにビルドされています。
public void someMethod() throws Exception {
//do something
}
これらのメソッドをテストする場合は、ユニットテストで次のように記述する必要があります。
@Test
public void someTest() {
try {
someMethod();
}
catch (Exception e) {
e.printStackTrace();
}
}
これを行うのは良い習慣ですか?または、これらの方法をテストする他の方法はありますか?
私はインターネットでいくつかの調査を行い、@Rule
アノテーションと@Test(expected=Exception.class)
を使用したいくつかのソリューションを見つけましたが、それは機能していません(EclipseはテストでsomeMethod()
行を間違っていると表示し続けます)。これらが良いソリューションであるかどうかはわかりません。ユニットテストのストーリー全体はかなり新しいからです。
このことをよく知っている人が私を助けてくれたら、本当にありがたいです。
Exception
はチェック例外であるため、次のいずれかを行います。
try...catch
ステートメントで例外をキャッチする必要がある、またはあなたがそこに持っているものはうまくいきますが、私の個人的な好みは、スローされる例外を宣言することです。このように、テストの実行中に予期しない例外がスローされた場合、テストはfailになります。
@Test
public void someTest() throws Exception {
// dodgy code here
}
特定の例外がスローされるかどうかを確認する必要がある場合は、@Rule
を使用するか、値を@Test
アノテーションに直接追加するオプションがあります。
@Test(expected = FileNotFoundException.class)
public void someTest() throws Exception {
// dodgy code here
}
JUnit 5では、 Assertions.expectThrows
を利用して同じことを実現できます。編集の時点ではまだGAではないので、この全体にはあまり慣れていませんが、JUnit 5からのExecutable
を受け入れるようです。
@Test
public void someTest() {
assertThrows(FileNotFoundException.class, () ->
{ dodgyService.breakableMethod() };
}
@Test
public void someTest() {
try {
someMethod();
}
catch (Exception e) {
Assert.fail("Exception " + e);
}
}
例外が発生しない場合にできることです。別の方法は、次のように署名に例外をスローすることです。
@Test
public void someTest() throws Exception {
someMethod();
}
違いは、あるケースではテストがアサーション例外で失敗し、別のケースではテストがクラッシュしたために失敗することです。 (コードのどこかでNPEを取得し、そのためにテストが行われます)
あなたがこれをしなければならない理由は、Exceptionがチェックされた例外だからです。 チェック済み例外と未チェック例外 を参照してください
@Test(expected = Exception.class)は、例外がスローされることをテストするテスト用です。
@Test(expected=ArrayIndexOutOfBounds.class)
public void testIndex() {
int[] array = new int[0];
int var = array[0]; //exception will be thrown here, but test will be green, because we expect this exception
}
テストコードでアプリケーションの例外をキャッチしないでください。代わりに、上方向にスローされることを宣言します。
JUnitのTestRunner
がスローされた例外を見つけると、テストケースのerror
として自動的にログに記録されるためです。
メソッドがtestcase
をスローすることをException
が期待する場合にのみ、@Test(expected=Exception.class)
を使用するか、例外をキャッチする必要があります。
それ以外の場合は、単に上に投げて、
public void someTest() throws Exception {
テストメソッドシグネチャに例外を追加できます。次に、例外がスローされるかどうかをテストする場合は、@Test(expected=Exception.class)
を使用する必要があります。例外をスローする必要がないテストケースでは、テストは成功します。
@Test
public void testCaseWhereExceptionWontBeThrown() throws Exception {
someMethod(); //Test pass
}
@Test(expected = Exception.class)
public void testCaseWhereExceptionWillBeThrown() throws Exception {
someMethod(); //Test pass
}
Junitテスターで例外を処理する方法には、2つの主なルールがあります。
テストされたコードに例外が発生した場合:
expected
アノテーションのTest
属性で宣言してください。または、例外オブジェクト自体をさらにチェックする必要がある場合は、キャッチして無視します。 (この場合、予想される例外が生成されなかったことを示すために、try
ブロックの最後にAssert.fail
への呼び出しもなければなりません)。Exception.printStackTrace
への以前の呼び出しも有用です)。例外がテストされたコードに由来していないか、テストに関係ない場合(たとえば、IOExceptionsのほとんどは、テストが完了する前にネットワークレベルで生成されます完了することも可能)、それを再スローしますthrows
節で。
テスターで例外を予期する必要があるのはなぜですか?リマインド:コーディングする必要がありますテストされたコードのすべての可能な結果に対して1つのテストメソッド(高いコードカバレッジを達成するため):あなたの場合、1つのメソッドが正常に戻り、少なくとも1つのメソッド例外を生成する必要があります。
JUnitに関する3つのポイント:
テストは正確である必要があり、テスト入力の設定方法のみに基づいて明確に合格または失敗する必要があります。
テストでは、フレームワークにエラーが報告されます。
テストでは、出力を読み取ることに依存すべきではありません。
あなたの例は3つすべてのカウントで失敗します。例外がスローされるかどうかにかかわらず、テストは引き続きパスします。例外がスローされた場合、JUnitはそれを見つけられず、テスト結果に含めることができません。何かが間違っていることを知る唯一の方法は、テストがstdoutに書き込む内容を読み取ることです。これにより、エラーが無視しやすくなります。これはテストを書くのに便利な方法ではありません。
JUnitは、正しいことを簡単に行えるようにし、開発者に有益なフィードバックを提供するように設計されました。テストメソッドから例外がスローされると、フレームワークによってキャッチされます。テストに例外が予想されることを示す例外が付けられている場合、フレームワークはテストに合格のマークを付けます。そうでない場合、フレームワークはテストに失敗し、レポートのためにスタックトレースを記録します。フレームワークは、どのアサーションが失敗し、どのような予期しない例外が発生したかを報告するため、テストが機能したかどうかを全員が知ることができます。
例外をスローせずにテストが成功すると予想される場合、テスト内の何かがチェック済み例外をスローできる場合は、throws Exception
をテストメソッドシグネチャに追加します。 throws
を署名に追加してもメソッドhas toは何もスローしません。テストフレームワークがそれらをキャッチできるように、発生した例外をスローするだけです。
テストで実際に例外をキャッチする唯一のインスタンスは、例外に関するアサーションをテストする場所です。たとえば、例外に関するメッセージが予想どおりかどうか、または例外に原因が設定されているかどうかをテストできます。その場合、tryブロックの最後にAssert.fail()
を追加して、例外がスローされないとテストが失敗するようにします。
最初にテストを書くときは、失敗させます。そうすることで、テストの実行内容を知っていることを自分自身に証明し、障害が発生したときにそれが認識されることを確認します。
どんな例外ですか?それは...ですか
1の場合、try-catchはセレモニー以外の実際の目的に役立たないため、メソッドシグネチャレベルに配置します。
@Test
public void testFoo() throws Exception {
// ...
}
2.の場合、もう少し複雑になります。例外がスローされた場合はどうなるかを自問する必要があります。テストは失敗しますか?期待されますか?無関係ですか?これらのすべてを処理する方法の以下の例。 BEWARE:あなたがしたので、例外のみを使用しました。期待したもの以外にother例外がスローされる可能性がある場合、これらは非常に不安定になるため、実際にはそうではないことを願っています。可能であればException
を使用しないで、より具体的なものを使用してください(junitandコードで)。
// The below code assumes you've imported the org.junit.Assert class.
@Test
public void thisShouldFailIfExceptionCaught() {
//Given...
try {
// When...
} catch (Exception e) {
Assert.fail();
}
// Then...
}
@Test
public void thisShouldPassOnlyIfTheExceptionIsCaught() {
//Given...
try {
// When...
Assert.fail();
} catch (Exception expected) {}
// No "then" needed, the fact that it didn't fail is enough.
}
@Test
public void irrelevantExceptionThatCouldBeThrown() {
//Given...
try {
// When...
} catch (Exception e) {}
// Then...
}