Pluginのテストを自動化するには(その3:テストクラスをHeadlessで動かす:前編)

テーマ『Pluginのテストを自動化する』の第3回です。正月中に記事をまとめきろうとするのは精神上どうなのかと若干後悔。休めるときに休んどけという声もあるでしょう。でもやれるところまでやるよー!
世に出ている記事はeclipse-test-frameworkを使うところ以降を扱ったものが多いですよね。でもそこに到達するまでが遠い。今回の記事もそこ以前のお話です。
そもそもテストクラスをHeadlessモード、つまりCUI(もしくはコンソール)から起動したことありますか?前回簡単に触れましたが、『JUnit Plug-in Test』のランチャーはEclipseインスタンスを別途起動し、そこでテストを実行します。この操作をCUI(コンソール)から実行する事が今回のテーマです。ここまでうまくできていなければ自動化なんて本当に夢のまた夢です。
さて、Eclipse上から実行しているプラグインのテストはどういうように実行されているのでしょうか。実行されているコマンドを確認することは簡単にできます。作成した『JUnit Plug-in Test』のラウンチコンフィグをデバッグモードで実行し、図1の箇所を右クリック->Propertiesを選択するとどのようなコマンドが実行されたか見ることができます。
実際にLinux環境で1テストケースを実行した例の場合は下記のコマンドが実行され手います。

/usr/lib/jvm/java-6-sun-1.6.0.03/bin/java -Declipse.pde.launch=true -classpath /home/kompiro/target-eclipse/plugins/org.eclipse.equinox.launcher_1.0.1.R33x_v20070828.jar -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:52142 org.eclipse.equinox.launcher.Main -os linux -ws gtk -arch x86 -nl ja_JP -version 3 -port 42874 -testLoaderClass org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader -loaderpluginname org.eclipse.jdt.junit4.runtime -classNames org.kompiro.readviewer.rss.TestRssService -application org.eclipse.pde.junit.runtime.coretestapplication -data /home/kompiro/code/workspaces/rss-reader/../junit-workspace -configuration file:/home/kompiro/code/workspaces/rss-reader/.metadata/.plugins/org.eclipse.pde.core/pde-junit/ -dev file:/home/kompiro/code/workspaces/rss-reader/.metadata/.plugins/org.eclipse.pde.core/pde-junit/dev.properties -os linux -ws gtk -arch x86 -nl ja_JP -testpluginname org.kompiro.percs.rss.test

このコマンドを簡単に見ていきます。

-application org.eclipse.pde.junit.runtime.coretestapplication

というアプリケーションが指定されています。『JUnit Plug-in Test』で実行した時のためのアプリケーションです。実行すると実行結果や実行中のテストがJUnitビューに表示されますが、

-port 42874

と指定しています。このポートに接続することでJUnitの実行しているテストを制御したり、実行結果を収集しているのです。

さて、このコマンドを使ってJUnitの実行結果を収集出来るでしょうか。答えはNoです。このコマンドではJUnitビューが必要なように、実行結果の収集をするものが別途必要になってしまいます。そこで登場するのがEclipse-JUnit-Frameworkです。(ここまで長かった。そしてくどい。)
明日はeclipse-test-frameworkを使って今渡こそコンソールで実行してみます。(今日の記事はなんだったんだ?っていうつっこみは自分もそう思ってます)

Pluginのテストを自動化するには(その2:テスト用のプラグインを作るには)

テスト用のプラグインを作るのは簡単なように見えますが、実は難解な作業です。本体のプラグインを必須プラグイン(Required-Bundle)に設定すれば一見クラスの参照関係が整うので、動作するように見えます。しかし、実際はプラグイン同士の依存関係が解決されていない事がよくあります。よく起しやすいのは循環参照です。

循環参照とは

循環参照はプラグイン同士の依存関係が循環している状態を指します。もっとも単純な例で記述すると、プラグインAをビルドするためにはプラグインBが必要で、プラグインBをビルドするためにはプラグインAがビルドされていなければならないという関係です。プラグインが二つの例ではなかなかおきない循環参照ですが、プラグインの数が増えてきて、かつテスト用のプラグインを作成する関係になると話が変わってきます。気付くとテスト用のプラグインがアサーションのときに元のプラグインの依存するクラスを参照したい場合が出てくるでしょう。それを補助するテスト用のプラグインなどを作り始めると、気付かないところで循環参照が起きていることがよくあります。そもそもプラグイン同士の依存関係が解決していないと、プラグインを開発環境でビルドがうまくいきません。起動時にうまくビルドが行かなかった場合は、プラグインの依存関係を見直すことが解決への近道です。

