Ответ 1
В вашей установленной папке, вероятно, есть все производители и файлы кеша. Попробуйте установить только исходную папку.
Я пытаюсь создать покрытие кода для моего PHP-проекта с помощью PHPUnit и phpdbg, используя следующую команду:
phpdbg -dmemory_limit=512M -qrr ./bin/phpunit -c .phpunit.cover.xml
Это отлично работает:
PHPUnit 6.2.4 by Sebastian Bergmann and contributors.
........ 8 / 8 (100%)
Time: 114 ms, Memory: 14.00MB
OK (8 tests, 13 assertions)
Generating code coverage report in HTML format ... done
Однако, когда я использую ту же самую команду в контейнере докера:
docker run -it --name YM4UPltmiPMjObaVULwsIPIkPL2bGL0T -e USER=sasan -v "/home/sasan/Project/phpredmin:/phpredmin" -w "/phpredmin" --user "1000:www-data" php:7.0-apache phpdbg -dmemory_limit=512M -qrr ./bin/phpunit -c .phpunit.cover.xml
Я получаю следующую ошибку:
PHPUnit 6.2.4 by Sebastian Bergmann and contributors.
[PHP Fatal error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 561514763337856 bytes) in /phpredmin/vendor/phpunit/phpunit/src/Util/GlobalState.php on line 166]
Я не понимаю, почему PHPUnit необходимо выделить 561514763337856 байт памяти. Я подозреваю, что он застревает в цикле, но почему это не происходит за пределами контейнера? Вот моя версия PHP на моей машине:
PHP 7.0.22-0ubuntu0.17.04.1 (cli) (built: Aug 8 2017 22:03:30) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
with Zend OPcache v7.0.22-0ubuntu0.17.04.1, Copyright (c) 1999-2017, by Zend Technologies
И вот файл .phpunit.cover.xml:
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/6.3/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
cacheTokens="false"
colors="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnError="true"
stopOnFailure="true"
stopOnIncomplete="false"
stopOnSkipped="false"
stopOnRisky="false"
timeoutForSmallTests="1"
timeoutForMediumTests="10"
timeoutForLargeTests="60"
verbose="false">
<testsuites>
<testsuite name="PhpRedmin PHP source">
<directory>src-test/</directory>
</testsuite>
</testsuites>
<logging>
<log type="coverage-html" target="cover/" lowUpperBound="35"
highLowerBound="70"/>
</logging>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src-test/</directory>
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
</phpunit>
- Edit1 -
Я обнаружил, что он имеет какое-то отношение к @runInSeparateProcess. Когда я удаляю тест с @runInSeparateProcess, он начинает работать. Но все же я не знаю, в чем проблема
- Edit2 -
Также я узнал, что если я не монтирую свою директорию кода в контейнере Docker, все работает отлично
В вашей установленной папке, вероятно, есть все производители и файлы кеша. Попробуйте установить только исходную папку.
Когда мы используем @runInSeparateProcess
, PHPUnit будет пытаться сериализовать включенные файлы, ini-настройки, глобальные переменные и константы, чтобы передать их новому процессу. В этом случае PHPUnit обнаружил рекурсивный сценарий при сериализации одного из этих элементов, который исчерпал память, доступную для процесса PHP. Нам нужно определить, что изменилось между вашей локальной средой и контейнером Docker.
Во-первых, мы можем попытаться отключить это поведение сериализации, чтобы убедиться, что мы должны идти по этому пути. Добавьте следующий @preserveGlobalState
аннотацию к методу тестирования, который не выполняется:
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testInSeparateProcess()
{
// ...
}
Если это решит проблему или если мы получим новую ошибку, мы можем начать искать различия в контейнере Docker, которые могут вызвать проблему. Без большей наглядности в коде и окружении трудно предложить, с чего начать, но вот несколько идей:
php -i
с каждой средой. Следите за расширениями PHP, которые существуют в одном, но не в другом.phpdbg
, чтобы установить точку останова и выполнить код. Мы уже используем его для создания покрытия, но это также полезный инструмент для отладки. Мы ищем элемент, который вызывает бесконечную рекурсию. Обратите внимание, что нам нужно установить точку останова до того, как PHPUnit выполнит тестовый пример, например, в файле начальной загрузки или исходном коде PHPUnit (строка 810 из TestCase
может работать).www-data
в контейнере имеет тот же UID, что и пользователь, который владеет файлами на хосте.Я не смог воспроизвести эту проблему, используя фиктивный тест в подобной среде (как можно ближе к тому же контейнеру с томом), поэтому тестируемый код может способствовать этой проблеме.