JDTのPreferenceStoreをPlug-inを使ってデフォルト値のカスタマイズをするには

Quick JUnitとmockitoをより連携させるために考えていることに、static importをコンテントアシストしてくれるFavoriteへの登録がある。こんな感じ。

既に似たような事をしているプラグインがある。SWTBotだ。なので、
http://github.com/ketan/swtbot/raw/master/org.eclipse.swtbot.eclipse.ui/src/org/eclipse/swtbot/eclipse/ui/preferences/PreferenceInitializer.javaを参考にしよう。

このPreferenceInitializerはAbstractPreferenceInitializerを継承しているので、設定の初期値を設置するためのクラスだ。その他にもIStartupやIPropertyChangeListenerを実装しているけど、IStartupは、Workbenchの起動後に実行するためのインタフェース、IPropertyChangeListenerは、設定画面から値が変更になったときに何かをするためのインタフェース。どちらもそんなに気にする必要はない。ということで、実際にどうやって値を設定しているか、見ていく。

org.eclipse.jdt.ui.PreferenceConstants を取得する

JDTにおける設定値はorg.eclipse.jdt.ui.PreferenceConstants#getPreferenceStore()で取得できる。PreferenceInitializer#initializeFavorites()で、Favoritesの値を変更しているけど、もし、SWTBotの設定画面でFavoritesに追加するようチェックが入っていれば、JDTのFavoritesに追加する、そうじゃなかったらSWTBotが追加している設定を削除する、ってやってるだけ。簡単簡単。

ということは、Quick JUnitでも同じような設定画面を作れば対応できそう。

Quick JUnit アイコン募集の途中経過

数日前に募集を始めたアイコンですが、いくつか案を頂きました!ありがとうございます。今月中に少し改善を加えたバージョンをリリースするので、その時にアイコンを使わせて頂きたいと考えています。

今日は、どんなアイコンを頂いているのか、ほんとうに簡単ですが紹介しますね。






@さん、@さん、@さん、@さんどうもありがとうございます。
今月いっぱいは受け付けようと思いますので、よろしくお願いします。

追記

http://f.hatena.ne.jp/skimura/20100803234324
僕は気づけなかったんですが、リンク先に書いてあるURLもネタでした><
って、これどうやってるんだろう。おもしろい。

Quick JUnitが@ITで取り上げられました!

@ITにQuick JUnitがとりあげられました!岡本さんありがとうございます!
http://www.atmarkit.co.jp/fjava/rensai4/devtool16/devtool16_1.html
最初、タイトルを見ただけうれしくなり、本文をしっかり目を通していませんでした。ところが大事なお名前の部分を見落としていたようです。心より恥じます。すいません。
さて、文中ではEclipse MarketplaceからQuick JUnitをインストールされているのですが、アイコンが表示されていません。そうなんです。Quick JUnitにはまだアイコンがないのです。この機会に募集したいと思います。アイコンの大きさは32x32、フォーマットはpngかgifです。オープンソースへのコントリビュートはソースコードだけじゃありません。興味をもたれた方はブクマコメントやtwitterなどでお声をおかけください。

MacOSX上でQuick JUnitをお使いの皆様へ。日本語クラス名、メソッド名の対応方法

毎年4月25日はQuick JUnitにとって大切な日です。毎年β版をリリースし続けているのもあれなので、リリース版とするために懸案だったMacOSX上でテストメソッド名が日本語メソッド名だと起動しない問題に挑戦しました。調べてみると、その原因はQuick JUnitに原因があった訳ではありませんでした。そもそもMacOSXEclipse環境だと、日本語が通らないことって多くないですか?ということで、原因と対策についてつらつらとまとめます。自分がMacOSXを開発環境として使用し始めたのはここ数日なんで、詳しくはわかりません。ので、もし違っていることがあればコメントなりブコメをいただけるとありがたいです。

原因はMacOSX上のJavaのデフォルトエンコードにある模様

MacOSX上のJavaApple謹製のJDK,JREな訳ですが、デフォルトエンコードがJDK5の時はUTF-8だったのが、JDK6ではSJISに変更になったんですね。情報源はこちら
MacOSXに置けるターミナルのデフォルトエンコードUTF-8です。なので、JDK6のデフォルトエンコードSJISとはあわないので、起動できない、というのが問題の真相でした。なので、起動ランチャの設定タブの一番右にある「Common*1」タブには「Console Encoding」という選択欄があります。