循環参照を回避する方法としてRequired-Bundleとして宣言している依存関係をやめて、Import-Packagesを使って必要なパッケージを宣言することが上げられます。Plug-inごとに必要なパッケージを宣言することになるので、循環参照のリスクはかなり低減されますが、あるパッケージを参照したくなるたびに宣言しなければならないのでかなり作業が煩雑になるでしょう。また別の問題も発生します。

実はプラグインごとにクラスローダーが稼動しているため、プラグインをまたいだリソースの取得は基本的にできない構造になっています。(僕はこれは構造的にプラグインごとの依存性を下げるための処置だと理解しています。プラグインが稼動しているOSGiはネットワークを意識したつくりになっているため、基本的に一つのプラグインで一つの環境を構成しています。しかしクラスファイルが例外になっているので、リソースもそうなっててもおかしくない気もします。)リソースの参照が基本的にできないと何が困るか、というとテスト用の設定ファイルを用意して、テスト時はそちらのファイルを読み込ませようとしても対応できないのです。それはなぜかというと、既存のほとんどのライブラリはクラスローダーからリソースを取得するものがほとんどです。そのためプラグインをまたいでしまうとリソースの取得が出来ません。

これを回避するにはテスト用のプラグインをplug-inとして作成するのではなく、本体のプラグインのfragmentとして作成すると良いというアイディアが公開されています。fragmentは本体のプラグインとの差分として読み込まれるため、同一のクラスローダーにロードされます。リソースの取得が出来なかったり、プラグインの依存関係が解決できていないということはテスト用のプラグインを作成したときと話が変わってきます。

次回はこの点をふまえて、Eclipseの外から実装したテストプラグインのテストを実行してみるというのをやってみます。あと、図とかは都度時間が出来たら追加してもっと推敲したものを公開する予定です。(絶対読みにくいですよね。ごめんなさい。)

参考URL
Testing Plug-ins with Fragments | RCP Quickstart: Learn the Eclipse Rich Client Platform from the experts

Pluginのテストを自動化するには(その1:心構え編)

そもそもPluginのテストを自動化するためにはJUnit Plug-in Testで動作するテスト環境を構築する必要があります。プラグインのロジックのテストにはJUnit Testで充分やっていけるので、そちらでテスト環境を構築している方も多いと思いますが、Plug-inのテスト自動化をするにはそれでは不十分なのです。まずその理由について触れます。

JUnit Plug-in Testについて

JUnit Plug-in Testは、JUnitを1BundleとしてインポートしたOSGi環境上で動作させるテストです。GUIを使ったPlug-inのみを対象にしたテストというわけではありません。
RunダイアログからJUnit Plug-in Testを作成し、Mainタブを開くと、テスト起動時のEclipseの起動アプリケーションを選択できるようになっています。ここで何も設定していない場合、『Program to Run』には『Run a Product』と『org.eclipse.sdk.ide』が選ばれているはずです。これはどういうことかというと、Junit Plug-in Testを実行する時にEclipseインスタンスを一つ別に起動して、そのインスタンス環境でテストクラスを実行プラグインとして動作させているのです。(Eclipseプラグイン開発入門でも図解されています)
なので、『Program to Run』を『Run a application』に選択し直し、右の選択コンボを表示してみると『[No Application] - Headless mode』という選択肢があります。これを選んで実行するとEclipseのアプリケーションとしては何も実行せず、Equinoxが起動し、OSGiのアプリケーションとして起動します。(このあたりの話は別途Eclipse Platform編として語ってみたい。)そしてその後、選択したテストクラスが実行されるという動作をします。
何も設定していない場合のテストと比較してみると、『Headless mode』はワークベンチを起動しない分少し速いです。(Equinoxを起動するので充分に遅いですけれども)。このテスト環境では拡張ポイントの読み込みは終わっているので、拡張ポイントを跨いだテストをする場合にも実施を検討してみてください。
もちろん自作RCPアプリケーションのエントリIDも『Run a application』に表示されます。自作RCPアプリケーションの起動部分のテスト(起動するかどうかくらいですが)もこれによって一応確認できるでしょう。
Plug-inのテストを自動化するためにはまず上記のようにEclipse上からキックできるテスト環境構築が必要です。早くもここでうまく動作しないことも多いので、次回はどうやってテスト用のプラグインを作るのかをやっちゃいます。

Pluginのテストを自動的に行うには(その0)

この冬休み中にせっかくなんで何か連載物をやりたいと思ってみたんで、Pluginのテストの自動化をまとめてみるよ。テストの自動化もビルドの自動化もほとんど変わらないはずなので、そのあたりにもつっこんでいきます。