皆さん, ユニットテスト書いてますか.

TDD (テスト駆動開発) によるプログラミングは本当に楽しいものですが, コマンドをいちいち手動で実行するのは面倒ですよね.
テストを自動化しているんだから, その実行も自動化したいですよね.

この記事では, 私が仕事や趣味で使っている PHPUnit を例に, テストの実行の自動化について紹介します.
PHPUnit の, としてはいますが, 他の言語で使えるテクニックもあります.

なお, ここでの自動化は開発しながらの自動実行のことで, CI (継続的インテグレーション) の話は出てきません.

その前に…

私の開発時のターミナルは以下のようになっています.

開発時のターミナル

開発時のターミナル

GNU screen での画面分割を利用して, 左半分をソースコードに, 右上をテストコードに, 右下をテストの実行に使っています.
これは作業の途中でいろいろと変動しますが, 右下ではほぼ常にテストが自動実行されるようになっています.
(ターミナルの透明化を利用してバックグラウンドでニコ動を観ることもできますね)

この小さい画面での実行を前提に, 紹介していきます.

シェルスクリプトを利用する

まずはとにかく, 決められたコマンドを定期的に実行しましょう.

コマンドを定期的に実行, というと watch コマンドを思い浮かべる人が多いと思いますが, これは使いません.
何故か, ターミナル上の色が無効化されてしまい, レッドやグリーンがわかりづらいからです.

色の使える watch は無いか, と探した所, superuser という Q&A サイトにちょうどいいものがありました.
bash watch command with colors preserved

ここへの書き込みを参考に, 以下のようなシェルスクリプトを用意しました.

適当な場所に保存して, chmod +x して実行権限を与えたら, 以下のように使用することができます.

$ ./watch2 phpunit --colors

これで, 出力の色づけを維持したまま, PHPUnit を 2 秒間のインターバルで起動し続けることができるようになりました.

プロジェクトの規模によっては全てのテストを実行するのに時間がかかることもあるので, そういうときは特定のファイルを指定しましょう.

$ ./watch2 phpunit --colors tests/Foo/BarTest.php

今自分が作業しているファイルだけを指定することで, フィードバックを素早く的確に得られるようになります.
コマンドの指定は手動ですが, 環境の用意はとても楽なのでよしとしましょう.

Stagehand_TestRunner を利用する

Stagehand_TestRunner は, PHPUnit だけでなく Lime や PHPSpec にも対応したテストランナーです.
(2011-08-16 14:00 追記: Lime への対応は勘違いでした. @heavenshell さんご指摘ありがとうございました.)

インストールについては本家の Wiki を参照しましょう.
テスト駆動開発のためのテストランナー

PHPUnit 本家よりも優れた表示が特徴です.

Stagehand_TestRunner による実行結果

Stagehand_TestRunner による実行結果

この出力形式は testdox と呼ばれるもので, テストメソッド名を英文っぽく表示してくれます.
testdox を表示する機能自体は PHPUnit にもあります (--testdox オプション) が, Stagehand_TestRunner を使うと色づけされるので, よりわかりやすくなります.

Stagehand_TestRunner には他にも様々な機能がありますが, ここで紹介するのはディレクトリの監視によるテストの自動実行です.

これを phpunit.xml として保存して, 同じディレクトリ上で以下のコマンドを実行します.

$ phpunitrunner --phpunit-config=phpunit.xml -cRa

c が色づけ, R が指定ディレクトリ (phpunit.xml で指定していますね) 以下を再帰的に, a が自動実行のためのオプションです.

これで, ディレクトリに変更のあったときだけテストが実行されるようになりました.

実行対象のテストを正規表現で絞り込んだりすることもできますが, それらの詳細については以下の Wiki が参考になります.
Stagehand_TestRunner ユーザーガイド

watchr を利用する

最後に紹介するのは, 最近一番よく使っている方法です.
watchr はファイルの変更を監視するツールで, 検出時にあらゆる処理をフックさせることができます.

watchr は Ruby 製のツールなので, 処理は Ruby で書く必要があります.
といっても, 簡単な正規表現が書ければ充分なので, Ruby 未経験でも問題無いでしょう.

インストールについては Rubygems をインストールして gem install watchr するだけです.

watchr の設定ファイルとして, 以下のようなものを用意します.

