テストを“いちばん重要な財産”と考えると見えるもの

第2回 本当にコードを失っても大丈夫なのか,確かめてみよう

この記事を読むのに必要な時間:およそ 7.5 分

前回⁠これまでの記事で取り上げたコードを,テスト駆動ベースに移行していく」と書きました。さっそく,取り組んでいきましょう。その中で「コードをすべて失ってしまったとしても,テストが無事なら元と同じ品質のコードをもう一度書くことができる」かどうかを確かめていきましょう。

今回取り上げるプログラム

今回取り上げるのはPHPでNゲージ模型を自由自在に動かそうです。第1回のリスト1は,以下のようになっていました。

リスト1 ⁠Nゲージ」第1回リスト1より

#! /usr/local/bin/php
<?php
$url = "http://192.168.0.100/";

file_get_contents($url."?00=C");
file_get_contents($url."?01=D");
file_get_contents($url."?02=D");
file_get_contents($url."?03=C");

?>

どうでしょう。ちょっとテスト駆動に向かないのではないか,と筆者は感じました。みなさんも同様に思われましたでしょうか。なぜこのソースをテスト駆動にしようと思わないかの分析は後半で行うことにして,次のソースを見ることにしましょう。

こちらは,同じ連載の第2回のソースですリスト2)⁠先頭にクラス定義がありますので,この部分をテスト駆動開発に移行してみることにしましょう。

リスト2 ⁠Nゲージ」第2回リスト2より

#! /usr/local/bin/php
<?php
$url = "http://192.168.0.100/";

class	rail {
    var    $number;
    function    rail($number = "00") {
        $this->number = $number;
    }
    function    drive($speed = 0) {
        global    $url;
        
        if ($speed >= 0)
            $command = substr("ABCDEF", min($speed, 5), 1);
        else
            $command = substr("abcdef", min(-$speed, 5), 1);
        file_get_contents($url."?".$this->number."=".$command);
    }
    function    sense() {
        global    $url;
        
        return file_get_contents($url."?".$this->number."=S") + 0;
    }
}

#
# |---r4---|---r3---|---r2---|---r1---|---r0---|
#

$r0 =& new rail("00");
$r1 =& new rail("01");
$r2 =& new rail("02");
$r3 =& new rail("03");
$r4 =& new rail("04");

for (;;) {
    $r0->drive(2);
    $r1->drive(3);
    $r2->drive(3);
    $r3->drive(2);
    while ($r4->sense() == 0)
        ;
    $r0->drive(0);
    $r1->drive(0);
    $r2->drive(0);
    $r3->drive(0);
    
    $r4->drive(-2);
    $r3->drive(-3);
    $r2->drive(-3);
    $r1->drive(-2);
    while ($r0->sense() == 0)
        ;
    $r4->drive(0);
    $r3->drive(0);
    $r2->drive(0);
    $r1->drive(0);
}

?>

今回使用するテストエンジンは,リスト3です。前回のものと1行だけ違い,読み込むファイル名をコマンドライン引数で指定できるようにしました。

リスト3 run.php

#! /usr/local/bin/php
<?php

function    asserteq($expected, $found) {
    if ($expected === $found) {
        printf(".");
        return;
    }
    printf("\nexpected: \"%s\"\nfound: \"%s\"\n----\ntest failed.\n", $expected, $found);
    die();
}

require(@$argv[1]);

foreach (get_declared_classes() as $classname) {
    foreach (get_class_methods($classname) as $methodname) {
        if (!ereg("^test", $methodname))
            continue;
        $obj =& new $classname();
        $obj->$methodname();
    }
}
print"\ntest successed.\n";

?>

また,PHPのincludeやrequireでは,returnで以降の取り込みを中止することができます。そこで以降のテスト対象のコードでは,asserteq関数が定義されていたら,クラス定義の直後でreturnしてテストエンジンに戻るようにしました。

著者プロフィール

木元峰之(きもとみねゆき)

独立系ソフトハウスに8年間勤務,パッケージソフトの開発や記事執筆などを行う。現在はフリーのコンサルタント。SWESTなどのワークショップで分科会のコーディネータを務める。デジタル回路設計歴30年,プログラミング歴27年。

きもと特急電子設計
URL:http://business.pa-i.org/

コメント

コメントの記入