PHPUnitによるMDB2の意図しない切断について、
やはり環境で問題をカバーするのではなくテスト自体を修正できないかと思います。
そこで改善方法を二つ程考えましたので、よろしければお目通し頂きたいです。
1. MDB2のインスタンスをバックアップの対象にしない。
2. 各テスト毎にMDB2のインスタンスを新規作成&破棄する。
1. の解決方法は前回同様、PHPUnit_Framework_TestCase::$backupGlobalsBlacklist を指定するものです。
DB接続をテスト間で共有するという前提が必要ですが、
元々の Common_TestCase::setUp() がコネクションプールから取っており、
またテスト毎にプールをクリアしていないからいいかな?と思ってます。
Index: tests/class/Common_TestCase.php
===================================================================
--- tests/class/Common_TestCase.php (revision 23329)
+++ tests/class/Common_TestCase.php (working copy)
@@ -16,6 +16,15 @@
*/
class Common_TestCase extends PHPUnit_Framework_TestCase
{
+ /**
+ * @var array
+ * @see PHPUnit_Framework_TestCase::$backupGlobals
+ * @see PHPUnit_Framework_TestCase::$backupGlobalsBlacklist
+ */
+ protected $backupGlobalsBlacklist = array(
+ '_MDB2_databases',
+ '_MDB2_dsninfo_default',
+ );
/** SC_Query インスタンス */
protected $objQuery;
参考:
http://phpunit.de/manual/3.7/ja/fixtures.html引用:
クラスの静的属性のバックアップ・リストアの実装には、PHP 5.3 (あるいはそれ以降のバージョン) が必要です。
グローバル変数やクラスの静的属性のバックアップ・リストアの実装には serialize() および unserialize() を使用しています。
PHP 組み込みの一部のクラス、たとえば PDO のオブジェクトはシリアライズできないため、
そのようなオブジェクトが $GLOBALS 配列に格納されている場合はバックアップ操作が失敗します。
2. の解決方法は不具合で切断されていた挙動を仕様にしてしまおう、というものです。
まずテスト準備段階で html/require.php を読み込んだ時にMDB2オブジェクトが作成されますが、
これをPHPUnitがバックアップしないように開放しておきます。
次に Common_TestCase::setUp() で SC_Query_Ex::getSingletonInstance('', true, true) で新規接続を行います。
これにより各テストで正しい手続きが行われたDB接続を使用できるようになります。
テスト毎に新規接続するパッチ:
Index: data/class/SC_Query.php
===================================================================
--- data/class/SC_Query.php (リビジョン 23329)
+++ data/class/SC_Query.php (作業コピー)
@@ -101,7 +101,7 @@
public static function getSingletonInstance($dsn = '', $force_run = false, $new = false)
{
$objThis = SC_Query_Ex::getPoolInstance($dsn);
- if (is_null($objThis)) {
+ if ($new || is_null($objThis)) {
$objThis = SC_Query_Ex::setPoolInstance(new SC_Query_Ex($dsn, $force_run, $new), $dsn);
}
/*
Index: tests/class/Common_TestCase.php
===================================================================
--- tests/class/Common_TestCase.php (リビジョン 23329)
+++ tests/class/Common_TestCase.php (作業コピー)
@@ -27,14 +27,13 @@
protected function setUp()
{
- $this->objQuery = SC_Query_Ex::getSingletonInstance('', true);
+ $this->objQuery = SC_Query_Ex::getSingletonInstance('', true, true);
$this->objQuery->begin();
}
protected function tearDown()
{
$this->objQuery->rollback();
- $this->objQuery = null;
}
/**
Index: tests/require.php.base
===================================================================
--- tests/require.php.base (リビジョン 23329)
+++ tests/require.php.base (作業コピー)
@@ -1,6 +1,19 @@
<?php
$HOME = realpath(dirname(__FILE__)) . '/../';
require_once "$HOME/html/require.php";
+
+// PHPUnitのグローバル変数バックアップによるMDB2オブジェクトの破壊防止の為、
+// html/require.php を読み込んだ際に作成されたMDB2オブジェクトを開放する。
+//
+// @see PHPUnit_Framework_TestCase::$backupGlobals
+// @todo MDB2を使用しなくなった際に削除する。
+foreach (SC_Query_Ex::$arrPoolInstance as $objQuery) {
+ $objQuery->conn->disconnect();
+ $objQuery->conn->free();
+}
+SC_Query_Ex::$arrPoolInstance = array();
+unset($objQuery);
+
// ローカルの環境に応じて追加・編集し、phpunitが使えるように設定してください。
set_include_path(get_include_path() . PATH_SEPARATOR . '/usr/share/pear');
set_include_path(get_include_path() . PATH_SEPARATOR . '/usr/local/lib/php');
長くなりましたがこの解決方法の是非と、
より良い解決方法がありましたらご教示頂けましたら幸いです。
ついでになって失礼ですが SC_Query_Ex::getSingletonInstance($dsn, $force_run, $new) の $new について、
既にコネクションプールに $dsn が存在する場合は問答無用で新規接続しないという挙動になっています。
これは仕様でしょうか?
----------------
Seiji Nitta
zenith6@gmail.com
https://github.com/zenith6/