PHPUnit + DBUnitでMySQLのテストを行う

Published: 2016年4月10日 by tomsato

概要

PHPUnitとDBUnitを使ってMySQLのテストを行う(Oracleのテストもできる)
テスト用のMySQLを用意してPHPUni+DBUnitでinsert,updateなどのテストを行って
その後に意図したデータになっているか確認をすることができる

テストの流れ

データベースのテストは次の4段階に分けて考える必要がある

Gerard Meszaros は、著書 xUnit Test Patterns でユニットテストを次の四段階に分類しています。

  1. フィクスチャのセットアップ (Setup)
  2. テストしたいシステムの実行 (Exercise)
  3. 結果の検証 (Verify)
  4. 後始末 (Teardown)

PHPUnit マニュアル – 第8章 データベースのテスト

フィクスチャとはアプリケーションやデータベースの初期状態のこと、テストを実行する前に用意する

環境の準備

MySQLのインストール

$ sudo yum -y install http://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm
$ sudo yum -y install mysql-community-server
$ sudo service mysqld start

MySQL環境の準備

$ mysql -uroot -p -e "create database test_database"
$ mysql -uroot -p -e "create table test_database.hoge_table (id int, name varchar(20))"

MySQL環境の確認

$ mysql -uroot -p -e "show databases"
Enter password:
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test_database      |
+--------------------+
$ mysql -uroot -p -e "use test_database;show tables;desc hoge_table"
Enter password:
+-------------------------+
| Tables_in_test_database |
+-------------------------+
| hoge_table              |
+-------------------------+
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+

PHP5.6のインストール

$ sudo rpm -Uvh http://ftp.iij.ad.jp/pub/linux/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
$ sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
$ sudo yum install -y --enablerepo=remi --enablerepo=remi-php56 php php-opcache php-devel php-mbstring php-mcrypt php-mysqlnd php-phpunit-PHPUnit php-pecl-xdebug php-pecl-xhprof

$ php --version
PHP 5.6.20 (cli) (built: Mar 31 2016 07:24:47)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies
    with Xdebug v2.4.0, Copyright (c) 2002-2016, by Derick Rethans

composerのインストール

$ curl -sS https://getcomposer.org/installer | php
$ sudo mv composer.phar /usr/local/bin/composer
$ composer -V
Composer version 1.0.0 2016-04-05 13:27:25

phpunitのインストール

$ mkdir phpunit; cd phpunit
$ vim composer.json
$ cat composer.json
{
	"require-dev": {
		"phpunit/phpunit": "4.5.*",
		"phpunit/dbunit": ">=1.2"
	}
}
$ sudo /usr/local/bin/composer install

$ vendor/bin/phpunit -V
PHPUnit 4.5.1 by Sebastian Bergmann and contributors.

unrecognized option -- V

PHPUnitファイルの用意

最終的に以下のようにファイルを作成する

$ tree
.
├── composer.json
├── composer.lock
├── tests
│   ├── assert # テストファイル
│   │   └── HogeTableTest.php
│   ├── common # テストファイル共通の処理が書かれている
│   │   └── Generic_Tests_DatabaseTestCase.php
│   ├── _fixute # データセット
│   │   └── hoge_table.csv
│   └── phpunit.xml # DB接続情報を記述
└── vendor # composerを使ってinstallしたdbunit,phpunitのファイル群が入っている

DB接続情報を記述したファイルの用意

PHPUnit実行時に引数でこのファイルを指定する
最悪このファイルがなくてもPHPUnitのファイルにDB情報を直接記述するのも可

$ mkdir -p tests/common
$ mkdir -p tests/assert
$ mkdir -p tests/_fixute

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

共通ロジックをまとめたファイルを用意

$ cat tests/common/Generic_Tests_DatabaseTestCase.php
<?php
abstract class Generic_Tests_DatabaseTestCase extends PHPUnit_Extensions_Database_TestCase
{
    // PDO のインスタンス生成は、クリーンアップおよびフィクスチャ読み込みのときに一度だけ
    static private $pdo = null;

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

    /**
     * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection
     */
    final public function getConnection()
    {
        if ($this->conn === null) {
            if (self::$pdo == null) {
                self::$pdo = new PDO( $GLOBALS['DB_DSN'], $GLOBALS['DB_USER'], $GLOBALS['DB_PASSWD'] );
            }
            $this->conn = $this->createDefaultDBConnection(self::$pdo, $GLOBALS['DB_DBNAME']);
        }

        return $this->conn;
    }
}

フィクスチャを作る

記述方法はYAML,CSV,Array,XMLなどで記述できる
YAMLが一番わかりやすいがMySQLのselectはCSV形式で出力できるためそのまま活用できやすいのでCSVで作成する

