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

参考

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

Share

最近の投稿

NetlifyのSplit TestingとFunctionsについて使い方をまとめる Split TestingはGitHubのブランチをベースにしたA/Bテストを行うための機能のことで、FunctionsはNetlifyでAWS Lambdaを使うことができる

NetlifyとはHTMLなどの静的コンテンツのみで構成されたWebサイトを閲覧できる形で配信するWebサービス GitHubやBitbucket、GitLabなどと連携して使うことができて、リポジトリにプッシュすることで自動でCI/CDを行うことができる、無料枠が豊富で独自ドメインを設定可能

WordPressからJekyll(GitHub Pages)に移行した手順をまとめる。 お金的な事情や使いやすさなどの理由で無料のJekyll+GitHub Pagesに移行した。JekyllとはMarkdown等から静的ページを生成する静的サイトジェネレータ

Scala開発のためにScalaらしさをまとめる 言語設計者の設計思想を元にScalaらしさについてまとめる オブジェクト指向と関数型の融合について

StorybookとはUI開発環境を提供するツール React、React Native、Angular、Vueなどをサポートしている ユーザーは独立した開発環境でコンポーネントを個別に作成して挙動の確認をテストできたり、コンポーネントを一覧にしてカタログ化できるので他の人に紹介する時に使えたりする

カテゴリ一覧

タグ一覧