FESTを使用してJava GUI (Swing)のテストを実行してみる
FEST-Swingを使用してみた手順を記載する。なお、NetBeans用プラグインも存在するが、現時点ではリリースされているバージョンより古いものがインストールされる。ライブラリを自動で作成してくれる程度のことしか行っていないように見えるので、プラグインにこだわる必要は無いだろう。
環境設定
テストライブラリにfest-assert-1.0.jar, fest-reflect-1.0.jar, fest-swing-1.0.jar, fest-util-1.0.jarを追加する。(これらはプラグインに含まれていたものであり、実際に全て使用しているのかは未検証)
恒常的に使用するのであれば、ライブラリ化しておくと良いだろう。
1つのチェックボックスの状態をテストする
チェックボックスを用いてテストを行ってみる。今回はJUnit4.5を使用した。
以下がテスト用のウィンドウである。JFrameの中にチェックボックスコンポーネントを1個配置した(ソースコード)。
まず、テストケース実行前後に以下の処理を実行させる。
@Before
public void setUp() {
window = new FrameFixture(new NewJFrame());
window.show(); // shows the frame to test
}
@After
public void tearDown() {
window.cleanUp();
}続いて、チェックボックスが選択された状態になっていることを確認するテストケースを作成する(ソースコード)。
@Test
public void testCheckBox() {
window.checkBox().requireSelected();
}ここまでのNetBeansプロジェクトとソースコードはこちら(NetBeansで実行するには、test_lib以下に冒頭のfestライブラリをコピーする必要がある)。
Shift+F6を押してテストケースを実行してみると、下記のエラーとなる(折り返されて見づらいが、実際には1行で表示される)。
junit.framework.AssertionFailedError: [javax.swing.JCheckBox[name=null, text='チェックボックス', selected=false, enabled=true, visible=true, showing=true] - property:'selected'] expected:<true> but was:<false>
selected(true)を期待していたが、実際にはfalseになっている、というJUnitの報告が挙がっている。
そこで、起動初期状態として、チェックボックスが選択された状態にするコードを追加する。
public NewJFrame() {
initComponents();
jCheckBox1.setSelected(true); // 追加
}NewJFrame.javaに上記の3行目を追加し、Ctrl+F6でテストを実行する。結果、JUnitは成功して終了する。[補足:本来は、この程度であれば上記のように手でコードを追加するより、Mattise上のプロパティ(下図)で設定を行った方が、手段の統一としては良いのかもしれない]
2つのチェックボックスの状態をチェックする
先ほどJUnitが成功したJFrameに、チェックボックスをもう1つ追加する(プロジェクト, ソースコード)。
ここで、先ほど成功したはずのテストケースを再度実行すると、失敗してしまう。
Found more than one component using matcher org.fest.swing.core.TypeMatcher[type=javax.swing.JCheckBox, requireShowing=true].
チェックボックスを探したところ、複数のコンポーネントがヒットしたのでどちらか特定できなくなっている。
これに対するfest側が想定している通常の対応は、コンポーネントに名前を付けておき、その名前で識別しよう、というものだ。
メインのコードで
public NewJFrame() {
initComponents();
jCheckBox1.setSelected(true); // 追加
jCheckBox1.setName("1個目"); // コンポーネントに名前を設定
jCheckBox2.setName("2nd");
}setNameメソッドで名前をセットしておけば、テストコード上ではその名前で識別できるようになる。
@Test
public void testCheckBox() {
window.checkBox("1個目").requireSelected(); // 引数に名前を指定
window.checkBox("2nd").requireNotSelected();
}ただ、あらかじめこのことを知っていれば良いのだが、通常、名前をつけるようなことはあるのだろうか。私は今回初めてnameという属性があるのを知ったのだが...
nameの設定を行っていない場合、表示されている文字列(setTextで設定した文字列)で2つのチェックボックスを識別できれば良いのでは、と考えた。
今まで使用してきたcheckboxメソッドは、Javadocを見るとContainerFixtureで実装されていることが分かる。また、このメソッドはnameを引数にとるものの他、GenericTypeMatcherを引数にとるものがある。今回はこちらを用いる(ソースコード)。
@Test
public void testCheckBox() {
GenericTypeMatcher<JCheckBox> matcher1 =
new GenericTypeMatcher<JCheckBox>(JCheckBox.class) {
@Override
protected boolean isMatching(JCheckBox component) {
return "チェックボックス".equals(component.getText()) ? true : false;
}
};
GenericTypeMatcher<JCheckBox> matcher2 =
new GenericTypeMatcher<JCheckBox>(JCheckBox.class) {
@Override
protected boolean isMatching(JCheckBox component) {
return "2nd check".equals(component.getText()) ? true : false;
}
};
window.checkBox(matcher1).requireSelected();
window.checkBox(matcher2).requireNotSelected();
}上記のように、isMatchingの中でコンポーネントを識別できるような実装を行うことになる。
コンポーネントごとにmatcherを作る必要があるようなので、かなり面倒な作業になる。festを使用するのであればnameは設定しておくべき、ということなのだろう。
なお、表示文字列で識別する場合、多言語対応しているアプリケーションでは問題が出るであろうことが予想される。(自分で実装しない部分、たとえばOK/キャンセルダイアログのボタン等も実行環境によって文字列が自動で切り替わる。このようなものについても検討が必要かもしれないが、未検証。)
参考:
- FEST Documentation - 公式サイト。導入初期段階で躓きそうなところは、ページ右の一覧を辿れば解決できそうな気がする。
- Easy GUI Testing with FEST(pdf)
| 固定リンク | コメント (0) | トラックバック (1)

最近のコメント