unittestのすすめ

unit testは数あるテストのうち、最初に行われるテスト工程である。これをきちっと行うのはソフトウェア工学的にはとても重要なことだと思うのだが、私はどうにもこれがめんどくさくて仕方がない。大学院時代にコードを書いていたときには、単体テストモドキ(本番用のmain関数の上の方で試しにモジュールを使ってみて、ちょろちょろとassertをかけてreturnするというゴミコード)を書いたことしかなかった。そして、そのどうしようもないテストですら面倒だと感じていた。

しかし、Dはそんな私の怠惰な心もやさしく受け止めてくれる。そう、Dはunit testを行うための構文を言語レベルでサポートしているのだ!その名もunittest構文である。名前のまんまだ。以下に簡単な使い方を示す。

import std.math;

int mnhttnDist(int x1, int y1, int x2, int y2){
    return abs(x1 - x2) + abs(y1 - y2);
}

unittest{
    assert(mnhttnDist(0, 0, 1, 1) == 2);
    assert(mnhttnDist(-1, 0, 4, 1) == 6);
    assert(mnhttnDist(-1, 2, 3, -4) == 10);
}

この例ではマンハッタン距離を求める関数を定義し、それに対するunittestを行なっている。unittestというキーワードのついたスコープの中でassert文を書くと、もしassertが失敗したときにはunittestが失敗した旨がエラーメッセージとして表示される。なお、コンパイル時には-unittestオプションを付ける必要がある。

さて、問題はこのテストをどうやって実行するかだ。このunittestはすべてmain関数を実行する前に行われることになっているが、それはつまりどこかにmain関数がなければならないことを意味する。そりゃそうだ、プログラムを実行しようと思ったら、普通main関数は必要だ。しかし、一箇所のunit testのためだけに毎回プログラム全体を実行するのは面倒なこともある。例えば、起動がものすごく重いプロセスだったら、きっとこの構文ですら使うのが億劫になるだろう。

そこで、Dは-mainというコンパイルオプションを用意している。これをつけてソースをコンパイルすると、なんと自動で空のmain関数が挿入される。つまり、テストをしたいモジュールだけ-mainをつけてコンパイルすれば、テスト用のバイナリが生成されるというわけだ。

上で例に挙げたプログラムをmanhattan.dとして保存したとすると、以下のようにコンパイルすればよい。

$ dmd -unittest -main manhattan.d

そうすると、manhattanという名前のバイナリが生成され、これを実行すればテストが行える。

unit testが簡単に行えるとテスト駆動開発をしようというモチベーションも高まり、まさに良いことずくめである。私はD言語を始めてまだ日が浅いが、すでにこのunittest構文にはお世話になりっぱなしだ。いまいち普及していないD言語だが、多くの人にこういう良い特徴を知ってもらえたら嬉しい。

参考:プログラミング言語D

プログラミング言語D

プログラミング言語D