Yii + Travis CI でユニットテストと機能テストを走らせる

## はじめに
Yii + Travis CI でユニットテストと機能テストを実行するやり方です。
簡単な yml ファイルを書くことによって、git push 時に指定した PHP のバージョン毎に自動で
protected/unit/*, protected/functional/* にあるファイルのテストを実行してくれます。
この記事では Travis CI の細かな説明は省いて、どういう流れでテストを実行していくかを書いていきます。

## ローカルの環境
OS: Mac OSX
Yii: 1.1.14
PHP: 5.4.28
MySQL: 5.6.17

## composer.json を用意

Yii と PHPUnit 系のファイルをインストール:

~~~composer.json
{
    "require": {
        "yiisoft/yii": "1.1.14"
    },
    "require-dev": {
        "phpunit/phpunit": "3.7.*",
        "phpunit/phpunit-selenium": "*",
        "phpunit/phpunit-story": "*",
        "phpunit/dbunit": "*",
        "phpunit/php-invoker": "*"
    },
    "config": {
        "vendor-dir": "protected/vendor"
    }
}
~~~

## phpunit.xml, WebTestCase.php の設定

Travis CI でのブラウザテストは今のところ Firefox と PhantomJS のみ対応しているようなので protected/tests/phpunit.xml は以下のようにしました。

~~~phpunit.xml
<phpunit bootstrap="bootstrap.php"
    colors="true"
    convertErrorsToExceptions="true"
    convertNoticesToExceptions="true"
    convertWarningsToExceptions="true"
    stopOnFailure="false">

    <selenium>
        <!-- <browser name="Internet Explorer" browser="*iexplore" /> -->
        <browser name="Firefox" browser="*firefox" />
        <!-- <browser name="Google Chrome" browser="*googlechrome" /> -->
    </selenium>

</phpunit>
~~~

あと PHP 5.4 以上だと PHP ビルトインウェブサーバーを使うという命令を protected/tests/CWebTestCase.php に書いておきます。

~~~WebTestCase.php
$testBaseUrl = (version_compare(PHP_VERSION, '5.4.0') >= 0)
    ? 'http://localhost:8000/index-test.php/'
    : 'http://localhost/hoge/index-test.php/';

define('TEST_BASE_URL', $testBaseUrl);
~~~

## .travis.yml の内容

リポジトリのルートディレクトリに .travis.yml というファイルを作成。
以下が Yii でユニットテスト、機能テストを自動で走らせる .travis.yml になります。

~~~.travis.yml
language: php

php:
  - 5.5
  - 5.4
  - 5.3

before_install:
  - export DISPLAY=:99.0
  - sh -e /etc/init.d/xvfb start
  - wget http://selenium-release.storage.googleapis.com/2.41/selenium-server-standalone-2.41.0.jar
  - '[[ "$TRAVIS_PHP_VERSION" == "5.3" ]] || java -jar selenium-server-standalone-2.41.0.jar > /tmp/selenium.log 2>&1 &'
  - '[[ "$TRAVIS_PHP_VERSION" == "5.3" ]] || php -S localhost:8000 > /tmp/server.log 2>&1 &'

install:
  - composer self-update
  - composer install

before_script:
  - mkdir -p assets protected/runtime && chmod a+w assets protected/runtime
  - mysql -e 'CREATE DATABASE hoge;'
  - mysql -e 'CREATE DATABASE hoge_test;'
  - php protected/yiic migrate --interactive=0 --connectionID=testdb

script:
  - cd protected/tests && ../vendor/bin/phpunit unit
  - '[[ "$TRAVIS_PHP_VERSION" == "5.3" ]] || ../vendor/bin/phpunit functional'

notifications:
  email: false

~~~

language: で言語の指定をし、php: でどのバージョンを使うかを追加していきます。
PHP を使うにあっては [Travis CI: Building a PHP project](http://docs.travis-ci.com/user/languages/php/) に詳しく書かれているので省略。
それ以降はほぼコマンドを上から順に実行していく流れかと思います。

xvfb を起動:
( [Travis CI: GUI & Headless browser testing](http://docs.travis-ci.com/user/gui-and-headless-browsers/) に詳しい説明が書かれています )

~~~yml
export DISPLAY=:99.0
sh -e /etc/init.d/xvfb start
~~~

Selenium の DL と PHP 5.3 以外の場合に selenium と PHP ビルトインウェブサーバーを起動:
( TRAVIS_PHP_VERSION は Travis CI 側の環境変数で [Travis CI: Environment variables]( http://docs.travis-ci.com/user/ci-environment/#Environment-variables) で確認できる )

~~~yml
wget http://selenium-release.storage.googleapis.com/2.41/selenium-server-standalone-2.41.0.jar
'[[ "$TRAVIS_PHP_VERSION" == "5.3" ]] || java -jar selenium-server-standalone-2.41.0.jar > /tmp/selenium.log 2>&1 &'
'[[ "$TRAVIS_PHP_VERSION" == "5.3" ]] || php -S localhost:8000 > /tmp/server.log 2>&1 &'
~~~

Composer のアップデートとパッケージのインストール:
( composer 本体はインスール済みたいなのでアップデートのみしておく )

~~~yml
composer self-update
composer install
~~~

assets, protected/runtime ディレクトリを作成して、書き込み権限を与える:
テスト用のデータベースを作成。hoge_test のみだけだとエラーが出るので、hoge も作っておく:
yiic migrate でテスト用のマイグレーションを適用する:
( --interactive=0 で yes/no を自動化、--coneectionID は後ほど説明します )

~~~yml
mkdir -p assets protected/runtime && chmod a+w assets protected/runtime
mysql -e 'CREATE DATABASE hoge;'
mysql -e 'CREATE DATABASE hoge_test;'
php protected/yiic migrate --interactive=0 --connectionID=testdb
~~~

最後にテストを実行:
( PHP ビルトインウェブサーバーを使っているので PHP 5.3 以外でのみ機能テストを実行 )

~~~yml
cd protected/tests && ../vendor/bin/phpunit unit
'[[ "$TRAVIS_PHP_VERSION" == "5.3" ]] || ../vendor/bin/phpunit functional'
~~~

全体的な流れは以上になります。
Apache をインストールしてとかは少し大変そうだったので、
今回は PHP 5.4 以上で使える PHP ビルトインウェブサーバーを使いました。
これだと Yii 1.x 系の意味がかなり薄れて Yii2 使えよって話ですが、
ユニットテストは 5.3 でも実行できるので良しとします。

### migrate コマンドの --connectionID=testdb について

このオプションはテスト用にマイグレーションを適用するときに使うものです。
protected/config/console.php に以下のように書くとそっちのデータベースにも適用してくれます。

~~~console.php
return array(
    ...
    'components' => array(
        'db' => array(
            ...
        ),
        'testdb' => array(
            'class' => 'CDbConnection',
            'connectionString' => 'mysql:host=localhost;dbname=hoge_test',
            'emulatePrepare' => true,
            'username' => 'hoge',
            'password' => 'fuga',
            'charset' => 'utf8',
            'tablePrefix' => '',
        ),
        ...
~~~

## まとめ
Yii + Travis CI でユニットテストと機能テストを実行するやり方をまとめてみました。
Yii2 になると PHP 5.4 以上ですし、Selenium から Codeception に変わったりで、テストの書き方や実行方法が変わってきますが、簡素な記述で幅のあるテストの自動実行が可能になるのも Travis CI の特徴のひとつなので、これから少しずつですが導入していこうかと考えています。

ちなみに自分が作った Yii のデモアプリにも使ってみました
[jamband/yii-englishwordbook-demo](https://github.com/jamband/yii-englishwordbook-demo)

## 参考 .travis.yml

[yii2 / .travis.yml](https://github.com/yiisoft/yii2/blob/master/.travis.yml)
[Codeception / .travis.yml](https://github.com/Codeception/Codeception/blob/1.8/.travis.yml)
[MinkSeleniumDriver / .travis.yml](https://github.com/Behat/MinkSeleniumDriver/blob/master/.travis.yml)
[phpunit-selenium / before_script.sh](https://github.com/sebastianbergmann/phpunit-selenium/blob/master/before_script.sh)
[capybara / .travis.yml](https://github.com/jnicklas/capybara/blob/master/.travis.yml)