2011年11月1日火曜日

Eclipse と JMockit でテストファースト

以前のブログで、他の2つのクラスとのコラボレーションを含む簡単なクラスのテストをJMockitを使って書いたけど、その時は、敢えてレガシーコードに後付けテストを追加するような感じで書いてみた。

やろうとしている事は以下のようなものだった。

  1. 作ろうとしているのは Foo というクラスで、文字列を返すメソッド hoge() を持っている
  2. Foo#hoge() が返す文字列は、Baz#hoge() から取得したものである
  3. ただし、Baz のインスタンスは、Bar のインスタンスを経由しないと使えない
これを以下に、テストファーストで実装してみる。ただし今日は、Eclipse を極力活用するという趣向でやってみる。

====

まず①の クラス Foo とメソッド hoge()だけど、以下の様に、まず最初にテストクラスを書く。

public class FooTest {
   @Test public void hoge() {
      Assert.assertEquals("dummy", new Foo().hoge());
   }
}
まだクラス Foo が無いから当然コンパイルエラーの赤波が表示されるので、以下のように仮実装する。
 public class Foo {
   public String hoge() {
      return null;
   }
}
ただし、これをそのままタイプしてはいけない。Eclipse を使うという前提なのだから Ctrl+1を2回(クラスに一回、メソッドに一回)使うだけでタイプせずに済むので、これを活用する。
とりあえず、ここまでで JUnit を実行して、テストが失敗するのを見てから、hoge() の戻り値を"dummy"に変えて、テスト成功に変わるのを確認しておく

で次に、② の Baz#hoge() への委譲。これもテスト・コードから書く。

public class FooTest {
   @Test public void hoge() {
      new NonStrictExpectations() {
         Baz baz;
         {
            baz.hoge(); result = "dummy"; times = 1;
         }
      };
      Assert.assertEquals("dummy", new Foo().hoge());
   }
}
ここでももちろん、Baz も Baz#hoge() も未だ無いわけだから赤波が表示されるけど、さっきと同様に Ctrl+1 を 2回使って Baz の空実装を Eclipseに生成させる。ただし今度は Baz#hoge() の中身を以下の様に書き換える。
public class Baz {
   public String hoge() {
      //FIXME [your user name] Nov 1, 2011
      throw new AssertionError();
   }
}
自分の環境では、この FIXMEコメントから AssertionError送出の2行は、Java エディターのテンプレートに登録してあるので、fixme とタイプして Ctrl+1を押せば、その日の日付とログインしているユーザ名で2行挿入される。

で、赤波が消えたら、また JUnit を実行して Baz#hoge() が呼ばれていないというアサーション例外が上がるのを確認し、Foo#hoge() を以下の様に書き換える。
public String hoge() {
   return new Baz().hoge();
}
書いたらまた JUnitを実行して、今度は緑になるのを確認。

最後に、③ の Bar インスタンスを経由して Baz インスタンスを得るところ。これもやっぱりテストコードから。

public class FooTest {
   @Test public void hoge() {
      new NonStrictExpectations() {
         Baz baz;
         Bar bar;
         {
            bar.baz(); result = baz; times = 1;
            baz.hoge(); result = "dummy"; times = 1;
         }
      };
      Assert.assertEquals("dummy", new Foo().hoge());
   }
}
またここでも Baz#hoge() と同様に、Ctrl+1 をクラスとメソッドにそれぞれ適用して空実装を生成し、FIXME付きのアサーション例外送出コードを書いておく。

赤波が消えたらJUnit実行。Bar#baz() が呼ばれてないってアサーション例外が上がったら、おもむろに Fooを以下のように書き換える。
public class Foo {
   private final Bar bar = new Bar();
   public String hoge() {
      return this.bar .baz().hoge();
   }
}
但し、これも Ctrl+1 (→ Create field 〜)を活用し、無駄なタイピングをせずに編集する。できたら、Junit を実行しになることを確認。

というわけで、完了。

====

ちなみに、この間からかじり始めた Coq のチュートリアルの第2回で、結論から1個ずつ論理を遡って証明を完成させていく手順が紹介されていたけど、テストファーストと似ているところがあると思った。

0 件のコメント:

コメントを投稿