ここの設定をUTF-8に設定すると、日本語クラス名でも、メソッド名でも起動できるはずです。これはソースコードのエンコーディングとは関係なくそう振る舞います。

Eclipseにおけるデフォルトエンコーディングの変更方法

若干Hackに見えると思いますが、大したことではないです。先述した情報源でも起動プロセスのシステムプロパティとして「file.encoding=UTF-8」を含むと書かれていますが、これをEclipseでも同様に設定してあげればいいです。ただ、MacOSXの場合、他のOSでは存在する、eclipse.iniが見当たりません。ではどこにあるかというと、まずEclipse.appを右クリックし、パッケージの内容を表示を選んでください。

次に「Contents/MacOS」を選択すると、その中にeclipse.iniが含まれています。このeclipse.iniの最後の行に「-Dfile.encoding=UTF-8」とすると日本語クラス名、メソッド名が通るようになるはずです。お試しください。

*1:Pleiadesユーザは適当に読み替えてください。多分「共通」

Quick JUnit 0.5.0について

かくたにさんから、「どうなってるのかな?」と言うお言葉をいただいたので、エントリを書く。
いちおう機能としてTestContextタグを追加したり、スイッチすることはできるようになった。Ctrl+Shift+8でクラスに対し、TestContextタグが追加され、Ctrl+8で、TestContextが宣言されているクラスのリストがポップアップし、ジャンプする事ができるようになりました。

/**
 * @TestContext org.eclipse.contribution.junit.test.TestProject
 */
public final class CreateTestProjectUtil {
  
  public static TestProject createTestProject() throws CoreException, MalformedURLException, IOException{
    final TestProject project = new TestProject();
    project.addJar("org.junit4", "junit.jar");
    return project;
  }
  
  public static IPackageFragment createPackageFragment(final TestProject project, final String packageName) throws CoreException{
    IPackageFragment created = project.createPackage(packageName);
    return created;
  }
  
  public static IType createType(
      final TestProject project,
      final String packageName,
      final String typeName,
      final String source) throws CoreException{
    return project.createType(project.getPackage(packageName), typeName + ".java",source);
  }
  
  private CreateTestProjectUtil(){
    
  }

}

ってな感じで、クラスに対してFQCNでTestContextが宣言されます。ただ、使用感がいまいち成熟しきれていません。宣言されたとき、カーソルがそこに行ってしまったり、ジャンプすると、そのクラスが開かれるだけだったりする点が練り足りないのかなぁ、と思ってます。感想を募集したい感じです。
明日、ベータバージョンとしてリリースすることってできないかな…。いや、正式リリースとしてShipして、フィードバックを得たい感じですけどね。ちょっといらないメニュー等整理したいです。

Testing Context(仮)という考え方

ちょっと前Quick JUnitの管理者でもあるかくたにさんとQuick JUnitをどう改良しようか、話してきました。その時に聞いてきたアイディアに名づけるとするならTesting Context。

以前はTesting Pairだけ考えてればよかったのに。

Quick JUnitでは実装クラスに対するテストクラスが1対となって存在するという、Testing Pairという考えを元に作られています。Ctrl+9でテストクラスと実装クラスを切り替えられる、というあれです。JUnit3の時代までは必ずTestCaseクラスを継承しなければならない、テストメソッド名はtest_で始まらなければならないなど、いくつか制限がありました。なので名前で実装クラスとテストクラスを対応づけられるよう、実装クラス名+Testをテストクラス名として検索できるようになっています。実は隠してるんですが、その対応を増やせるようにするための設定画面がありますね。

JUnit4の登場でテストに対する考えがちょっと変わった!?

既にJUnit4が広く使われる時代。@Testアノテーションがメソッドについていればテストクラス、と言う時代です。JUnit3のころでもいくつかのクラスを組み合わせて動くような、機能テストもしますよね。実はテストクラスと実装クラスってそもそも1対1の対応ではないのです。真面目にテストを書いていくといくつかのテストクラスから実装クラスがテストされる関係になるはずです。ちょっと眠くなって来たので論理飛躍しますけど、テストにはテストをしたいコンテキストが存在します。それは一つのクラスだけを扱う場合もあれば、いくつかのクラスを扱って振る舞いを検証することもあります。パフォーマンス要件に達しているのか検証するためのテストクラスもありますよね。テストメソッドが、どのクラスを検証したいのか、コンテキストを示すことができるはずなんです。
そこでそれを僕はTesting Contextと呼んでみました。

