読者です 読者をやめる 読者になる 読者になる

PHPUnitでデータベースありのテストを行うための設定メモ

第8章 データベースのテスト

インストール

PHPUnitのインストールは以下のコマンドで行う。

# pear config-set auto_discover 1
# pear install pear.phpunit.de/PHPUnit

auto_discoverでインストールがうまくいかない場合は。

# pear channel-discover pear.phpunit.de 
# pear channel-discover pear.symfony.com

DBのテストを行うためには拡張をインストールする。
以下のコマンドでインストールする。

# pear install phpunit/DbUnit

基本クラスの準備

DBのテストをするためには、PHPUnit_Extensions_Database_TestCaseを継承したクラスを用意する。
また、getConnectionメソッドとgetDataSetメソッドを定義する必要がある。

<?php

require_once "PHPUnit/Extensions/Database/TestCase.php";

class CommonDatabaseTest extends PHPUnit_Extensions_Database_TestCase
{

    /**
     * @var PDOのインスタンス生成は、クリーンアップおよびフィクスチャ読み込みのときに一度だけ
     */
    static public $pdo = null;

    /**
     * @var PHPUnit_Extensions_Database_DB_IDatabaseConnection のインスタンス生成は、テストごとに一度だけ
     */
    public $conn = null;

    /**
      * データベースに接続
      */
     public function getConnection()
    {
        if ( $this->conn === null ) {
            if ( self::$pdo == null ) {
                self::$pdo = new PDO($GLOBALS['DB_DSN'], $GLOBALS['DB_USER'], $GLOBALS['DB_PASSWD']);
                self::$pdo->query('SET NAMES UTF8');
            }
            $this->conn = $this->createDefaultDBConnection(self::$pdo, $GLOBALS['DB_DBNAME']);
        }

        return $this->conn;
    }

    /**
      * フィクスチャを読み込んで、データベースを初期化する
      *
      * @return PHPUnit_Extensions_Database_DataSet_CompositeDataSet
      */
    public function getDataSet()
    {
        $compositeDs = new PHPUnit_Extensions_Database_DataSet_CompositeDataSet(array());

        $dir = dirname(__FILE__) . '/fixture';
        $fh = opendir($dir);
        while ($file = readdir($fh)) {
            if ( preg_match('/^\./', $file) ) {
                continue;
            }
            if ( preg_match('/\.xml$/', $file) ) {
                $ds = $this->createMySQLXMLDataSet("$dir/$file");
                $compositeDs->addDataSet($ds);
            }
        }

        return $compositeDs;        
    }    
}

ここで$GLOBALでアクセスしている値を設定するために、以下の様なXMLファイルを作成する。
設定ファイル名は「phpunit.xml」とする。

<?xml version="1.0" encoding="UTF-8" ?>
<phpunit>
  <php>
    <var name="DB_DSN" value="mysql:dbname=dbname;host=localhost" />
    <var name="DB_USER" value="root" />
    <var name="DB_PASSWD" value="" />
    <var name="DB_DBNAME" value="hogehoge" />
  </php>
</phpunit>


この設定ファイルを読み込むためには、以下の様なコマンドで実行することになる。

$ phpunit -c tests/phpunit.xml tests/


フィクスチャファイルのフォーマットは色々とある。
phpMyAdminでデータを作ってmysqldumpで出力、とかしたいので、
MySQL XMLデータセット形式を使う。
mysqldumpのコマンドは以下の様な感じになる。

$ mysqldump --xml -t -u [username] --password=[password] [database] > /path/to/file.xml


このファイルを読み込むためには、createMySQLXMLDataSetメソッドを使うことになる。
基本クラスのgetDataSetメソッド内で使用している。


テスト

テストはCommonDatabaseTestクラスを継承して行う。

DBテーブル内のデータの比較は、期待値をXMLで設定することができる。
「expected.xml」とするファイルを用意する。

<?xml version="1.0"?>
<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <database name="primarire_unittest">
    <table_data name="user">
      <row>
          <field name="first_name">名前</field>
          <field name="last_name">苗字</field>
          <field name="gender"></filed>
      </row>
    </table_data>
    <table_data name="log">
      <row>
          <field name="action">register</field>
          <field name="created_at">2012-10-01 00:00:00</field>
      </row>
    </table_data>
  </database>
</mysqldump>    


このXMLは以下のようにcreateMySQLXMLDataSetで読み込む。

$expectedTables = $this->createMySQLXMLDataSet('expected.xml');


PHPUnitの機能で、透過的にXMLのデータを取得することが出来る。
例えば、userテーブルのデータを取得する場合は以下のようにする。

$expectedUser = $expectedTables->getTable('user');

また、テストの結果、実際にDBに入っているuserテーブルのデータを取得する場合は以下のようにする。

$doneUser = $this->getConnection()->createQueryTable('user', 'SELECT first_name, last_name, gender FROM user');


期待値と実際の値をチェックする場合はassertTablesEqualメソッドを使用する。

$this->assertTablesEqual($expectedUser, $doneUser);


以上のことを踏まえて、ユーザー登録処理をテストするコードは以下の様な感じになる。

require_once "CommonDatabaseTest.php";

class RegisterUserTest extends CommonDatabaseTest
{
     public function testRegisterUser()
     {
          $user = array(
               'first_name' => '名前',
               'last_name'  => '苗字',
               'gender'       => '男',
          );

          $model = new User();
          $model->registerUser($user); 

          $expectedTables = $this->createMySQLXMLDataSet('expected.xml');
          $expectedUser = $expectedTables->getTable('user');

         $doneUser = $this->getConnection()->createQueryTable('user', 'SELECT first_name, last_name, gender FROM user');

         $this->assertTablesEqual($expectedUser, $doneUser);
     }
}