2012年8月6日月曜日

システム例外を扱うテストコードを JMockit で書いてみる

外部のライブラリで発生した例外のハンドリングを、どうやってテストファーストで書くか。これを示してみる。

====

お題は、以下のようなもの。

java.io の API を使って、テキストファイルから最初の 1行目を読み込むメソッド loadText() があり、クラス ExceptionalFugafuga で定義されている。またテストコードも既に書いてある。ただし IOException 発生時のコードは未定のままになっている。

本体コード。
public class ExceptionalFugafuga {
   public String loadText() {
      try (BufferedReader reader = new BufferedReader(new FileReader("fuga.txt"))) {
         return reader.readLine();
      } catch (IOException exep) {
         throw new AssertionError(); // ★ 後回しの暫定コード
      } 
  }
}
こっちはテストコード。
public class ExceptionalFugafugaTest {
   @Mocked BufferedReader br = null;
   @Mocked FileReader reader= null;
   @Test public void loadText() throws Exception {
      new NonStrictExpectations() {{
         br.readLine(); result="the first line";
      }};
      assertEquals("the first line", new ExceptionalFugafuga().loadText());
   }
}
ここで、IOException をキャッチしたときの暫定コードを、"例外: "+例外メッセージという文字列を返すように修正したい。これをテストファーストでやるとどうなるか。

まずテストコードから。
こんなテストメソッドを追加する。

@Test public void loadText_IOException() throws Exception {
  new Expectations() {{
    new FileReader("fuga.txt"); result = new IOException("はあこりゃこりゃ");
  }};
  assertEquals("例外: はあこりゃこりゃ", new ExceptionalFugafuga().loadText());
}
本体コードがまだそのままなので、テストが失敗して赤くなる。

で、AssertionError() を上げているところを "return "例外: " + exep.getMessage();"に変える。

再度実行し、今度はグリーンになる事を確認する。以上。

====

昔なら、テストメソッド loadText() の @Before とか @After で、実ファイル "fuga.txt" を作ったり消したりしていたところだけど、見ての通り、モックツールを使うとそういうのはいらなくなる。

例外に関しても同じようなことで、例外を発生させる状況を作りだすのではなく、単に例外を投げ上げる振る舞いに差し替えればいい。「Unit」としてテストするとは、本来はこうやって環境から隔離して実施するのものではなかったかと思う。同じやり方は DB例外 でも WebService 例外でも、なんでも応用が効く。

0 件のコメント:

コメントを投稿