Testing Contextとは?

Testing Contextはテストメソッドに対して、どのクラスをテストするのか、アノテーションで記述したもの、と定義します。
テストメソッドが実装をどうテストするのか、ドキュメントとして残っているとうれしいと思うんですが、それを切り替えにも使えるように出来たら結構便利かも!?と思ったわけです。
それが実装クラス上ではマーカーとして表示されれば、テストされているクラスか、そうではないのかすぐに見分けることができます。マーカーからテストへリンクするのです。(正直マーカーをつけるとなるとパフォーマンスに悩まされそうなのでやりたくない><)
テストメソッドに記述できるコンテキストは何も実装クラスだけに留まらず、URLとかMylynと組み合わせてチケット番号を結びつけられれば、障害とテストも結びつけられます。ここまでくればたいしたもんでしょ。すごいでしょ。(作ってもないのに自画自賛)

実際にどんな仕様なの?

上記を仕様としてまとめます。大事なことなので2回書きます。
今考えている仕様はテストメソッドに対してテスト対象のクラスをアノテーションで記述し、Quick JUnitではそのアノテーションを元に切り替えを行います。記述するアノテーションは厳密にはアノテーションではないですが、既存の枠組みで考えるとJavaDocの@seeタグか、@linkタグが一番適当だと考えています。
逆にプロダクトコードの方ではテストコードのタグでリンクが貼られているクラス、メソッドではマーカーが表示され、テストコードとリンクされていることが分かるようにします。
こうすることでテストコードがどのクラスをテストしているのか、またプロダクトコードではどういった観点でテストされているのかを明示できるのではないかと考えています。

アイディアを書き出した、というだけですがどーすかね。しかもTesting Contextなんて名前どう考えても誰か言ってるよなぁ。

追記

  • ブクマ米で「(仮)」がついていたのでタイトルを変更しました。
  • RSpecだとspecをまとめるのがContextらしいので、素直に直せばTesting Setか?

違うPluginのクラスメソッドを呼ぶための簡単な方法

なるほどね。継承しちゃえばいいのか。
Quick JUnit - Quick PDE JUnit - junit.extensions.eclipse.quick.pde.ExtensionSupport

package junit.extensions.eclipse.quick.pde;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.ui.ILaunchShortcut;

public class ExtensionSupport extends junit.extensions.eclipse.quick.ExtensionSupport {

    public static ILaunchShortcut createJUnitWorkbenchShortcut() throws CoreException {
        return createLaunchShortcut("org.eclipse.pde.ui"); //$NON-NLS-1$
    }
}

Quick JUnit - Quick JUnit - junit.extensions.eclipse.quick.ExtensionSupport

package junit.extensions.eclipse.quick;
...

public class ExtensionSupport {
...
    protected static ILaunchShortcut createLaunchShortcut(final String namespace)
            throws CoreException {
        final IExtensionRegistry reg = Platform.getExtensionRegistry();
        final IExtensionPoint point = reg.getExtensionPoint("org.eclipse.debug.ui.launchShortcuts"); //$NON-NLS-1$
        final IExtension[] extensions = point.getExtensions();
        for (int i = 0; i < extensions.length; ++i) {
            if (namespace.equals(extensions[i].getNamespaceIdentifier())) {
                final IConfigurationElement[] elements = extensions[i].getConfigurationElements();
                ILaunchShortcut shortcut = (ILaunchShortcut) elements[0]
                        .createExecutableExtension("class"); //$NON-NLS-1$
                if (shortcut != null) {
                    return shortcut;
                }
            }
        }
        throw new RuntimeException("LaunchShortcut not found. namespace:" + namespace); //$NON-NLS-1$
    }
...
}

継承しちゃえば子クラスのクラスローダーから親クラスのクラスローダーに処理を委譲するのは可能なのね。普通にクラスメソッド*1として呼び出そうとすると、呼び出し側のクラスローダーにそのクラスがある訳ではないので、ClassNotFoundExceptionが投げられる気ガス。というか、僕はそれで結構悩まされてBuddy-Policyを学んだけれども。

*1:static修飾子のついてるメソッドのこと。静的メソッドとか色々呼ばれますが、クラスメソッドが一番意を表している気がする。