FEST-Swingを利用する(6) 非EDTでのSwingアクセスを検証する
Swingのスレッドポリシーに記載されている通り、Swingコンポーネント及び関連クラスはイベントディスパッチスレッド(EDT)で実行する必要がある。
スタンドアロンなプログラムを作成している場合には、上記リンク先に記載されているとおり、あまり意識する必要がない。しかし、クライアント/サーバ間で非同期通信を行うプログラムなどでは、よく誤ったコーディングを見かける。
本エントリでは、上記問題の簡単な実例と、それに対するFEST-Swingでの検証方法について記述する。
サンプルの説明
今回のサンプルコードはこちらになる。本サンプルコードは、GUIを持つクライアント(client.Client)とサーバ(server.Server)が登場する。
クライアントは、サーバに要求を行い、サーバからその結果を受けた際に、画面に結果を表示する機能を持つ。
サーバは、クライアントからの要求を受け付けた後、非同期で処理を行い結果を通知する機能を持つ。
(余談。JUDE/Community 改め astash* community、最近のバージョンでは、印刷やコピー時に、上図のような透かしが入るようになったようだ。あくまで試用版、という色合いが濃くなったということか。JUDEは2009年末までダウンロード提供、とのこと。)
注目すべき箇所
結果を表示するラベル(resultLabel)に文字列を設定している2箇所に注目する。
1箇所目はclient/Client.javaの106行目requestButtonActionPerformed メソッド中になる。要求ボタンを押した際に実行される。
1: private void requestButtonActionPerformed(java.awt.event.ActionEvent evt) {
2: resultLabel.setText("要求中...");
3: server.request();
4: }
2箇所目は同ファイル134行目 listen メソッド中になる。サーバからの通知を受けた際に実行される。
1: public void listen(String str) {
2: resultLabel.setText(str);
3: }
どちらも同じようにイベントハンドラの中でラベルに文字列を書いており、実行してみても通常問題は発生しないため、このような実装が行われているのをよく見かける。
しかし実際は、一方は問題ないが、もう一方は冒頭記述のSwingスレッドポリシーに反している。
1点目のメソッドはJButton#addActionListenerメソッドで登録したハンドラであり、これは、ボタンが押された場合にEDTで実行されることが保証されている。
一方、2点目のメソッドはサーバ側のタイミングで実行される(今回の場合はサーバスレッドが実行する)。従って非EDTで実行されてしまっている。
FEST-Swingを用いた検出
FEST-Swingでは、上記のようなコーディング誤りを検知する方法を提供している。FailOnThreadViolationRepaintManagerというクラスがこれに当たる。
利用するには、JUnitのテストクラスの@BeforeClassで以下の1行を追加すればよい。
1: @BeforeClass
2: public static void setUpClass() throws Exception {
3: FailOnThreadViolationRepaintManager.install();
4: }
サンプルコードのテストケースを実行してみると、例外EdtViolationExceptionが発生し
Exception in thread "Server Thread" org.fest.swing.exception.EdtViolationException: EDT violation detected
から始まる例外スタックトレースによって、前述2点目のハンドラに問題があることが検知できる。
ただし、JUnit自体は正常終了している。これは、前回記載した事項と同様で、JUnitを失敗させるためには、JUnitスレッドで例外を送出する必要がある。
実際のプログラムでは、あらゆるスレッドやプロセス(通常、クライアントとサーバは別VMだろう)で発生した例外をJUnitスレッドに集約することはできないだろう。ただし、ユニットテスト時、このようなテストにはモックオブジェクトを使用するのが通例だと考える。従って、モックオブジェクトのスレッドで発生した例外を、前回のようにJUnitスレッドに教えるコードを追加すれば正しく問題を検知できるテストコードが作成できると考える。
FailOnThreadViolationRepaintManagerを用いた検証は完璧ではない(これについては次回記載予定)のだが、十分役に立つのではないだろうか。
« Enum<?>にキャストしようとするとコンパイルエラー"変換できない型"が発生する | トップページ | [読書]「科学者になる方法」 科学技術振興機構(JST)プレスルーム編 »
この記事へのコメントは終了しました。
トラックバック
この記事へのトラックバック一覧です: FEST-Swingを利用する(6) 非EDTでのSwingアクセスを検証する:
» FEST-Swingを利用する(7) EDTで発生した例外をJUnitで検知するの追補 [雪羽の発火後忘失]
EDTで発生した例外のハンドラをカスタム化するにはsun.awt.exception.handlerプロパティを使用する、と以前記載した。 先日リリースされたFEST-Swing 1.2a4では、カスタム化するためのクラスAWTExceptionHandlerInstallerが用意されたようだ。こちらを使用する方が良いかもしれない。ただし、実装上は、内部で上記プロパティを利用しているので差異は無... [続きを読む]
» FEST-Swingを利用する(8) 視覚の威力 [雪羽の発火後忘失]
期間があいた割にネタが用意できていないので、今回は総集編、回想回です… 過去FEST-Swingに関して記述したエントリを以下に示します。 FESTを使用してJava GUI (Swing)のテストを実行してみる FEST-Swingの紹介。FEST-Swingの機能概要を、簡単なサンプルをもとにして実行してみます。 NetBeansでFEST-Swingを利用する その1 インストール 実際にF... [続きを読む]
« Enum<?>にキャストしようとするとコンパイルエラー"変換できない型"が発生する | トップページ | [読書]「科学者になる方法」 科学技術振興機構(JST)プレスルーム編 »
コメント