S2JUnit4をJUnit4.8でも使いたい
このブログでJavaについて書くのは初めてな気がしますが、仕事では基本的にJava使いです。
Seasar2を使い始めたのは、今の会社に入ってからなのですが、S2JUnit4が中々使いやすいので、今のプロジェクトでも導入してみてました。
しかし、S2JUnit4は、JUnit4.4でしか(完全には)動作せず、4.5や自分のプロジェクトで使っている4.8とかでは、一部メソッドだけの実行が上手くいかなかったり、Enclosedの内部クラスで上手く動作しなかったりと、なにかと不便です。
特に、メソッド単位で実行できないのは、Quick JUnitの恩恵があまり受けられないため、わりとストレスに感じていました。ですが、今のプロジェクトでは、テストに限定して導入しているため、全体はDIをするような作りになっていませんし、テストだけだからまぁいっか・・・という感じでした。
それでも、ひたすらコーディングしていると、それらのわずらわしさがやたらと気になりはじめたので、ちょっと調査してやってみました。
S2JUnit4でメソッド単位実行できるように
まず、上手くいかない原因は、Sorterに渡しているS2TestClassRunnerのインターフェースがRunnerで作成しているのですが、Sorterに渡すのはSortableインターフェースでなければならないため、ここに齟齬が発生していたようでした。S2TestClassRunner自体はSortableインターフェースをimplementsしていたので、これをそのまま渡せばいいんじゃまいか、ということで、以下のように派生クラスを作成してやってみました。
まずはSeasar2クラスの派生クラス。
package hoge; import org.junit.runner.Description; import org.junit.runner.manipulation.Filter; import org.junit.runner.manipulation.NoTestsRemainException; import org.junit.runner.manipulation.Sorter; import org.junit.runner.notification.RunNotifier; import org.seasar.framework.unit.S2TestClassRunner; import org.seasar.framework.unit.Seasar2; public class Seasar2Extension extends Seasar2 { private final S2TestClassRunner extendedDelegate; /** * @param clazz * @throws Exception */ public Seasar2Extension(final Class<?> clazz) throws Exception { super(clazz); setProvider(new S2DefaultProviderExtension()); this.extendedDelegate = (S2TestClassRunner) createTestClassRunner(clazz); } @Override public Description getDescription() { return extendedDelegate.getDescription(); } @Override public void run(final RunNotifier notifier) { extendedDelegate.run(notifier); } @Override public void filter(final Filter filter) throws NoTestsRemainException { filter.apply(extendedDelegate); } @Override public void sort(final Sorter sorter) { sorter.apply(extendedDelegate); } }
S2TestClassRunnerを生成するためのProviderについても、派生クラスを定義しておきます。
package hoge; import org.junit.runner.Runner; import org.seasar.framework.unit.S2Parameterized; import org.seasar.framework.unit.S2TestClassMethodsRunner; import org.seasar.framework.unit.Seasar2.DefaultProvider; public class S2DefaultProviderExtension extends DefaultProvider { @Override public Runner createTestClassRunner(final Class<?> clazz) throws Exception { if (hasParameterAnnotation(clazz)) { return new S2Parameterized(clazz); } return new S2TestClassRunnerExtension(clazz, new S2TestClassMethodsRunner(clazz)); } }
S2TestClassRunnerExtensionは、Seaser2Extensionと同様に、filterとsortでsorterなどに渡しているdelegateを、Runnerインターフェースではなく、S2TestClassMethodRunnerにして渡しているだけです。
実際に調べながらやったので、2時間くらいはかかりましたが、これでQuick JUnitも使えるようになり、同時にEnclosedしたクラスの内部クラスで@RunWithを使っても、問題なく動作するようになりました。
後はjmockitと同時に動かせればいいのですが・・・、まぁその辺はできなくてもなんとかなるので大丈夫です。
もし同じように悩んでいる方の参考になれば。