GUI+DBのユニットテスト② Java

前回の続きです。
SampleFrameのテストを簡単にする為にユーティリティクラスを作ってみます。


Java SwingのテストはFEST-Swingを使います。
FEST-Swingを使えば、画面を操作しながらのテストを実行する事ができます。
FEST-Swingはココからダウンロードできます。


FEST-Swingを使うには画面のコンポーネントに名前を設定しておく必要があります。
例えば、テスト対象画面にある検索ボタンを押す操作をしたいときは、
予め検索ボタンに名前を設定しておく必要があります。

 JButton searchButton = new JButton("検索");
  searchButton.setName("searchButton");

 〜

 // 検索ボタンを押下
 FrameFixture frame = 〜
 frame.button("searchButton").click();


ですが、XXX.setName("XXX")のテスト用コードをいちいち書くのメンドクサイですよね。
なので、名前もリフレクションを使って自動的につけてしまいます。



GuiTestUtils.java

対象画面の中にあるコンポーネントをひたすら検索して名前をつけていくメソッドを実装しています。
継承フィールドとか子供コンポーネントも探して名前をつけていきます。

package sample;

import java.awt.Component;
import java.lang.reflect.Field;

import javax.swing.JComponent;

public class GuiTestUtils {

  public static void setComponentName(Object instance) throws Throwable {

    // クラスフィールドに名称を設定
    Class<?> clazz = instance.getClass();
    setComponentName(clazz, instance);

    // 子供コンポーネントに名称を設定
    if (instance instanceof JComponent) {
      Component[] list = ((JComponent) instance).getComponents();
      for (int i = 0; i < list.length; i++) {
        setComponentName(list[i]);
      }
    }

    // 継承フィールドに名称を設定
    Class<?> superClazz = clazz.getSuperclass();
    while (superClazz != null) {
      setComponentName(superClazz, instance);
      superClazz = superClazz.getSuperclass();
    }
  }

  private static void setComponentName(Class<?> clazz, Object instance) throws Throwable {

    Field[] field = clazz.getDeclaredFields();
    for (int i = 0; i < field.length; i++) {

      field[i].setAccessible(true);
      String name = field[i].getName();
      Object obj = field[i].get(instance);

      if (obj instanceof Component) {
        ((Component) obj).setName(name);
      }
    }
  }
}

FrameTester.java

Java Swing JFrmeを操作したりテストするクラスです。

setUp()メソッドで表示中の画面からテスト対象画面を検索してFrameFixtureクラスを生成します。
FrameFixtureクラスはFEST-Swingが提供するクラスで、画面を操作したりテストするいろいろなメソッドを持っています。
また、先程のGuiTestUtilsを使って、テスト対象画面の中にあるコンポーネントに名前をつけています。

package sample;

import java.awt.Frame;

import org.fest.swing.core.BasicRobot;
import org.fest.swing.finder.WindowFinder;
import org.fest.swing.fixture.FrameFixture;

public class FrameTester {

  private FrameFixture frame;

  public void setUp(Class<? extends Frame> frameClass) throws Throwable {
    this.setUp(frameClass, 1000);
  }

  public void setUp(Class<? extends Frame> frameClass, int delayBetweenEvents) throws Throwable {
    
    // 表示中の画面からテスト対象画面を検索
    this.frame = WindowFinder.findFrame(frameClass).using(BasicRobot.robotWithCurrentAwtHierarchy());
    // テスト操作時の遅延時間を設定
    this.frame.robot.settings().delayBetweenEvents(delayBetweenEvents);
    // テスト対象画面のコンポーネントに名称を設定
    GuiTestUtils.setComponentName(this.frame.target);
  }

  public void tearDown() throws Throwable {
    this.frame.cleanUp();
  }

  public FrameFixture getFrame() {
    return this.frame;
  }
}