DBを使ったテストを考えた場合、
・Insertのテストが走るとTableにそのデータがInsertされテストが正常完了する
・上記テストをもう一度走らせると、前回のInsertされたデータがあるのでDuplicateでテストが失敗する
上記の問題を解決することを考える
・テストが走るとテーブルが初期化される
・Insertのテストが走ると初期化されているので、前のテストでInsertされたデータは消えているので、Duplicateにはならない。
##phpunit/dbunit
・テストが接続するDB情報を設定できる
・テストが走るとテーブルのデータが初期化される
###インストール
Composerを使ってインストール
{
"require": {
"phpunit/phpunit": ">=4.0,<5.0",
"phpunit/dbunit": ">=1.3,<1.4"
}
}
・テストでは本番DBにはInsertさせないのでレプリカのDBとテーブルを用意する
・DBUnitはデータベースを作ったりテーブルを作ったりは出来ないので事前に用意しておく
create database hogeDB
・接続するユーザーを作る
GRANT ALL PRIVILEGES ON hogeDB.* TO hoge@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;
###テストが接続するためのDB情報
<?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
・テストの初期処理
<?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;
}
}
・テストファイル
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のテストに使える
・機能テストに使える
・データベース接続を伴うクラス、メソッドは他との依存関係をなくすように設計する