Phpunit: 「Closure」の連載は許可されていません

作成日 2012年01月02日  ·  12コメント  ·  ソース: sebastianbergmann/phpunit

$GLOBALクロージャーはシリアル化されなくなりましたが、01aa34783c9b19d39e568641f3f2dd0fc983b11a および #352 値としてクロージャーを含む$GLOBAL配列は、「「許可されたクロージャー」のシリアル化エラー」が引き続き発生します。

$GLOBALS[] = array( 'foo' => function() { return 'bar'; }  );
typbug

最も参考になるコメント

new MyRestClient()をインスタンス化するたびに、この同じエラー メッセージが表示されます。そのコンストラクターには$this->client = new \GuzzleHttp\Client();が含まれます。 私のクラスのコンストラクターで$x=function(){};を使用しようとしたときも同じです。 Guzzleクライアントは内部的に同様のことをしていると思います。 これにより、phpunitテスト内からインスタンス化することが不可能になります。 私は今とても悲しいです:sob:

全てのコメント12件

私を含め、何人かの人がこの問題を抱えているようです。 http://stackoverflow.com/questions/4366592/symfony-2-doctrine-2-phpunit-3-5-serialization-of-closure-exception

私はそれを取得している別のケース

 /* test.php */
クラス closureTest は PHPUnit_Framework_TestCase を拡張します
 {
 関数 testClosure() {
 $this->assertEquals(1, 1);
 call_user_func(関数($a) {
 新しい \Exception("test") をスローします。
 }、10);
 $this->assertEquals(2, 2);
 }
 }

そして、それをプロセス分離で実行します

 phpunit --プロセス分離 test.php

あなたは得るでしょう

エラーが 1 件ありました:
 1) phTest::testClosure
 PHPUnit_Framework_Exception: PHP 致命的なエラー: キャッチされていない例外 'Exception' とメッセージ 'Serialization of 'Closure' is not allowed' in -:37
スタックトレース:
 #0 -(37): シリアライズ(配列)
 #1 - (123): __phpunit_run_isolated_test()
 #2 {メイン}
投入 - 37行目
失敗!
テスト: 1、アサーション: 0、エラー: 1。

プロセス分離を使用するときに同じ問題が発生していました。これを回避するために、testCaseに__sleepを追加し、そこでクロージャをクリーンアップしました。 私にとっては、テストケースのプロパティにいくつかのモックを保存していたので、本当に自分のせいでした。

私も同じ問題を抱えており、前述の問題@tmilos を再現できます。 このチケットが無効かどうかはわかりませんが、解決できれば幸いです。 必要に応じてプル リクエストを送信するつもりです。

プルリクエストはいつでも大歓迎です!

少し時間が経ったことは知っていますが、私はしばらくの間プロジェクトから外れていました。 @tmilosによるコメントに

/* test.php */
class closureTest extends PHPUnit_Framework_TestCase
{
    function testClosure() {
        call_user_func(function($a) {
            throw new \Exception("test");
        });
    }
}

call_user_func最後に引数が指定されていないことに注意してください。 シリアル化の例外は、PHPUnit_Framework_TestResult オブジェクトをシリアル化しようとしたために発生します。 このシリアル化の試みは、 PHPUnit/Framework/Process/TestCaseMethod.tpl.dist 42 行目にあります。 シリアル化されるオブジェクトの問題のある部分は、スローされた例外のトレース階層内のクロージャ参照です。

[1] => Array
    (
        [function] => {closure}
        [class] => Issue451Test
        [type] => ->
        [args] => Array
            (
            )

)

PHPUnitにパッチを適用するのはこれが初めてなので、私の質問は、クロージャーを削除したり、それ以外の場合は無害になるように修正したりすることはできません.これには間違いなくReflectionの使用が含まれます. ? 少なくとも何か考えや入力はありますか?

また、Regressions/GitHub でテストを作成しました。 これは受け入れられますか?

@kunjalpopat 、あなたの問題に関して、私が最初に確認するのは例外です。 プロセス分離の場合、スローされた例外により、「Serialization of Closure」メッセージが表示される場合があります。 テスト コードを try/catch でラップして、問題が解決するかどうかを確認します。問題が解決する場合は、問題のある領域が見つかるまで try/catch の範囲を縮小することを検討することをお勧めします。

問題はPHPUnit_Util_GlobalState::backupGlobalsます:

if ($key != 'GLOBALS' &&
    !in_array($key, $superGlobalArrays) &&
    !in_array($key, $blacklist) &&
    !$GLOBALS[$key] instanceof Closure) {  // <-- this is the problem
    self::$globals['GLOBALS'][$key] = serialize($GLOBALS[$key]);
}

PHPUnit_Util_GlobalStateヘルパーを作りました:

public static function checkIfThereIsClosureInIt($arr) {
    if ($arr instanceof Closure)
        return true;
    if (is_object($arr))
        $arr = get_object_vars($arr);
    if (is_array($arr))
        foreach ($arr as $x)
            if (PHPUnit_Util_GlobalState::checkIfThereIsClosureInIt($x))
                return true;
    return false;
}

少しbackupGlobals関数を変更しました:

foreach (array_keys($GLOBALS) as $key) {
    if ($key != 'GLOBALS' &&
        !in_array($key, $superGlobalArrays) &&
        !in_array($key, $blacklist) &&
        !PHPUnit_Util_GlobalState::checkIfThereIsClosureInIt($GLOBALS[$key])
//        !$GLOBALS[$key] instanceof Closure
    ) {
        self::$globals['GLOBALS'][$key] = serialize($GLOBALS[$key]);
    }
}

このバージョンは機能しているようです(私はもうその例外をキャッチしていません)。
これは $GLOBALS に対する再帰であるため、CPU に余分な熱を与える可能性があります。

上記の stafr のコード修正により、「クロージャーのシリアル化」例外で発生していた PHPunit の問題が修正されました。 どうもありがとう!

new MyRestClient()をインスタンス化するたびに、この同じエラー メッセージが表示されます。そのコンストラクターには$this->client = new \GuzzleHttp\Client();が含まれます。 私のクラスのコンストラクターで$x=function(){};を使用しようとしたときも同じです。 Guzzleクライアントは内部的に同様のことをしていると思います。 これにより、phpunitテスト内からインスタンス化することが不可能になります。 私は今とても悲しいです:sob:

私の経験を追加するだけです。 基本的に、匿名関数またはクラスをテスト クラス属性として配置すると、phpunit はSerialization of 'Closure' is not allowedまたはSerialization of 'class<strong i="6">@anonymous</strong>' is not allowedをスローします。 したがって、匿名関数またはクラスを使用する必要がある場合は、クラス属性をテストするのではなく、その 1 回限りの変数を使用してください。

このページは役に立ちましたか?
0 / 5 - 0 評価