Phpunit: Serialisasi 'Penutupan' tidak diperbolehkan

Dibuat pada 2 Jan 2012  ·  12Komentar  ·  Sumber: sebastianbergmann/phpunit

Meskipun $GLOBAL Closures tidak lagi diserialkan sejak 01aa34783c9b19d39e568641f3f2dd0fc983b11a & #352 a $GLOBAL array yang berisi Closure sebagai nilai masih akan menyebabkan kesalahan "Serialization of 'Closure' is notallowed".

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

Komentar yang paling membantu

Saya memiliki pesan kesalahan yang sama setiap kali saya membuat instance new MyRestClient() , konstruktornya berisi $this->client = new \GuzzleHttp\Client(); . Itu juga sama ketika saya mencoba menggunakan $x=function(){}; di konstruktor kelas saya. Saya kira klien Guzzle melakukan hal serupa secara internal. Ini membuatnya tidak mungkin untuk membuat instance dari dalam pengujian phpunit. aku sedih banget sekarang :sob:

Semua 12 komentar

Kasus lain saya mengerti

 /* tes.php */
 penutupan kelasTest memperluas PHPUnit_Framework_TestCase
 {
 fungsi testClosure() {
 $ this-> assertEquals (1, 1);
 panggilan_pengguna_fungsi(fungsi($a) {
 melempar baru \Exception("test");
 }, 10);
 $this->assertEquals(2, 2);
 }
 }

dan kemudian jalankan dalam proses isolasi

 phpunit --proses-isolasi tes.php

kamu akan mendapatkan

 Ada 1 kesalahan:
 1) phTest::testClosure
 PHPUnit_Framework_Exception: PHP Kesalahan fatal: Pengecualian tidak tertangkap 'Pengecualian' dengan pesan 'Serialisasi 'Penutupan' tidak diizinkan' di -:37
 Jejak tumpukan:
 #0 -(37): membuat serial (Array)
 # 1 - (123): __phpunit_run_isolated_test ()
 # 2 {utama}
 dilemparkan - on line 37
 KEGAGALAN!
 Pengujian: 1, Pernyataan: 0, Kesalahan: 1.

Saya mengalami masalah yang sama ketika menggunakan isolasi proses, untuk mengatasinya saya menambahkan __sleep ke testCase saya dan membersihkan penutupan di sana. Bagi saya, saya telah menyimpan beberapa tiruan di properti testcase jadi itu adalah kesalahan saya sendiri, saya harap ini membantu seseorang.

Saya juga mengalami masalah yang sama, dan dapat mereplikasi masalah @tmilos yang disebutkan sebelumnya. Saya tidak tahu apakah tiket ini sudah mati, tetapi alangkah baiknya jika kita bisa menyelesaikan ini. Saya lebih dari bersedia untuk mengajukan permintaan tarik jika itu lebih baik.

Permintaan tarik selalu dihargai!

Saya tahu ini agak lama, tetapi saya tidak mengerjakan proyek untuk sementara waktu. Lebih jauh ke komentar oleh @tmilos , saya dapat mereplikasi masalah jika saya memaksakan kesalahan sintaks, misalnya:

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

Perhatikan kurangnya argumen yang disediakan di akhir call_user_func . Pengecualian serialisasi dihasilkan dari upaya membuat serial objek PHPUnit_Framework_TestResult. Upaya serialisasi ini dapat ditemukan pada baris 42 dari PHPUnit/Framework/Process/TestCaseMethod.tpl.dist . Bagian yang menyinggung dari objek yang akan diserialisasikan adalah referensi penutupan dalam hierarki jejak Pengecualian yang dilemparkan:

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

)

Pertanyaan saya kemudian, karena ini adalah pertama kalinya saya menambal PHPUnit, tidak cukup untuk menghapus penutupan atau memodifikasinya menjadi jinak - yang tidak diragukan lagi akan melibatkan penggunaan Refleksi - apakah ada beberapa cara praktik terbaik PHPUnit untuk menangani ini ? Ada pemikiran atau masukan setidaknya?

Juga, saya menulis tes di bawah Regresi/GitHub. Apakah ini dapat diterima?

@kunjalpopat , mengacu pada masalah Anda, Hal pertama yang akan saya periksa adalah pengecualian. Saat dalam isolasi proses, pengecualian yang dilemparkan mungkin memberi Anda pesan "Serialization of Closure". Coba bungkus kode pengujian Anda dalam try/catch dan lihat apakah itu memperbaiki masalah, jika ya, maka Anda mungkin ingin melihat memangkas cakupan try/catch sampai Anda menemukan area masalah.

Masalahnya terletak pada 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]);
}

Saya telah membuat beberapa pembantu di 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;
}

dan mengubah sedikit fungsi 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]);
    }
}

versi ini tampaknya berfungsi (saya tidak lagi menangkap pengecualian itu).
Karena ini adalah rekursi terhadap $GLOBALS, jadi, ini dapat memberikan panas ekstra ke cpu.

Perbaikan kode di atas dari stafr memperbaiki masalah PHPunit yang saya alami dengan pengecualian "Serialization of Closure". Terimakasih banyak!

Saya memiliki pesan kesalahan yang sama setiap kali saya membuat instance new MyRestClient() , konstruktornya berisi $this->client = new \GuzzleHttp\Client(); . Itu juga sama ketika saya mencoba menggunakan $x=function(){}; di konstruktor kelas saya. Saya kira klien Guzzle melakukan hal serupa secara internal. Ini membuatnya tidak mungkin untuk membuat instance dari dalam pengujian phpunit. aku sedih banget sekarang :sob:

Hanya menambahkan pengalaman saya. Pada dasarnya setiap kali Anda menempatkan fungsi atau kelas anonim sebagai atribut kelas uji, phpunit akan melempar Serialization of 'Closure' is not allowed atau Serialization of 'class<strong i="6">@anonymous</strong>' is not allowed . Jadi, jika Anda perlu menggunakan fungsi atau kelas anonim, pastikan variabel satu kali, bukan atribut kelas uji.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat