PHP基礎編

第7回 DocTestを使ってUnitTestをやってみよう (その2)

DocTestを使ってみよう

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

TOM先生

  • 数字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 といったチェック用のメソッドも省略形が準備されている。(省略しないパターンは次回説明します)

TOM先生


上記のコード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を実行してみましょう。さてどうなるでしょうか?

「TOM先生のテスト講座」のトップへ