アライドアーキテクツの伊藤です。
前回のエントリでは、PHPUnit系のお話を書きましたが、今回もしつこくPHPUnit系のお話を書きます。PHPUnitでテストを書いている時、データベースへの接続が発生するようなテストがあった場合、皆さんはどうしてますでしょうか。
レガシーコード改善ガイドによれば、データベース接続を伴う単体テストはあまり望ましくない為、データベース接続を伴うクラス、メソッドとの依存関係を排除して単体テストを書くべきとあります。
僕もそれが本来あるべき姿だと思いますが、今回はその話は一旦横に置いておき、PHPUnit上で使えるDBUnit拡張について書かせて頂きます。
使い方
通常のテストクラスは「PHPUnit_Framework_TestCase」を継承して作りますが、DBUnitを使う場合は「PHPUnit_Extensions_Database_TestCase」を継承して、さらにabstract functionの「getConnection」と「getDataSet」を実装します。
↓こんな感じで↓
1 2 3 4 5 6 7 8 9 10 11 |
class SampleDBTest extends PHPUnit_Extensions_Database_TestCase { public function getConnection() { $pdo = new PDO('mysql:host=192.168.***.***; dbname=test', 'user', 'password'); return $this->createDefaultDBConnection($pdo); } public function getDataSet() { return $this->createXMLDataSet(dirname(__FILE__) . '/../data/sample.xml'); } } |
getConnectionで使用するデータベース情報、getDataSetで初期データをぶち込んでいます。sample.xmlは次のようなXMLファイルです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?xml version="1.0" encoding="UTF-8"?> <dataset> <table name="sample"> <column>id</column> <column>name</column> <column>telephone</column> <row> <value>1</value> <value>itoh</value> <value>03-****-****</value> </row> <row> <value>2</value> <value>katoh</value> <value>04-****-****</value> </row> </table> </dataset> |
このように記述すると、テストメソッドが実行される前にsampleテーブルにレコードが2行追加されます。
試しに、ちゃんと初期データが追加されているかどうかを確認する為、次のようなテストを書いてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/** @test */ public function 初期データがちゃんとロードされているかテスト() { // 事前データが作成されて、実際のDBのテーブルの件数が2件であること $this->assertEquals(2, $this->getConnection()->getRowCount('sample')); // 事前データが作成されて、実際のDBからSQLで取得したテーブルの内容と事前データのテーブルの内容が同一であること $sql = 'SELECT id, name, telephone FROM sample'; $this->assertTablesEqual($this->getDataSet('sample')->getTable('sample'), $this->getConnection()->createQueryTable('sample', $sql)); // 事前データが作成されて、実際のDBからSQLで取得したテーブルの内容と予め用意した期待値用xmlで生成したテーブルの内容が同一であること $sql = 'SELECT name, telephone FROM sample'; $this->assertTablesEqual($this->createXMLDataSet(dirname(__FILE__) . '/../data/sample_expected.xml')->getTable('sample'), $this->getConnection()->createQueryTable('sample', $sql)); // 事前データが作成されて、実際のDBからSQLで取得したデータセットの内容と事前データのデータセットの内容が同一であること $this->assertDataSetsEqual($this->getDataSet('sample'), $this->getConnection()->createDataSet(array('sample'))); } |
テストはちゃんと全て通ります。ちなみに3番目のassertは予め用意した期待値用XMLを利用しています。sample_expected.xmlの内容はこんな感じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?xml version="1.0" encoding="UTF-8"?> <dataset> <table name="sample"> <column>name</column> <column>telephone</column> <row> <value>itoh</value> <value>03-****-****</value> </row> <row> <value>katoh</value> <value>04-****-****</value> </row> </table> </dataset> |
まとめ
このようにDBUnit拡張を使うと、簡単に初期データの投入や、予め用意されているfunctionや仕組みを使って、データの検証ができます。便利ですね〜。実際に使用する場合は、PHPUnit_Extensions_Database_TestCaseをさらに拡張して、データのロールバックの仕組みや、各テストケース事に異なる初期データをぶち込む仕組みを入れるなどして使い易くする必要があるかと思います。その辺についても書こうかと思いましたが、今回はここまでということで。。
アライドアーキテクツでは、一緒に働く単体テスト好きな仲間を随時募集しています。是非一度採用サイトを覗いてみてください。
元Javaプログラマ。現在はScala/PlayでWeb開発と、SwiftでiOSアプリ開発をしています。 Unitテストとか書いてる時が一番楽しかったりします。