JUnitソースコードリーディングに行ってきました。感想を書くと "Groovyすげぇ" になりかねないので、さらっと書きます。
雑感
色々ありますけど、読んだら使い方がわかります。読まなくても使えるんですけど、読んでからだと使えてなかった気がするから不思議です。
コードを勉強として読むならば JUnit3.8 を読んだほうがいいかも知れません。Swingの実装の勉強にもなるみたいですし。
JUnit4.8は読み物としては難しい方だと思います。やりたい事ははっきりしているので読めなくはないのですけど、互換の為に色々やってたりでいい感じに混乱しました。JUnitとしての機能の実現よりは、そこに至る過程に膨大な労力があったりするので。
とりあえずRuleを使うと出来る事が一気に広がって、テストコードを一気に見辛く出来ます。そこは書く人の責任なので何とかしましょう。
TestSuite
public class TestSuite implements Test { /** * Constructs a TestSuite from the given class. Adds all the methods * starting with "test" as test cases to the suite. * Parts of this method were written at 2337 meters in the Hueffihuette, * Kanton Uri */ public TestSuite(final Class<?> theClass) { addTestsFromTestCase(theClass); }
Computer
/** * Represents a strategy for computing runners and suites. * WARNING: this class is very likely to undergo serious changes in version 4.8 and * beyond. */ public class Computer {
へー変わるのね、とか。
BlockJUnit4ClassRunner#methodBlock
Statement statement= methodInvoker(method, test);
statement= possiblyExpectingExceptions(method, test, statement);
statement= withPotentialTimeout(method, test, statement);
statement= withBefores(method, test, statement);
statement= withAfters(method, test, statement);
statement= withRules(method, test, statement);
return statement;
マジメなのも。実行するMethodからstatementを作って、それを包んで包んで、最終的に実行するstatementの出来上がり。なおmethodInvokerとwithRules以外はdeplicatedになってます。今後は全部Ruleに統一される感じなんでしょうかね。互換のために@BeforeとかをRuleに処理させなきゃいけなくなるんだろうけどどうすんだろ。面倒そう。
BlockJUnit4ClassRunner#withRules
private Statement withRules(FrameworkMethod method, Object target, Statement statement) { Statement result= statement; for (MethodRule each : getTestClass().getAnnotatedFieldValues(target, Rule.class, MethodRule.class)) result= each.apply(result, method, target); return result; }
Ruleの適用の仕方は実にシンプルです。@Ruleつけられたフィールド拾ってきてapplyするだけ。applyで返されるStatementはこーして使われる。
あらゆるテストが通るようになるおまじない
@Rule public MethodRule rule = new MethodRule() { public Statement apply(Statement base, FrameworkMethod method, Object target) { return new Statement() { @Override public void evaluate() throws Throwable { } }; } };
どうしても通らないテストにこのフィールドを書けばばっちりです。Redに悩まされる日々におさらばして、いつもGreenでハッピーになれま…やらないでね。
まじめにRuleを使うと
とりあえずテストコーディングの効率化は出来そう。コピペやらなにやらでやってるBefore/Afterとかがあったら、MethodRuleのクラス作っておけば多少は楽できそう。わからない人には全然わからないコードになる気もしますけど、それを気にしてたらプログラマは勉強してはいけないことになりますし。