$ cat tests/_fixute/hoge_table.csv
id,name
1,'tomsato'
2,'hogehoge'
3,'hello world'
11,'testtest'

テストケースを作成する

$ cat tests/assert/HogeTableTest.php
<?php 
require_once dirname(__DIR__).'/common/Generic_Tests_DatabaseTestCase.php'; 
class HogeTableTest extends Generic_Tests_DatabaseTestCase 
{ 
    /** 
     * @return PHPUnit_Extensions_Database_DataSet_IDataSet 
     */ 
    protected function getDataSet() { 
        $dataSet = new PHPUnit_Extensions_Database_DataSet_CsvDataSet(); 
        $dataSet->addTable('hoge_table', dirname(__DIR__)."/_fixute/hoge_table.csv");
        return $dataSet;
    }

    public function testGetRowCount()
    {
	// 4件insertしたのでテーブルの件数が4件になっていることを確認する
        $this->assertEquals(4, $this->getConnection()->getRowCount('hoge_table'));
    }
}

PHPUnit実行

以下のコマンドを実行すると対象のtableにデータが入ってテストケースが実行されます
実行時にはtableが一度クリーンされるので空の状態でデータが入るので冪等性を意識して、何度でもテストを再実行できるようにしましょう

$ vendor/bin/phpunit -c tests/phpunit.xml tests/assert/HogeTableTest.php
PHPUnit 4.5.1 by Sebastian Bergmann and contributors.

Configuration read from /home/tomsato/phpunit/tests/phpunit.xml

.

Time: 259 ms, Memory: 3.75Mb

OK (1 test, 1 assertion)

■ もう少し修正を加えてみる

任意のSQLを実行する

// 以下のメソッドを追加
$ vim tests/common/Generic_Tests_DatabaseTestCase.php
...
   public function getPdo() {
        return self::$pdo;
   }
...

// update文を記述
$ vim tests/assert/HogeTableTest.php
    public function testUpdateSql()
    {
        $pdo = $this->getPdo();
        $pdo->exec("update hoge_table set id=111 where id='11'");
    }

// 実行
$ vendor/bin/phpunit -c tests/phpunit.xml tests/assert/HogeTableTest.php

実行後にtableを確認するとupdate文が実行されている

CSVデータとテーブルをSELECTした結果を比較する

updateなどでデータを修正した後に意図したデータになっているか確認するために
CSV(他にYAML,配列,XMLなど)データとテーブルをSELECTした結果を比較する

// 以下のメソッドを追加する
$ vim tests/assert/HogeTableTest.php
...
    public function testQuerySql()
    {
        $queryTable = $this->getConnection()->createQueryTable(
             'hoge_table', 'select * from hoge_table'
        );
        $expectedTableObj = new PHPUnit_Extensions_Database_DataSet_CsvDataSet();
        $expectedTableObj->addTable('hoge_table', dirname(__DIR__)."/_fixute/hoge_table.csv");
        $expectedTable = $expectedTableObj->getTable('hoge_table');


        $this->assertTablesEqual($expectedTable, $queryTable);
    }
...

// 実行
$ vendor/bin/phpunit -c tests/phpunit.xml tests/assert/HogeTableTest.php

参考

基本はマニュアルを熟読する

コメントを書く

※ 個別に返信が必要な時のみご記入ください

※ Emailは公開されません

※ 承認されると名前・コメントが下記に表示されます

コメント一覧

最近の投稿

ビジュアルリグレッションテストについてまとめ、ネットで調べると数多くのライブラリがありどれがどんな立ち位置なのか全体像がわかりずらかったのでどんな種類があるのか入門の入門としてまとめます、またPlaywrightを使って実際に触ってみました

社内ツールなどの超小規模なAPIをGolangで実装する際にフレームワークを使うべきかを、実際にnet/httpを使った実装とフレームワークを使った実装を比較することでどれだけ優位性があるかを見ていきたいと思います。今回はフレームワークにはシンプルで使いやすそうなEchoを使うことにします。

vue-pdfを使ってNuxt.jsで作成しているアプリケーションに pdfスライドを表示させるサンプルを作成しました README.md通りに実装してもうまくいかないところがあったのでそのあたり含めてまとめます

Vue.js / Nuxt.jsにおけるログインの実装方法をまとめる Auth0やNuxt.jsのAuth Moduleとmiddlewareについて調べつつサンプルを作成することで理解を深める

コンポーネント設計について考える Atomic DesignやPresentational Component, Container Componentについてまとめつつ 自分だったらVue.js / Nuxt.jsでどういうコンポーネント設計にするかについてまとめます

カテゴリ一覧

タグ一覧