2011年7月11日月曜日

JMockit と Swing と無名クラス

JMockit を使った Swing の UnitTest を考えてみる。今日はとりあえず、最初の一歩。
参考資料はこれ → Behavior-based testing with JMockit

====
まずこんなコードから始めてみる。Swing に限らず、GUI フレークワークの入門書の最初に出てくるような、何もないウィンドウを単に開いてみるだけのもの。
public class Exercise1 {
  public static void main(String[] args) {
     JFrame frame = new JFrame();
     frame.setSize(500, 300);
     frame.setVisible(true);
  }
}

要するに 500×300のウィンドウがビジブルになれば良い訳で、以下のようなテストコードになる。
public class Exercise1Test {
  @Test public void main() {
     new Expectations() {
        @NonStrict JFrame frame; {
        frame.setSize(500, 300);times=1;
        frame.setVisible(true);times=1;
     }};
     Exercise1.main(new String[]{});
  }
}

ここで、ウィンドウのクローズイベントに対応するアプリケーション終了処理が無い事に気づき、例えば、以下のように追加したとする。
public static void main(String[] args) {
  JFrame frame = new JFrame();
  frame.addWindowListener(new WindowAdapter() {
     @Override public void windowClosing(WindowEvent e) {
        System.exit(0);
     }
  });
  frame.setSize(500, 300);
  frame.setVisible(true);
}
この無名クラスを含むコードをどうやってテストするか。

以下のような方針をとってみた。
  • System クラスをパーシャルモックして、exit(0) 呼び出しを expect する(変な日本語だが…)。
  • 無名インナークラスについては、次のようにする。
    • addWindowListener に渡された、WindowListener を保持しておく。
    • main() 実行の後で、保持しておいた WindowListener のwindowClosing()を明示的に呼び出す。

コードはこんな感じ。
public class Exercise1Test2 {
  @Mocked({"exit"}) System system;
 
  static class WindowListenerCapturer implements Delegate {
     WindowListener captured;
     void addWindowListener(WindowListener l) {
        captured = l;
     };
  }
 
  @Test
  public void main() {
     final WindowListenerCapturer delegate = new WindowListenerCapturer();
     new Expectations() {
        @NonStrict JFrame frame; {
        frame.addWindowListener((WindowListener)any); result = delegate;
        frame.setSize(500, 300);times=1;
        frame.setVisible(true);times=1;
     }};
     new Expectations() {{
        System.exit(0);
     }};
     Exercise1.main(new String[]{});
     delegate.captured.windowClosing(null);
  }
}

ここでは、実際の実行パスの流れと同じになるように、main() からの Expectation と、windowClosing() からの Expectation を分けて書いてみた。

WindowListenerCapturer を使わないで、result = new Delegate() { ... }として、「...」のところで、windowClosing() を呼ぶやり方も試してみたが、何故か Eclipse プラグインがテスト終了を認識しない。

まあ上で示したコードでも、キャプチャのためのコードが若干増えることになるとはいえ、実行時の流れを表していると言う点では、却って分かりやすいような気もする。

0 件のコメント:

コメントを投稿