最近、新人のテストコードを見る機会があり、ユニットテストの書き方について考える機会があった。ユニットテストはテンプレートみたいなものがあるので、それさえ押さえれば、誰でも簡単に書くことができる。ここでは、その方法について紹介したい。サンプルはRSpecで書くが、その他のユニットテストフレームワークでも、応用ができるとおもう。はじめにごく単純化すると、テスト対象は状態を持ち、入力を与えると何らかの出力を行なうものである。入力が変われば出力は変化するし、状態が変化すると入力が同じでも出力が変わる(かもしれない)。ユニットテストは、テスト対象の状態を操作し、与えた入力によって意図通りの出力を得られるかを確認する作業のことをいう。ユニットテストを書くときには、オブジェクトの状態ごとにメソッド単位で入力と出力を確認するようにする。RSpecの疑似コードで書くと、次のようなテンプレートになる。endend例として、シンボルだけを受け付けるスタックを考えてみよう。このスタックは次のような仕様とする。スタックの最大容量は10である。pushメソッドは、スタックの先頭にシンボルを追加する。pushメソッドは、シンボル以外が渡されたときに例外を発生させる。スタックが満杯のときに、pushメソッドは例外を発生させる。popメソッドはスタックの先頭のシンボルを返す。スタックが空のときに、popメソッドは例外を発生させる。sizeメソッドはスタックサイズを返す。ユニットテストの書き方ユニットテストを書くときには、まず状態に注目する。すると、このスタックは空、満杯、それ以外という3つの状態を持ち、それぞれで振る舞いが異なることに気付く。そこで、まずはその状態をテストにcontextとして記述する。状態によって振る舞いが変わらないオブジェクトであれば、状態ごとのcontextは省略できる。endend次に、メソッド単位でテストを行なうため、状態ごとにメソッドをdescribeとして一覧する。end...もし、入力によって出力が変化する場合には、その入力ごとにcontextを分ける。contextは、正常系ばかりではなく異常系も含めるようにしよう。同値分割や境界値分析についても意識するとテストの質が上がる。end...それから、期待する出力を表明する。end...rspecコマンドのフォーマットオプションでドキュメンテーションフォーマットを指定して起動したときに、適切に構造化されていることが重要である。implemented)さて、ここから実際のテストの中身を書いていく。テスト対象の状態を作り出すための事前条件を書く。これは、コンテキストのテストを書くタイミングで書いてもいいし、最初にまとめて書いてもいい。end...あとはひたすらテストの内容を書いていく。end...テストが通ることが確認できたら、テスト自体の可読性を高める工夫をしていこう。end上記のようにitの説明部分が、テスト部分とほぼ同等ということであれば、それを省略するのがよい。}subjectがコンテキストによって変わったりする場合であれば、適切な名前をつけることもできる。読んで、どのようなことができるのかを把握しておいたほうがよい。まとめユニットテストは、最初に挙げた疑似コードのテンプレートを次の手順で書いていくことで機械的に書けるようになる。状態をコンテキストとして分ける状態ごとにメソッドを一覧するメソッドごとに入力のコンテキストを分ける期待する出力を表明する事前条件を書くテスト本体を書くテストをグリーンにするテストの可読性を高めるこの手順で書いたテストは適切に構造化されるため、テストの意図が明確に伝わるテストになる。テストすべき条件に抜けや漏れがないかチェックもしやすい。この手順を活用して、適切で分かりやすいテストを書くように心がけよう。ソフトウェアエンジニア。大学在学中からネットワークやWeb技術にたずさわる。Web制作会社、システムインテグレータを経て、現在はインターネットサービスの開発に従事。