LogoRRR は TestFX を使って JavaFX UI の統合テストを実行しています。これらのテストにより、新機能の追加、内部整理、依存関係の更新後も主要な操作が正常に動作することを確認でき、ユニットテストでは検出できない回帰を捕捉できます。
なぜ今なのか
20回以上のリリースを経て、LogoRRR は手動テストだけでは十分でないほど複雑になっていました。コードベースには、自動で問題を見つける仕組みが必要でした。TestFX を使えば、実際のアプリウィンドウを操作できます。ボタンのクリック、ファイルの開閉、UI 状態の検査などを、すべて JUnit テストメソッドから実行できます。
画面操作テストをいつ増やすかは、いつも判断が必要です。プロジェクト初期は UI の変化が速すぎてテストが追いつけません。しかし主要な流れが安定してきたとき、テストは負担ではなく開発を進める力になります。そのタイミングが 24.3.0 で訪れました。
実装
Scala の簡潔な構文は、小さなテスト DSL を構築するのに自然と向いています。ファイルを開く、閉じるボタンをクリックする、タブペインが空であることを確認する、といった小さな操作が読みやすい構成要素になります。
@Test def openAndCloseTab(): Unit = {
checkForEmptyTabPane()
openFile(path)
checkForNonEmptyTabPane()
clickOn(lookup(UiNodes.LogFileHeaderTabs).query[StackPane](), MouseButton.SECONDARY)
waitAndClickVisibleItem(CloseTabMenuItem.uiNode(fileId))
checkForEmptyTabPane()
}
UI テストを書くことで、本番コードにも改善が生まれました。ファイル I/O と外部プロセス呼び出しを抽象化する新しいサービス層が追加され、テストのためだけでなく設計そのものも整理されました。
テストで発見されたこと
- アプリのシャットダウン動作 — 適切にクリーンアップされていなかったリソースがテストで明らかになりました
- テストの独立性 — 各テストは独自に準備と後片付けを行う必要があり、共有 UI 状態に関するいくつかの微妙な前提が明らかになりました
- パフォーマンスのベースライン — テスト実行時間に注目することで、テストの緩やかな遅延の蓄積を防げます
ヘッダー写真:Sora Shimazaki(Pexels)
