Грешка в уеб теста на PHPUnit при изпращане на заглавки в теста

Написах REST API в symfony. Той приема Json заявка и генерира форматиран pdf с FPDF библиотека като отговор.

Искам да напиша уеб тест на phpunit, който ще провери състоянието на отговора и данните в заглавката.

public function test_getCertificate()
{
    $client = $this->getClient(['username'=>'user','password'=>'xxxxxx']);

    $client->request(
        'GET',
        '/api/v1/certificate',
        array(),
        array(),
        array('CONTENT_TYPE' => 'application/json'),
        null
    );

    $this->assertEquals(200, $client->getResponse()->getStatusCode());

    $this->assertTrue(
        $client->getResponse()->headers->contains(
            'Content-Type',
            'application/x-download'
        )
    );

    $this->assertTrue(
        $client->getResponse()->headers->contains(
            'Content-Disposition',
            'attachment; filename="el_certificate.pdf"'
        )
    );
}

Проблемът е, че при стартиране на тест PHPUnit вече стартира заглавката на изхода и тогава моят контролер има проблем да генерира PDF:

Uncaught PHP Exception Exception: "FPDF error: Some data has already been output, can't send PDF file"

header() се извиква от кода на библиотеката, който не мога да променя. Когато се опитам да изчистя изходния буфер в моя тестов скрипт с ob_end_clean() или стартирам нов буфер с ob_start(), получавам изключение:

Uncaught PHP Exception PHPUnit_Framework_Error_Warning: "Cannot modify header information - headers already sent by (output started at /usr/share/php/PHPUnit/Util/Printer.php:134)"

Версии PHP 7.2.2-3+ubuntu16.04.1+deb.sury.org+1, PHPUnit 5.1.3

Някакви съвети как да се справя в подобна ситуация?

РЕДАКТИРАНЕ: Опитах се да стартирам този тест в отделен процес:

/**
 * @runInSeparateProcess
 * @preserveGlobalState disabled
 */
public function test_getCertificate()
{
    //...
}

След това получих грешка:

PHP Warning:  Uncaught require_once(/var/cache/test/jms_diextra/doctrine/EntityManager_5a9419b75e6b1.php): failed to open stream: No such file or directory

/vendor/symfony/phpunit-bridge/DeprecationErrorHandler.php:108
/var/cache/test/appTestDebugProjectContainer.php:2456
/var/cache/test/appTestDebugProjectContainer.php:2456
/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Container.php:329
/var/cache/test/appTestDebugProjectContainer.php:8179
/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Container.php:329
/var/cache/test/appTestDebugProjectContainer.php:7994
/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Container.php:329
/var/cache/test/appTestDebugProjectContainer.php:7954
/var/www/html/elearning-ap in /var/cache/test/appTestDebugProjectContainer.php on line 2456
PHP Fatal error:  appTestDebugProjectContainer::getDoctrine_Orm_DefaultEntityManagerService(): Failed opening required '/var/cache/test/jms_diextra/doctrine/EntityManager_5a9419b75e6b1.php' (include_path='.:/usr/share/php') in /var/cache/test/appTestDebugProjectContainer.php on line 2456
test_getPhases
{"error":{"code":500,"message":"Internal Server Error","exception":[{"message":"Compile Error: appTestDebugProjectContainer::getDoctrine_Orm_DefaultEntityManagerService(): Failed opening required '\/var\/cache\/test\/jms_diextra\/doctrine\/EntityManager_5a9419b75e6b1.php' (include_path='.:\/usr\/share\/php')","class":"Symfony\\Component\\Debug\\Exception\\FatalErrorException","trace":[{"namespace":"","short_class":"","class":"","type":"","function":"","file":"\/var\/cache\/test\/appTestDebugProjectContainer.php","line":2456,"args":[]}]}]}}

person Srdjan    schedule 26.02.2018    source източник


Отговори (1)


Добре, най-накрая разбрах какво се случва.

Ако PHPUnit трябва да тества някакъв код, който излъчва заглавки (напр. генериране на файл), тестът трябва да се изпълнява в отделен процес. Това може да се постигне с помощта на анотация:

/**
 * @runInSeparateProcess
 * @preserveGlobalState disabled
 */
public function test_getCertificate()
{
    //...
}

В моя случай JMSDiExtraBundle създаде грешки, защото го опакова в свой собствен прокси обект. Ако не искате JMSDiExtra да генерира прокси класове към доктрината, тогава може да се добави следната конфигурация:

jms_di_extra:
    doctrine_integration: false

След това тестът може да се изпълнява правилно в отделен процес без проблеми с изхода на заглавката.

person Srdjan    schedule 27.02.2018