こんばんは。VOYAGE GROUPの野良クルー、@katzchangです。

ところでみなさん、バルスしてますか?

バルスとは滅びの言葉、つまりおまいらに解かりやすく言うと、異常系処理をキックするコマンドなわけです。で、やはり、異常系処理も含めてテストされるべきですよ。当然ですね。

ということで、テスト駆動開発、いわゆるTDD"風味"で、バルスのJava実装を作ってみました。とはいえ、要するに System.exit(1) すればよいので、実装は大したことがない。でも、実際にどのような動作になるか、あまり試したことがないのは僕だけじゃないはず。試す価値はありそうです。

方針としては、balseメソッドを実装したBalsableクラスを用意し、システムが無事に異常終了することを確認すればよいということにします。

さて、いきましょう。
package balse; import static org.junit.Assert.*; import org.junit.Test; public class BalsableTest { @Test public void test() { new Balsable().balse(); fail(); } }
テストコードはこんな感じ、new Balsable().balse();を実行すると、次のfail();が実行されないはずです。そうです、このときはそう信じていました………。alt + shift + x, t。

first_test_gray

よし、Gre……………y……?

なんと、JUnit test runnerがバルスしてしまいました。バルスマジバルス。

仕方がないから、外部プロセスとして実行し、結果を確認することにします。方針転換ってやつです。

こんな感じにテスト用のランナーを用意し、
package balse;

public class BalsableRunner { public static void main(String...args) { new Balsable().balse(); } }
外部プロセスとして実行させます。
@Test
public void testBalsableProcess() throws Exception { ProcessBuilder pb = new ProcessBuilder("java", "-classpath", "./target/test-classes;./target/classes", "balse.BalsableRunner"); Process p = pb.start(); assertThat(p.waitFor(), is(1)); }
green

今度はGreen。ちゃんとバルスできています。

ところが、ここで心配になりました。このバルスは、ちゃんとプロセス全体をバルスしているのでしょうか?マルチスレッドでも問題なくバルスるのでしょうか?

そう、不安があったらテストしましょう。

マルチスレッドを使ったテスト用ランナーを用意し、それをテストします。今度はリターンコードだけではなく、スレッドが実行されていることを確かめるべく、標準出力の内容も検査することにします。
@Test public void testBalsableThread() throws Exception { ProcessBuilder pb = new ProcessBuilder("java", "-classpath", "./target/test-classes;./target/classes", "balse.BalsableThreadRunner"); Process p = pb.start(); assertThat(p.waitFor(), is(1));
// TODO: helperを作るべき InputStream is = p.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line; List<String> lines = new ArrayList<String>(); while ((line = br.readLine()) != null) lines.add(line); is.close(); assertThat(lines.size(), is(2)); assertThat(lines.get(0), is("時間だ!!答えを聞こう!!")); assertThat(lines.get(1), is("バルス!")); }
バルス!

はい、Green。標準出力の内容も意図通りのようです。

他のコードも含めて https://github.com/katzchang/balse にコミットしていますので、煮るなり焼くなり好きにしてください。

これを他のプロダクトに組み込む場合、直接System.exit(1)を呼ぶより、Balsableを通して呼ぶように変えることができます。そのときのテストとしては、MockBalsableを用意し、モックのbalse()メソッドが呼ばれたことを確認すれば、プロダクトへのバルス実装は完了です(Balsableにももう少し手を加える必要はあります)。そして、end-to-endテストとして実際にBalsableを組み込んだ上でバルスしていることを確認できれば、出荷可能です。

さて、この記事はTDD Advent Calendar jp: 2011の10日目の記事でした。

9日目の記事は@yujioramaC言語でもレガシーでも、TDD をやってやれないことはない(レガシーコード改善成分90%、TDD成分10%)、明日は大学でテスト駆動開発プロセスを研究してる@pocketberserkerです。きっと読み応えのある記事を書いてくれることでしょう……!!

純粋なTDDではないけど、まぁこんな感じで進めてますということで…。