JUnitで異常放出をテストする方法

3875 ワード

最近TWUのTDDについての作業をしていて、JUnitで異常放出をテストする方法についていくつかの学習と思考を行いました.
ユニットテストを行う際に、ある方法が正しい異常を投げ出したかどうかをテストする必要がある場合があります.例えば、私はリストを読み取る方法があり、IndexOutOfBoundsExceptionを投げ出す可能性があります.ユニットテストでテストを通じて、この方法が正しいタイプの異常を正確に投げ出すことを保証したいと思っています.このようなテスト異常が正確に投げ出されたかどうかをまとめる方法は3つあります.
1. try…fail...catch…
@Test
public voidtestExceptionMessage() {
      try {
          new ArrayList<Object>().get(0);
          fail("Expected an IndexOutOfBoundsException to be thrown");
      } catch (IndexOutOfBoundsException anIndexOutOfBoundsException) {
          assertThat(anIndexOutOfBoundsException.getMessage(), is("Index: 0, Size: 0"));
      }  
}

この書き方は実装クラスの書き方と似ているように見え,異常が投げ出されない場合failメソッドが呼び出され,テストに失敗した情報が出力される. 
2.@Test(expected=xxx) 
@Test(expected= IndexOutOfBoundsException.class) 
  public void empty() { 
       new ArrayList<Object>().get(0);  
}

この書き方は簡単に見えますが、マークされたこのテスト方法のいずれかの操作が対応する異常を投げ出すと、このテストは合格する潜在的な問題があります.これは、異常な場所を投げ出す可能性があることを意味し、私たちが望んでいる操作ではありません.このような状況はtest caseを書くときに人為的に避けることができるが,異常放出をテストするより良い方法がある.
3.ExpectedException Rule
@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void shouldTestExceptionMessage() throws IndexOutOfBoundsException {
        List<Object> list = new ArrayList<Object>();
        thrown.expect(IndexOutOfBoundsException.class);
        thrown.expectMessage("Index: 0, Size: 0");
        list.get(0); // execution will never get past this line  
}

この方法は、所望の放出の異常タイプを指定することに加えて、放出時に同時に与えたい異常情報を指定することもできる.テストの前にRuleタグを使用してExpectedExceptionを指定し、対応するアクションをテストする前に所望のExceptionタイプ(IndexOutOfBoundException.classなど)を指定する必要があります.
この3つの方法は、対応する操作が所望の異常を投げ出したかどうかをテストすることができますが、どの方法がよりよく使用するのに適していますか?私のまとめは次のとおりです.
@Test(expected=xxx)>異常が正しく放出されているかどうかをまったく予測しない>@Test(expected=xxx)try...fail...catch>ExpectedException
try...fail...catchメソッドがExpectedExceptionより良いと思うのは、
1.try...fail...catchは一般的なtest functionのスタイルに合っており、まずある操作を行い、結果をassertする.一方,ExpectedExceptionの順序は,確かに期待される結果を示してから対応する操作を行う.
2.TDDのベストプラクティスは、test functionごとに1つのassertしかないが、同じtest functionで複数のassertを使用して異なる側面をテストする場合もある.ただし、ExpectedExceptionを使用して異常テストを行うと、現在のtest functionは終了し、expectの対応する操作の後にassertがある場合は自動的にスキップされ、try...fail...catchは現在のtest functionからスキップされず、その後のassertは順次実行されます.
3.ExpectedExceptionはJUnitから提供されているため、別のテストフレームワークを使用する場合はこのようなテスト方法は無効です.try/catchでは、より多くのテストフレームワークがサポートされています(failもJUnitが提供しています.別のテストフレームワークを使用する場合はfailを使用してテストに失敗した情報を与えることはできません).