これは src ディレクトリのソースコードの変更時に対応するテストを実行すること, テストコードの変更時にはそのファイル自身のテストを実行すること, を設定しています.

そして以下のようなコマンドを実行することで, 監視状態に入ります.

$ watchr phpunitrunner.watchr

前提として, ソースコードが src/Foo.php であればテストコードは tests/FooTest.php というように, 命名規則にそったファイル名になっていることが必要です.

変更のあったときにだけ, そのファイルだけテストが実行されるので, 素早く確実にフィードバックを得ることができます.

また, Ctrl + \ を押すことで, 全てのテストを実行することもできます.

注意としては, 監視対象のファイルの読み込みが watchr の起動時なので, 例えば途中で新規に追加したファイルは監視対象に入っていないことです.
ある程度開発が進んで, 作業のメインが既存ファイルの編集になったときに, より高い効果を発揮するでしょう.

まとめ

テストだけでなく, その実行まで自動化することで開発にリズムが生まれ, フロー状態に入りやすくなります.
開発効率を上げ, 楽しい TDD ライフを送りましょう.

その他, オススメのツールややり方などありましたら, 是非 @yuya_takeyama まで教えてください.

, , , ,

Cache_Lite は未だに PHP4 なコードであんまりだし, Zend_Cache は依存関係がめんどくさそうなので, 外部ライブラリに依存しないものを作ってみました.

Github
Openpear

使い方

Cache_Casual オブジェクトは ArrayAccess インターフェイスを実装しており, 連想配列のように操作することができるので, かなりカジュアルだと思います.

カスタムキャッシュコンテナ

上記の例では, キャッシュコンテナとしてファイルを利用しています.
キャッシュコンテナは Dependency Injection (依存性の注入) により Cache_Casual オブジェクトに差し込むことができるので, Cache_Casual_ContainerAbstract クラスを継承し, Cache_Casual_ContainerInterface インターフェイスのメソッドを実装するだけで簡単につくることができます.

例としては, Cache_Casual_Container_Memory が一番シンプルでわかりやすいと思います.

今の自分の用途としてはファイルコンテナで充分なのでまだ作ってはいませんが, 例えば PDO 用のコンテナを書けば RDB にデータを格納することもできますし, memcached 用のコンテナを書けば同様のインターフェイスを持った KVS にデータを格納することもできると思います.

制限

これは各コンテナに依存する問題ですが, 値が serialize/unserialize できる必要があります.
File コンテナは serialize() してファイルに書き込んでいます.

個人的には今の所配列ぐらいしか保存する用途が無いので全然試してはいないですが, 多分循環参照を持ったオブジェクトとかは格納できないと思います.

テストについて

ユニットテストにはいつも通り PHPUnit を使っていますが, 今回は初めての試みとして, vfsStream というファイルシステムのモックライブラリを使用しています.
これは PHP のストリームラッパーという仕組みを利用して, 実際のファイルシステム上に操作を行うことなく, ファイルを用いた処理をテストすることができるというものです.
とても便利なので, これについては後日ブログにまとめる予定です.

, , , ,

PHP の interface や implements ってご存知ですか ? 知っている前提で話を進めます。

それでは PHP の組込みインターフェイスをご存知ですか ?
この記事ではそれについて紹介します。

なお、PHP のバージョンは 5.3 以降を前提としています。 (多分、 5.2 でも動く)

PHP の組込みインターフェイスとは

PHP でインターフェイスを定義するには、 interface 宣言を記述する必要があります。
しかし、以下のようなインターフェイスは PHP に予め組込まれており、定義すること無しに利用できます。

普通 interface といえば、メソッドの定義を強制することで、クラスの再利用性を高めるために用いられていると思います。
上記の組込みのインターフェイスについても、もちろんそういった利点があります。

ですが、組込みインターフェイスには、通常のクラス定義ではあり得ない振る舞いをオブジェクトに持たせることができるものがあります。
要は 普通じゃないオブジェクトを作れる ということです。

配列っぽいオブジェクトをつくる

ここからは、PHP の組込みインターフェイスの便利さを知ってもらうために、配列っぽいオブジェクトの作り方を説明します。

さて、配列っぽいってどういうことでしょうか ?
配列、つまり PHP の array 型は、以下のような使い方ができますね。

