はじめまして、株式会社Flesselの田中と申します。

私は長いことケータイサイトを作る仕事に関わってきました。
縮小傾向にあるフィーチャーフォンですが、まだまだ現役です。

このエントリーではPHPのストーリーテストツールBehatを利用して、
ケータイサイトの受け入れテストを行う方法をご紹介します。

インストール
今回は対象となるプロジェクトにcomposerを使ってBehatを組み込む方法をとります。

まずはcomposerをインストールします。
curl -s https://getcomposer.org/installer | php
※CentOS環境だと証明書の関係で動かないことがあります。

次にcomposerの設定ファイルであるcomposer.jsonをプロジェクト直下に作成します。
今回はBehatともにMinkというブラウザテストの抽象化ライブラリを使うので、これも一緒に設定します。
{
    "require": {
        "behat/behat": ">=2.4@stable",
        "behat/mink":  "1.4@stable",
        "behat/mink-extension": "*",
        "behat/mink-goutte-driver": "*"
    },

    "config": {
        "bin-dir": "bin/"
    }
}
composer.jsonが用意できたら、インストールコマンドを叩いて依存するライブラリをインストールします。 
php composer.phar install
これでvendorディレクトリの中にbehatがインストールされ、binディレクトリにbehatコマンドができます。
(※2012年8月3日現在、依存関係が解決できずにインストールが失敗するようです)

プロジェクトの初期化
behatがインストールされたのでbehatが利用するファイルを初期化します。
bin/behat --init
これでプロジェクト直下に下記のファイルが作成されます。
features/bootstrap/FeatureContext.php
このファイルにテストコードを記述することになります。

フィーチャー定義を用意する
フィーチャーとはアプリケーションが持つ個別の機能のことです。Behatでは各フィーチャーごとにテストシナリオが書かれたファイルを用意します。
このファイルは拡張子をfeatureとしてfeaturesディレクトリに配置します。

各ファイルは自然言語に近い記述で書きます。
今回は次の定義をsearch.featureとして作成しました。
# language: ja 
フィーチャ: 検索機能
  欲しい商品を見つけるために
  ユーザーとして
  商品を検索できる

  背景:
    前提 au端末で接続する

  シナリオ: カメラを検索する
    かつ"/" を表示している
    もし"keyword" フィールドに "camera" と入力する
    かつ"検索" ボタンをクリックする
    ならば"「camera」の検索結果" と表示されていること
    かつ"「camera」ランキング 1位" と表示されていること

  シナリオ: ヒットしない単語で検索する
    かつ"/" を表示している
    もし"keyword" フィールドに "fak;efalkjekd" と入力する
    かつ"検索" ボタンをクリックする
    ならば"ご指定の検索条件に該当する商品はありませんでした。" と表示されていること
日本語で書かれていてとてもわかりやすいと思います。
各シナリオの「前提」からはじまる行以降はステップと呼ばれ、テストはこのステップごとに実行されていきます。
ステップ中のダブルウォーテーションで囲われた文字列が変数として扱われます。

さて、ここで一度テストを実行してみます。
step01
黄色くなっているところがテストが未実装なステップです。また、下の方にテストを実装する際のスニペットも表示されています。
通常はこのスニペットをコピペしてテストを実装していく流れになります。


MinkContextを利用する
単純なブラウザをつかったテストであれば、今回一緒にインストールしたMinkExtensionが提供するMinkContextを用いると自分でステップを実装せずにテストすることができます。
MinkContextが提供しているステップについてはbehat -diコマンドで参照できます。日本語のステップについては https://github.com/Behat/MinkExtension/blob/master/i18n/ja.xliffで確認できます。

便利なMinkContextを利用するにはFeatureContext.phpに次の修正を加えます。
--- features/bootstrap/FeatureContext.php.orig  2012-08-02 08:01:36.000000000 +0900
+++ features/bootstrap/FeatureContext.php       2012-08-02 08:03:03.000000000 +0900
@@ -7,6 +7,8 @@
 use Behat\Gherkin\Node\PyStringNode,
     Behat\Gherkin\Node\TableNode;
 
+use Behat\MinkExtension\Context\MinkContext;
+
 //
 // Require 3rd-party libraries here:
 //
@@ -17,7 +19,7 @@
 /**
  * Features context.
  */
-class FeatureContext extends BehatContext
+class FeatureContext extends MinkContext
 {
     /**
      * Initializes context.

また、次の内容のbehat.ymlをプロジェクトルートに作成します。
# behat.yml
default:
  extensions:
    Behat\MinkExtension\Extension:
      base_url: 'http://example.com/'
      goutte:    ~

base_urlにはテスト時にアクセスするサーバーのベースURLを設定します。

ここでテストを実行すると次のようになります。
step02
「au端末で接続する」というステップ以外は青になりテスト実装が加わったことがわかります。

独自のステップを実装する
「au端末で接続する」はケータイサイト特有のステップですから当然提供されていません。
今回はau端末での接続をau端末のUser-AgentとEz番号をHTTPヘッダにもつという条件として定義します。

これのステップの実装は次のようになります。
    /**
     * @Given /^au端末で接続する$/
     */
    public function au端末で接続する()
    {
        $this->getSession()
        ->getDriver()
        ->getClient()
        ->setServerParameters(['HTTP_USER_AGENT' => 'KDDI-CA39 UP.Browser/6.2.0.13.1.5 (GUI) MMP/2.0']);
        $this->getSession()->setRequestHeader('x-up-subno', '10msimmsim000_vr.ezweb.ne.jp');
    }
MinkContextを利用している場合にヘッダを設定するにはx-up-subnoを設定しているように$this->getSession()->setRequestHeader()を用いればよいのですが、
今回ブラウザの実装として利用しているGoutteがsetRequestHeaderを通したユーザーエージェントの書き変えに対応していないためこのような形になっています。

実行する
それではすべてのステップの実装ができたのでbehatコマンドを叩いてテストを実行してみます。
step03
すべてのステップがグリーンになりました! 簡単ですね!

まとめ
Behatでは自然言語に近いフィーチャー定義を利用するので、エンジニア以外でもテストの概要を把握することができます。
しかも、MinkExtensionと組み合わせることで容易にブラウザテストをできるのは大変魅力的です。
皆さんもぜひ使ってみてください。