LoginSignup
39
39

More than 5 years have passed since last update.

PHP DBまわりのテスト

Last updated at Posted at 2014-09-17

DBを使ったテストを考えた場合、
・Insertのテストが走るとTableにそのデータがInsertされテストが正常完了する
・上記テストをもう一度走らせると、前回のInsertされたデータがあるのでDuplicateでテストが失敗する

上記の問題を解決することを考える
・テストが走るとテーブルが初期化される
・Insertのテストが走ると初期化されているので、前のテストでInsertされたデータは消えているので、Duplicateにはならない。

phpunit/dbunit

・テストが接続するDB情報を設定できる
・テストが走るとテーブルのデータが初期化される

インストール

Composerを使ってインストール

composer.json
{
    "require": {
        "phpunit/phpunit": ">=4.0,<5.0",
        "phpunit/dbunit": ">=1.3,<1.4"
    }
}

・テストでは本番DBにはInsertさせないのでレプリカのDBとテーブルを用意する
・DBUnitはデータベースを作ったりテーブルを作ったりは出来ないので事前に用意しておく

sql
create database hogeDB

・接続するユーザーを作る

sql
GRANT ALL PRIVILEGES ON hogeDB.* TO hoge@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;

テストが接続するためのDB情報

tests/phpunit.xml
<?xml version="1.0" encoding="UTF-8" ?>
  <phpunit>
    <php>
      <var name="DB_DSN" value="mysql:dbname=hogeDB;host=localhost" />
      <var name="DB_USER" value="hoge" />
      <var name="DB_PASSWORD" value="password" />
      <var name="DB_DBNAME" value="hogeDB" />
  </php>
</phpunit>

・テーブルの初期値データをmysqldumpで取得する

$ mkdir -p tests/fixture
$ mysqladmin --xml -t -u hoge -p hogeDB > tests/fixture/expect.xml

・テストの初期処理

CommonDatabaseTest.php
<?php
class CommonDatabaseTest extends PHPUnit_Extensions_Database_TestCase
{
    static public $pdo = null;
    public $connection = null;

    // テストのDB接続情報
    public function getConnection()
    {
        if ( $this->connection == null ) {
            if ( self::$pdo == null ) {
                self::$pdo = new PDO($GLOBALS['DB_DSN'],
                                     $GLOBALS['DB_USER'],
                                     $GLOBALS['DB_PASSWORD']);
                self::$pdo->query('SET NAMES UTF8');
            }
            $this->connection = $this->createDefaultDBConnection(self::$pdo, $GLOBALS['DB_DBNAME']);
        }

        return $this->connection;
    }

    // テストがDBに接続してデータを初期化する処理
    public function getDataSet()
    {
        $compositeDs = new PHPUnit_Extensions_Database_DataSet_CompositeDataSet([]);

        // fixture配下の.xmlファイルをすべて読み込んでデータセットしてる
        $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;
    }
}

・テストファイル

dbTestSample.php
require_once "CommonDatabaseTest.php";

class dbTestSample extends \CommonDatabaseTest {

    public function testRegisterUser()
    {
        // アプリ側のInsert処理
        $register = new Register();
        $result   = $register->insertMemberData([
            'name'        => '山田太郎',
            'birthday'    => '1980/08/01',
            'sex'         => 0,
        ]);

        // Insert後の期待値Tableデータ
        $expectedTables = $this->createMySQLXMLDataSet('/path/test/except/table.xml');
        $expectedMember = $expectedTables->getTable('member');

        // Insert後のTableデータ
        $doneUser = $this->getConnection()->createQueryTable('member', 'SELECT * FROM member');

        // tableの状態が同じか
        $this->assertTablesEqual($expectedMember, $doneUser);
    }

}

・実行

$ vendor/bin/phpunit -c tests/phpunit.xml tests/dbTestSample.php

所感

・まだよくわかっていない。
・アプリ側のDB接続情報も、テストで動かされた場合はテストDBに接続するように変更が必要なのかな?
・SQLのテストに使える
・機能テストに使える
・データベース接続を伴うクラス、メソッドは他との依存関係をなくすように設計する

39
39
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
39