バグ報告 > その他 > PHPUnitによるテストが失敗する |
その他
スレッド表示 | 古いものから | 前のトピック | 次のトピック | 下へ |
投稿者 | スレッド |
---|---|
snitta |
投稿日時: 2014/2/2 22:03
対応状況: −−−
|
一人前 登録日: 2013/10/3 居住地: 島根県 投稿: 100 |
Re: PHPUnitによるテストが失敗する PHPUnitによるMDB2の意図しない切断について、
やはり環境で問題をカバーするのではなくテスト自体を修正できないかと思います。 そこで改善方法を二つ程考えましたので、よろしければお目通し頂きたいです。 1. MDB2のインスタンスをバックアップの対象にしない。 2. 各テスト毎にMDB2のインスタンスを新規作成&破棄する。 1. の解決方法は前回同様、PHPUnit_Framework_TestCase::$backupGlobalsBlacklist を指定するものです。 DB接続をテスト間で共有するという前提が必要ですが、 元々の Common_TestCase::setUp() がコネクションプールから取っており、 またテスト毎にプールをクリアしていないからいいかな?と思ってます。
参考: http://phpunit.de/manual/3.7/ja/fixtures.html 引用: クラスの静的属性のバックアップ・リストアの実装には、PHP 5.3 (あるいはそれ以降のバージョン) が必要です。 2. の解決方法は不具合で切断されていた挙動を仕様にしてしまおう、というものです。 まずテスト準備段階で html/require.php を読み込んだ時にMDB2オブジェクトが作成されますが、 これをPHPUnitがバックアップしないように開放しておきます。 次に Common_TestCase::setUp() で SC_Query_Ex::getSingletonInstance('', true, true) で新規接続を行います。 これにより各テストで正しい手続きが行われたDB接続を使用できるようになります。 テスト毎に新規接続するパッチ:
長くなりましたがこの解決方法の是非と、 より良い解決方法がありましたらご教示頂けましたら幸いです。 ついでになって失礼ですが SC_Query_Ex::getSingletonInstance($dsn, $force_run, $new) の $new について、 既にコネクションプールに $dsn が存在する場合は問答無用で新規接続しないという挙動になっています。 これは仕様でしょうか?
|
snitta |
投稿日時: 2014/1/31 19:27
対応状況: −−−
|
一人前 登録日: 2013/10/3 居住地: 島根県 投稿: 100 |
Re: PHPUnitによるテストが失敗する ご返事ありがとうございます。
エンコーディング指定はおまけなのですね。参考になります。 ただ他にも SC_DB_DBFactory::initObjQuery() 等で設定初期化用のクエリーが発行されており、 これらを開発者全員が把握してテスト環境をすり合わせるのは大変だと思います。 http://svn.ec-cube.net/open_trac/browser/branches/version-2_13-dev/data/class/db/dbfactory/SC_DB_DBFactory_MYSQL.php?rev=23329#L361 とここまで言っておいてふと思いつきました。 PHPUnitによって意図しない再接続が起きるのが問題なのだから、 自分で明示的に新規接続してしまえば良いのではと。
これならテスト毎に初期化コードも走り、PHPUnitによってMDB2がおかしくなろうと関係ないはず…と思いましたが結果は同じでした。 SC_Query_Ex::getSingletonInstance($dsn = '', $force_run = false, $new = false) の $new は新規接続するかどうかですよね。 なぜでしょう…w ちょっと時間が足りず中途半端ですが、ここまでのご報告とさせて下さい。 また時間が取れ次第調べたいと思います。 nanasess 様お付き合いありがとうございました。
|
nanasess |
投稿日時: 2014/1/31 16:29
対応状況: −−−
|
神 登録日: 2006/9/9 居住地: 投稿: 2325 |
Re: PHPUnitによるテストが失敗する 引用:
1回目と2回目の条件が変化してしまうのは問題ですね。。 SC_Query で MDB2::setCharset() をコールしているのは、character_set_client = latin1 などの環境を考慮して、「念のために」再設定(イレギュラー対応)しているものなので、個人的には、 1. 条件が変化しないよう、サーバー側の環境面で差異を無くした上で 2. 本来の関心事である、アプリケーション側のユニットテストを実行。 3. 別途 SC_Query のユニットテスト内で、 MDB2::setCharset() のテスト(イレギュラーケースのテスト) という流れが良いのではないかと思っています。 どうしても、アプリケーション側のテストで MDB2::setCharset() のテストをしたい場合は、 $backupGlobalsBlacklist をテストケースでオーバーライドするしかなさそうですね。。 |
snitta |
投稿日時: 2014/1/31 14:13
対応状況: −−−
|
一人前 登録日: 2013/10/3 居住地: 島根県 投稿: 100 |
Re: PHPUnitによるテストが失敗する nanasess 様
早速のご回答ありがとうございます! 引用: どうしても character_set_client を変更できない環境は別として、通常 PHPUnit を実行する環境(ローカル環境や CIサーバーなど)は設定できると思いますので、my.cnf などで、character_set_client を正しく設定するのが良いのではないでしょうか。 テスト環境の不備という点でしたらまさにおっしゃられる通りですが、今回の問題はエンコーディングだけではなく、テスト毎にテスト条件が変わってしまうという所にあると思います。 具体的には SC_Query のコンストラクタで MDB2::setCharset() を呼んでいますが、MySQL/PostgreSQLの実装では mysql_set_charset() や pg_set_client_encoding() を実行するだけで再接続の考慮はされていません。 同じ Common_TestCase::setUp() を通しても初回のテストではエンコーディングが指定してある、二回目以降のテストでは指定されていない、というのは問題ではないでしょうか…。 参考にした個所はこちらです。 http://svn.ec-cube.net/open_trac/browser/branches/version-2_13-dev/data/class/SC_Query.php?rev=23329#L82 http://svn.ec-cube.net/open_trac/browser/branches/version-2_13-dev/data/module/MDB2/Driver/mysql.php?rev=23329#L626 http://svn.ec-cube.net/open_trac/browser/branches/version-2_13-dev/data/module/MDB2/Driver/pgsql.php?rev=23329#L538 引用: テストケースの観点からすると、テストとは直接関係のない設定を、テストプログラムにコーディングするのは、あまり良くありません。 勉強になります。確かにあまり気持ちのいいやり方ではないですね。 これはPHPUnitとMDB2の問題ですので phpunit.xml 辺りに追い出す方法がないか探しましたが見つけられませんでした。 # グローバル変数バックアップ機能の切り替えだけはありました。 http://phpunit.de/manual/3.7/ja/appendixes.annotations.html#appendixes.annotations.backupGlobals
|
nanasess |
投稿日時: 2014/1/31 13:22
対応状況: −−−
|
神 登録日: 2006/9/9 居住地: 投稿: 2325 |
Re: PHPUnitによるテストが失敗する どうしても character_set_client を変更できない環境は別として、通常 PHPUnit を実行する環境(ローカル環境や CIサーバーなど)は設定できると思いますので、my.cnf などで、character_set_client を正しく設定するのが良いのではないでしょうか。
どうしても character_set_client を変更できないのでしたら、 $backupGlobalsBlacklist をオーバーライドしてあげるのは良いと思います。 テストケースの観点からすると、テストとは直接関係のない設定を、テストプログラムにコーディングするのは、あまり良くありません。 |
snitta |
投稿日時: 2014/1/31 12:25
対応状況: −−−
|
一人前 登録日: 2013/10/3 居住地: 島根県 投稿: 100 |
PHPUnitによるテストが失敗する ------------------------------------------------------------------------------------------
[EC-CUBE] 2.13.0-dev (http://svn.ec-cube.net/open_trac/browser/branches/version-2_13-dev?rev=23329) [OS] CentOS 6.5 [PHP] PHP 5.3 [データベース] MySQL 5.6 [WEBサーバ] Apache 2.2.15 [ブラウザ] Firefox 26.0 [現象] PHPUnitによるテストが失敗する ------------------------------------------------------------------------------------------ いつもお世話になっております。 PHPUnitによるテストのうち Common_TestCase::$objQuery を使っているテストについて、 実行環境によっては失敗する場合があります。 発生条件の一例: * DB_TYPE が mysql である事。 * コマンドラインにおいて mysql_connect() 後の character_set_client が utf8 以外である事。 再現手順:
テストが失敗する原因: PHPUnitのグローバル変数バックアップのせい? 失敗したテストケースではDBから取得したデータが文字化けしていました。 そこからMySQLのクエリーログを調べると MDB2::setCharset() が適用されていない接続が使用されていました。 次にこの辺りの処理を順に追っていくと以下のようになります。 https://github.com/sebastianbergmann/phpunit/blob/3.7.29/PHPUnit/Framework/TestCase.php#L802-L810 1. テスト前にグローバル変数を serialize() で保存。 2. テスト実行。 3. テスト後にグローバル変数を unserialize() で復元。 最初のテストの 3. でオリジナルのMDB2オブジェクトがGC対象になりデータベース接続が切れます。 次のテストでは復元されたMDB2オブジェクトによって自動的に再接続されますが、 MDB2::setCharset() が呼ばれないために文字化けに繋がっているのでは?と考えます。 対処方法: ならグローバル変数の復元対象からMDB2を外そうという安直な思考で PHPUnit_Framework_TestCase::$backupGlobalsBlacklist を指定すると解消しました。
原因や対処はこれで本当によいのか、どなたかご検証頂けましたら幸いです。 よろしくお願いいたします。
|
スレッド表示 | 古いものから | 前のトピック | 次のトピック | トップ |