以下では、array 型が持つこれらの機能を、オブジェクトに実装していきます。

(0) コンストラクタ

まずは、 array をプロパティとして持つ ArrayLike クラスを定義します。

<?php
class ArrayLike
{
    protected $_arr;

    public function __construct($arr = array())
    {
        $this->_arr = $arr;
    }
}

ArrayLike オブジェクトは以下のように生成します。

<?php
require_once 'ArrayLike.php';

$arrObj = new ArrayLike(array('foo', 'bar', 'baz'));

以下では省略しますが、 $arrObj はすべてこのように生成しているという前提でお読みください。

(1) 要素数を数える (Countable)

現状ではこうなります。

<?php
echo count($arrObj), PHP_EOL; // => 1

3 となって欲しいところですが、なりません。
オブジェクトに count() 関数を適用すると、通常は常に 1 となるようです。
(count 関数のマニュアルには「オブジェクトに含まれるプロパティの数を数える」となってますが間違いのようです)

そこで、 ArrayLike クラスに次のような変更を加えましょう。
最初に宣言したプロパティや定義したメソッドは省略します。

<?php
class ArrayLike implements Countable
{
    public function count()
    {
        return count($this->_arr);
    }
}

Countable というインターフェイスに定義されている count() メソッドを実装しました。
すると、 count() に対する ArrayLike オブジェクトの振る舞いはいかのようになります。

<?php
echo count($arrObj), PHP_EOL; // => 3

期待通りの値が返ってきました !
これで配列に一歩近づきましたね。

(2) 要素を 1 つ 1 つ列挙する (Iterator)

foreach 構文にオブジェクトを渡すと、通常は public なプロパティが列挙されます。
ArrayLike オブジェクトは public なプロパティを持たないので、 foreach は空振りします。
構文エラーではありませんが、やはり配列として期待する動作とは違います。

そこで、再び ArrayLike クラスに変更を加えます。
先ほどまでに実装している部分は省略しています。
実装するメソッド数がさっきより多いので、詳細は気にせず「Iterator インターフェイスのメソッドを実装した」ことだけ理解していただけで問題ありません。

<?php
class ArrayLike implements Countable, Iterator
{
    protected $_index;

    public function rewind()
    {
        $this->_index = 0;
    }

    public function key()
    {
        return $this->_index;
    }

    public function current()
    {
        return $this->_arr[$this->key()];
    }

    public function next()
    {
        $this->_index++;
    }

    public function valid()
    {
        return $this->_index < $this->count();
    }
}

すると、 foreach に対する ArrayLike オブジェクトの振る舞いは以下のようになります。

<?php
foreach ($arrObj as $key => $value) {
    echo "{$key}:{$value}", PHP_EOL;
}
// =>
//   0:foo
//   1:bar
//   2:baz

だいぶ配列に近づいてきましたね。

(3) 要素へ値の代入と取得 (ArrayAccess)

count や foreach のときと違い、オブジェクトに対して [] 演算子を使うと Fatal error となります。

<?php
$arrObj[1] = 'foo'; => PHP Fatal error:  Cannot use object of type ArrayLike as array in...

というわけで、さらに ArrayLike に手を加えます。
例によって、今までに実装したメソッドや宣言したプロパティは省略しています。

<php
class ArrayLike implements Countable, Iterator, ArrayAccess
{
    public function offsetSet($key, $value)
    {
        $this->_arr[$key] = $value;
    }

    public function offsetGet($key)
    {
        return $this->_arr[$key];
    }

    public function offsetExists($key)
    {
        return isset($this->_arr[$key]);
    }

    public function offsetUnset($key)
    {
        unset($this->_arr[$key]);
    }
}

さて、再び [] 演算子を使ってみましょう。

<?php
$arrObj[1] = 'foo';
echo $arrObj[1], PHP_EOL; // => foo

これはもうほとんど配列ですね。

完成

ここまでで実装してきたものをまとめると以下のようになります。

まとめ

PHP の組込みインターフェイスを使うと、普通のクラス定義ではありえない振る舞いをオブジェクトに持たせることができます。
また、言語組込みのインターフェイスなので、とりあえずこれに従っておけば、メソッドの命名で喧嘩せずに済むかもしれません。

See also

, ,