第7回 DocTestを使ってUnitTestをやってみよう (その2)
DocTestを使ってみよう
では早速DocTestを使ってみましょう。といっても、何か作るものがなければUnitTestをする必要もないので、今回は次のようなものを作りたいと思います。

- 数字7桁かどうかを判別するValidatorクラス
symfonyやCakePHPといったフレームワークを利用されている方は"Validator"という言葉を聞かれたことがあるかもしれませんね。入力された値が何か決められたルールに合っているかをチェックすることを"Validate"、それを行うものを"Validator"と呼びます。
では、まず最初のバージョンとして次のようなものを作ってみましょう。ファイル名は"C:\Temp\phppro\classes\NumberValidator.php"としてください。(このあたりのファイルの命名規則については次回説明します)
コード2 最初のバージョン
<?php
class NumberValidator
{
/**
* 7桁の数字かどうかをチェックする
*
* @param integer $value チェックしたい文字列
* @return boolean チェック結果
* @access public
*/
public function validate($value)
{
}
}
ここでもう一度DocTestを実行してみましょう。今回もまだテストを作成していないので何も表示されません。
実行手順6 DocTestの実行
C:\Temp\phppro>php doctest.php classes
次に何をするかというと普段はここでおもむろにvalidateメソッドの中身を書き始めると思うのですが、まずは「こういう風に動いてほしいなぁ」というものを記述してみましょう。その「こういう風に動いてほしいなぁ」というのがテストということになります。
今回の場合、7桁の数字だったら成功というが最低限のものですね。ということでDocTestのルールに従ってテストをDocコメントとして書いてみると以下のようになります。
コード3 最初のテスト追加
<?php
class NumberValidator
{
/**
* 7桁の数字かどうかをチェックする
*
* #test
* <code>
* #true(#f(1234567));
* </code>
*
* @param integer $value チェックしたい文字列
* @return boolean チェック結果
* @access public
*/
public function validate($value)
{
}
}
DocTestの書式ではいくつかのルールがあります。
- Docコメント(/** で始まり */で終わるもの)の中に記述する。
- @paramや@returnといった@で始まるDocコメントの各種識別子より前に書く。
- #test テスト名
...というものとして記述する。("テスト名"は省略可能) - 上記のブロックは同じメソッドに対して何度記述しても良い。
- コメントをつけている対象メソッドの呼び出しを #f(...) と省略して記述できる。(省略しないパターンは次回説明します)
- #true や #false、#eq といったチェック用のメソッドも省略形が準備されている。(省略しないパターンは次回説明します)

上記のコード3のテストは以下のように読むことができます。
- #f(1234567) を呼び出すと #true() が成功する。
→ validateメソッドに1234567を渡して呼び出すと結果がtrueになる。
それでは、DocTestを実行してみましょう。何もメソッドの処理を書いていないので、テストは失敗します。
実行手順7 DocTestの実行
C:\Temp\phppro>php doctest.php classes PHPUnit 3.2.21 by Sebastian Bergmann. F Time: 0 seconds There was 1 failure: 1) testValidate(Maple4_DocTest_NumberValidatorTest) Failed asserting that <null> is true. C:\Temp\phppro\tests_c\Maple4_DocTest_NumberValidatorTest.php:19 C:\usr\local\php5\PEAR\Maple\DocTest\Runner.php:142 C:\usr\local\php5\PEAR\Maple\DocTest.php:128 C:\Temp\phppro\doctest.php:18 FAILURES! Tests: 1, Failures: 1.
さて、テストを成功させてみましょう。以下のように書くと成功しますよね?
コード4 とりあえずテストを成功させる
<?php
class NumberValidator
{
/**
* 7桁の数字かどうかをチェックする
*
* #test
* <code>
* #true(#f(1234567));
* </code>
*
* @param integer $value チェックしたい文字列
* @return boolean チェック結果
* @access public
*/
public function validate($value)
{
return true;
}
}
「おいおい…」と思った方が多いかもしれませんが、テストを通すだけならばこれで十分です。(もちろんここで終わったりしませんからご安心ください)
ひとまずテストを実行しましょう。無事OKがでました!!!
実行手順8 DocTestの実行
C:\Temp\phppro>php doctest.php classes PHPUnit 3.2.21 by Sebastian Bergmann. . Time: 0 seconds OK (1 test)
もちろんここで終わることはできません。チェックに引っかかるパターンもテストで書いてみましょう。
コード5 チェックに引っかかるパターンを追加する
<?php
class NumberValidator
{
/**
* 7桁の数字かどうかをチェックする
*
* #test
* <code>
* #true(#f(1234567));
* #false(#f(123456));
* #false(#f(12345678));
* </code>
*
* @param integer $value チェックしたい文字列
* @return boolean チェック結果
* @access public
*/
public function validate($value)
{
return true;
}
}
今回6桁や8桁の数字では失敗するというテストを追加してみました。さて実行してみましょう。
実行手順9 DocTestの実行
C:\Temp\phppro>php doctest.php classes PHPUnit 3.2.21 by Sebastian Bergmann. F Time: 0 seconds There was 1 failure: 1) testValidate(Maple4_DocTest_NumberValidatorTest) Failed asserting that <boolean:true> is false. C:\Temp\phppro\tests_c\Maple4_DocTest_NumberValidatorTest.php:20 C:\usr\local\php5\PEAR\Maple\DocTest\Runner.php:142 C:\usr\local\php5\PEAR\Maple\DocTest.php:128 C:\Temp\phppro\doctest.php:18 FAILURES! Tests: 1, Failures: 1.
もちろん失敗しますね。では正しく動作するようにしてみましょう。
コード6 7桁だけ成功するようにする
<?php
class NumberValidator
{
/**
* 7桁の数字かどうかをチェックする
*
* #test
* <code>
* #true(#f(1234567));
* #false(#f(123456));
* #false(#f(12345678));
* </code>
*
* @param integer $value チェックしたい文字列
* @return boolean チェック結果
* @access public
*/
public function validate($value)
{
if (is_numeric($value) && (strlen($value) === 7)){
return true;
} else {
return false;
}
}
}
「それでいいの?」というコードではありますが、これでテストは通ります。
実行手順10 DocTestの実行
C:\Temp\phppro>php doctest.php classes PHPUnit 3.2.21 by Sebastian Bergmann. . Time: 0 seconds OK (1 test)
「今日もいい仕事したなぁ」とここで手を止めてはいけません。このValidatorは次のようなテストを追加すると期待通りの動作をしません。
コード7 数字以外が入ってきても・・・
<?php
class NumberValidator
{
/**
* 7桁の数字かどうかをチェックする
*
* #test
* <code>
* #true(#f(1234567));
* #false(#f(123456));
* #false(#f(12345678));
* #false(#f(-123456));
* #false(#f(123.456));
* </code>
*
* @param integer $value チェックしたい文字列
* @return boolean チェック結果
* @access public
*/
public function validate($value)
{
if (is_numeric($value) && (strlen($value) === 7)) {
return true;
} else {
return false;
}
}
}
テストを追加したのでDocTestを実行してみましょう。さてどうなるでしょうか?







