FEST-SwingでGoos本を写経したときのwork-around

 Goos本ではGUIのテスティングツールとしてwindowlickerを使用していますが、導入に際してビルドが通らず、写経のためだけに使うのも嫌だなということでFEST-Swingを使うことにしました。

 ところが、FEST-Swingでは「ラベルに表示された文字列が変更されたらその文字列をチェックしろ」といったことはできません*1

 そこでとったwork-aroundのコードが下記になります(抜粋なのでこれだけでは動きません)。

public class AuctionSniperDriver {
    private FrameFixture fixture; // どこかで初期化する
    
    public void showsSniperStatus(String statusText) throws InterruptedException {
        for (int i=0; i<10; i++) {
            try {
                fixture.label().requireText(statusText);
            } catch (AssertionError ex) {
                if (i==10) throw ex; // リトライの上限に達したらテスト失敗と判断
                Thread.sleep(200);   // 200msのインターバルを設ける
                continue;            // 失敗したらもう一度
            }
            break; // テストに成功するとここに到達する
        }
    }
}

 つまり、requireTextが失敗すればAssertionErrorが投げられるので、成功するか上限(ここでは2秒)に達するまでやり直すという方法になります。

 200ms以内にラベルの文字列が変わってしまうことは、おそらくないという想定です。

 誰向けの情報だよという感じですが、考えるのにちょっと時間がかかってしまったのでメモしておきました。

*1:windowlickerでどうしてるのか?ということを調べるの含めて、今後役に立たないだろうと思ってやっていません

FEST-Swingを使う (2) - すでに起動されたウィンドウを使用する場合のテンプレート

< (1) テスト内でウィンドウを起動する場合のテンプレート

1. 概要

前回はテスト内でウィンドウを起動したため、ウィンドウのインスタンスFrameFixtureコンストラクタに渡すことができました。

しかし、End-to-Endテストなどで直接インスタンスが取得できない場合があります。 今回はこういった場合に、既に起動されているウィンドウからテスト対象ウィンドウを取得する方法を紹介します。

2. サンプル

LabelWindow.java:ラベルにHelloと表示するウィンドウ(前回と同じなので割愛)

LaunchLabelWindow.java:LabelWindowを起動

LaunchLabelWindowTest.java:起動されたLabelWindowでラベルがHelloであるかをテストする

// LaunchLabelWindow.java

package festsample;

public class LaunchLabelWindow {
    public static void Launch() {
        new LabelWindow();
    }
}
// LaunchLabelWindowTest.java

package festsample;

import org.fest.swing.core.BasicRobot;
import org.fest.swing.finder.WindowFinder;
import org.fest.swing.fixture.FrameFixture;
import org.junit.After;
import org.junit.Test;
import org.junit.Before;

public class LaunchLabelWindowTest {
    private FrameFixture fixture;
    
    @Before
    public void before() {
        // ウィンドウが外部で起動される
        LaunchLabelWindow.Launch();
        
        // 名前が"Label-Window"のウィンドウを、1秒以内に探す
        fixture = WindowFinder
                .findFrame("Label-Window")
                .withTimeout(1000)
                .using(BasicRobot.robotWithCurrentAwtHierarchy());
    }
    
    @After
    public void after() {
        fixture.cleanUp();
    }
    
    @Test
    public void 起動中のLabelWindowにHelloが表示されていること() {
        fixture.label("label1").requireText("Hello");
    }
}

before()findFrameの引数でウィンドウの名前を指定します*1

withTimeoutは探す時間のタイムアウト時間(ミリ秒)です。

前回と比べるとEDTセーフな記述がなくなっている分、コードが短くなっています。

見つからなかった場合

指定した名前のウィンドウが表示されていない(名前が間違っている)といった理由でfindFrameがタイムアウトした場合、次のようなエラーメッセージが表示されます。

Timed out waiting for component to be found using matcher org.fest.swing.core.NameMatcher[name='Label-Window', type=java.awt.Frame, requireShowing=true]
Unable to find component using matcher org.fest.swing.core.NameMatcher[name='Label-Window', type=java.awt.Frame, requireShowing=true].

[]内がFESTの想定している条件なので、これをたよりにデバッグしてください。

3. 参考

http://docs.codehaus.org/display/FEST/Testing+Long-Duration+Tasks

http://docs.codehaus.org/display/FEST/Looking+up+Components+with+ComponentFinder

*1:「ウィンドウの名前」とは、LabelWindow.javaにおいてsetNameで指定した名前です。LabelWindowは「Label-Window」という名前が設定されています。

FEST-Swingを使う (1) - テスト内でウィンドウを起動する場合のテンプレート

(2) すでに起動されたウィンドウを使用する場合のテンプレート >

1. 概要

FEST-SwingはJavaGUIツールキットであるSwingのテスティングツールです。
今回は、そのテンプレートをメモします。

2. サンプル

[テスト対象]
 LabelWindow.java :"Hello"と書かれたラベルを表示するウィンドウ

[テスト]
 LabelWindowTest.java:「文字列"Hello"が表示されているか」をテストします

// LabelWindow.java

package festsample;

import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;

/** LabelにHelloと表示するウィンドウ */
public class LabelWindow extends JFrame {
    
    private JLabel label;
    
    public LabelWindow() {
        label = new JLabel("Hello");
        label.setName("label1");
        add(label, BorderLayout.NORTH);
        
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(200, 100);
        setName("Label-Window");
        setVisible(true);
    }
}
// LabelWindowTest.java

package festsample;

import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
import org.fest.swing.edt.GuiActionRunner;
import org.fest.swing.edt.GuiQuery;
import org.fest.swing.fixture.FrameFixture;
import org.junit.After;
import org.junit.Test;
import org.junit.Before;
import org.junit.BeforeClass;

public class LabelWindowTest {
    
    private FrameFixture fixture;
    
    @BeforeClass
    public static void beforeClass() {
        FailOnThreadViolationRepaintManager.install();
    }
    
    @Before
    public void before() {
        // 新たにウィンドウを作成する
        LabelWindow window = GuiActionRunner.execute(new GuiQuery<LabelWindow>() {
            @Override
            protected LabelWindow executeInEDT() throws Throwable {
                return new LabelWindow();
            }
        });
        fixture = new FrameFixture(window);
        fixture.show();
    }
    
    @After
    public void after() {
        fixture.cleanUp();
    }
    
    @Test
    public void ラベルがHelloであること() {
        fixture.label("label1").requireText("Hello");
    }
}

@BeforeClass@Before@Afterには、Swingのスレッドに関するルールを守る上で必要な処理が記述されています。*1。 別のウィンドウをテスト対象にするにはLabelWindowをnewしている行(とテストケース)を書き換えます。

テスト自体は@Testに書かれた一行だけです。labelで引数に指定した名前(setTextで設定したもの)のラベルを取得し、requireTextでラベルに表示されているべき文字列をassertしています。

3. 参考

インストール方法:http://d.hatena.ne.jp/torutk/20110130/p1

テストコード:http://docs.codehaus.org/display/FEST/Getting+Started