2011年10月24日月曜日

簡単な後付けテストで基本を再確認

こんなクラスがあるとする。

public class Foo {
   private final Bar bar = new Bar();
   public String hoge() {
      return this.bar.baz().hoge();
   }
}
見ての通り、Foo は メソッド hoge()の中で、関連オブジェクト bar から取得した baz に、hoge() 処理を移譲している(日本語にすると、なんのこっちゃだが…)。

Bar と Baz は以下のような感じで後回しにしてある。

public class Bar {
   public Baz baz() {  throw new AssertionError();  }
}
public class Baz {
   public String hoge() {  throw new AssertionError(); }
}

ここで、Foo#hoge() をテストするにはどうするか。つまり以下の/* ??? */ のところに何を入れたらテストできるか。

public class FooTest {
   @Test public void hoge() {
      /* ??? */
      Assert.assertEquals("hello", new Foo().hoge());
   }
}

とりあえず2個だけ例を書いてみると(ちょっとずつニュアンスの違うものを何通りも書けるが)、以下のようになる。

@Test public void hoge1() {
   new Expectations() {
      @Mocked("baz") Bar bar;
      @Mocked("hoge") Baz baz; {
         bar.baz(); result = baz;
         baz.hoge(); result = "hello";
      }
   };
   Assert.assertEquals("hello", new Foo().hoge());
}
@Test public void hoge2() {
   new NonStrictExpectations() {
      Bar bar;
      Baz baz; {
         bar.baz(); result = baz; times=1;
         baz.hoge(); result = "hello"; times=1;
      }
   };
   Assert.assertEquals("hello", new Foo().hoge());
}
JMockit を使い始めたばかりだと、結構、とまどうんじゃないかと思う。デバッガで追ってみると、例えば "result = baz" のところで、初期化していないはずの baz に何故かインスタンスが設定されているし、代入されたと思った result が null のままだったりして、普通の Java ソースの感覚で読んでいると訳が分からなかったりする。

とは言ってもまあ、すぐ慣れるし、そうなると逆に、JMockit 無しのテストを考える事が、時折難しく感じられてくる。

ただ、JMockit を使うと後付けテストもかなり簡単になるにはなるけど、やっぱりテストファーストが基本というのは押さえておいた方が良い。この例はもともと簡単だから、それほど大変なテストコードにはならないけど、もっと複雑なものになると、後付けとテストファーストではテストコーディングの生産性が大きく違ってくる。

====

テストファースト版は、こっちに書いた。

0 件のコメント:

コメントを投稿