ちなみに、今作っているPHP + Zend FrameworkのWebアプリでの代表的な*1モデルのテストコード。
(コントローラはモデルの個別クラスを直接呼び出さず、一つのDataAccessServiceクラス*2だけを呼び出して、daが処理先クラスを振り分ける感じ。)

  • テストコントローラ
<?php
class DatatestController extends Zend_Controller_Action_Mybase
{
    // データ抽出テスト
    public function selectzAction()
    {
        $da = new dataAccessService;
        $sc = $da->createCriteria('zip');
        $sc->setZipCode('399-0000'); // formatとunformatは勝手にやるはず
        //$sc->setZipCode('3990000'); // formatとunformatは勝手にやるはず
        //$sc->setPrefname('長野県');
        //$sc->setCityname('松本市');
        //$sc->setAreaname('渚一丁目');
        //$sc->setActive(true);

        $dbrows = $da->selectZipRowSet($sc);

        $this->view->rows = $dbrows;
    }

    // データ追加テスト
    public function insertpAction()
    {
        $data = array(
            'newdata'               => true,
            'make_affiliations_id'  => 2,
            'order_affiliations_id' => 1,
            'item_name'             => '購入キボンヌ005',
            'large_category_id'     => '1',
            'middle_category_id'    => '1',
            'period_class'          => '1',
            'period_from'           => '2012-03-01',
            'period_to'             => '2012-03-31',
        );

        $data['goods'] = array();
        $data['goods'][] = array(
            'row_number'     => 1,
            'name'           => 'Realforce101',
            'specification'  => '101英語キーボード',
            'amount'         => '19800',
        );

        $da = new dataAccessService;
        $da->updateItemRow($data);
    }

    // データ更新テスト
    public function updatepAction()
    {
        $data = array(
            'newdata'               => false,
            'item_id'               => 15,
            'item_name'             => '購入キボンヌ005-update',
            'large_category_id'     => '2',
            'middle_category_id'    => '2',
            'period_class'          => '2',
            'period_from'           => '2012-04-01',
            'period_to'             => '2012-04-31',

            // この下の項目はこのメソッドからは更新されないはず
            'method_id'        => 999,
            'basis_id'         => 999,
            'publication_date' => '2099-01-10',
            'publication_time' => '15:15',
        );

        $data['goods'] = array();
        $data['goods'][] = array(
            'row_number'     => 1,
            'name'           => 'Realforce101-update',
            'specification'  => '101英語キーボード-update',
            'remarks'        => '備考-update',
            'amount'         => 9800,

            // この下の項目はこのメソッドからは更新されないはず
            'estimated_price' => 123456,
            'estimated_basis' => 99,
        );

        $data['goods'][] = array(
            'row_number'    => 2,
            'name'          => 'Logitech M705R',
            'specification' => 'ワイヤレスマウス',
            'remarks'       => '備考',
            'amount'        => 14000,
        );

        $da = new dataAccessService;
        $da->updateItemRow($data);
    }

    // 削除テスト
    public function deletepAction()
    {
        $data = array('item_id' => 15);

        $da = new dataAccessService;
        $da->deleteItemRow($data);
    }
}
  • daの中身
<?php
class dataAccessService extends customDataAccessService
{
    public static function createCriteria($group, $value = null)
    {
        switch (strtolower($group)) {
            // データ系
            case 'item':
                return daItem::createCriteria($value);
                break;
            // (略)
            // マスタ系
            case 'affiliations':
                return daAffiliations::createCriteria($value);
                break;
            // (略)
            case 'zip':
                return daZips::createCriteria($value);
                break;
            default:
                return null;
            break;
        }
    }

    public function selectItemRowSet(SearchCriteria_Interface $sc)
    {
        $da = new daItem; // こいつがモデルの本体
        return $da->selectRowSet($sc);
    }

    public function updateItemRow($data)
    {
        $da = new daItem; // こいつがモデルの本体
        return $da->updateRow($data);
    }

    public function selectZipRowSet(SearchCriteria_Interface $sc)
    {
        $da = new daZips; // こいつがモデルの本体
        return $da->selectRowSet($sc);
    }
}
  • ビュー
{* selectz.tpl *}
<div>
{foreach from=$rows item=row}
    {foreach key=key item=value from=$row}
        {$key|escape}: {$value|escape}<br />
    {/foreach}
<br />
<br />
{/foreach}
</div>

{* Zend_Viewは、ビューの実体がなくてもそのエラーが出た時点でActionの処理は終わってるので、実装しなくても問題なし *}

テストの実行方法は、ブラウザから http://localhost/datatest/selectz とか http://localhost/datatest/updatep を呼び出すだけ。
後は、画面表示とかデータベースの値とか、モデルに埋め込んだロガーから出力されたログデータをチェックしましょうと。


専用のテストコードがあるので、UI一切関係なしにハードコーディングされたデータで何度でも繰り返しテスト可能な訳で。
コレをUIから手入力したら死ねます。っていうか、ASPアプリの開発中はやってたのか、それ?
途中でなんかおかしいとか思わなかったのかと言う‥‥


あ、Zend Frameworkではテストクラスも使えるけど、入出力にDBが絡むテストは手動の方がまだマシかなぁ。今のところは。

*1:ちゅうか9割方の

*2:多分、このアプリで一番長いコード。2,000行とかどんだけww