phpunit memory_limit parameter does not apply - php

I've just installed phpunit via pear in a mac osx 10.7 and everything works fine except I got memory limit errors (xdebug enabled for reports).
I tried to add the -d memory_limit=512M parameter to phpunit but it is not applying because, on the very first error, I added var_dump(ini_get('memory_limit')); exit; and it prints string(3) "32M"
So, why is it not being applied?
Besides that, if I run
php -d memory_limit=256M -r "echo ini_get('memory_limit');"
it echoes "256M"
Is it possible that phpunit is not executing same php?

For those who reach this thread and need to get the configuration for phpunit.xml configuration file:
<php>
<ini name="memory_limit" value="512M" />
</php>
More on section "Setting PHP INI settings, Constants and Global Variables" at
https://phpunit.de/manual/6.5/en/appendixes.configuration.html

Yes you can set every php option with phpunit -d that can be set with ini_set.
You already opened a bug over in the phpunit bug tracker but well I'm going for the more verbose answer here
Reproduce to show it works in general:
echo "<?php var_dump(ini_get('memory_limit')); " > foo.php
phpunit -d memory_limit=12M --bootstrap foo.php
Produces:
string(3) "12M"
PHPUnit 3.6.5 by Sebastian Bergmann.
But phpunit only applies this option once before the first test is run!
So chances are your code is somewhere changing the memory limit back to 32M which is something phpunit can't "fix".
Same goes for setting the memory limit in the phpunit.xml file.

If you don't mind about the speed of the tests, found this thread very useful as it's better handling of memory for your app.
Basically; In your phpunit.xml, under the <phpunit> tag, set the processIsolation to true i.e
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
...
processIsolation="true"
... >
Alternatively,
You can just disable memory limiting altogether under the <php> tag, set the memory_limit to -1 i.e
<php>
...
<ini name="memory_limit" value="-1"/>
...

Related

PHPUnit coverage: Allowed memory size of 536870912 bytes exhausted

I am trying to generate code test coverage for my PHP project with PHPUnit and phpdbg using the following command:
phpdbg -dmemory_limit=512M -qrr ./bin/phpunit -c .phpunit.cover.xml
This works perfectly fine:
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
However, when I use the exact same command in a docker container:
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
I get the following error:
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]
I don't understand why PHPUnit needs to allocate 561514763337856 bytes of memory. I suspect it gets stuck in a loop, but why this does not happen outside of the container? Here is my PHP version on my machine:
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
And here is the .phpunit.cover.xml file:
<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 --
I found that it has something to do with #runInSeparateProcess. When I remove the test that has #runInSeparateProcess then it starts to work. But still I don't know what is the problem
-- Edit2 --
Also I found out that If I don't mount my code directory in the Docker container everything works fine
Add '-d memory_limit=-1' before your test
if use composer use the below code
./vendor/bin/simple-phpunit -d memory_limit=-1 tests/
if you use phpdbg use the below code
phpdbg -d memory_limit=-1 -qrr vendor/bin/phpunit --coverage-text
When we use #runInSeparateProcess, PHPUnit will attempt to serialize included files, ini settings, global variables, and constants to pass them to the new process. In this case, it looks like PHPUnit encountered a recursive scenario when serializing one of these items, which exhausted the memory available to the PHP process. We need to determine what changed between your local environment and the Docker container.
First, we can try disabling this serialization behavior to verify that we should proceed along this path. Add the following #preserveGlobalState annotation to the test method that fails:
/**
* #runInSeparateProcess
* #preserveGlobalState disabled
*/
public function testInSeparateProcess()
{
// ...
}
If this resolves the problem, or if we get a new error, we can begin looking for differences in the Docker container that may cause the issue. Without more visibility into the code and environment, it's hard to suggest where to start, but here are some ideas:
Compare the output of php -i from each environment. Look out for PHP extensions that exist in one, but not the other.
Use phpdbg to set a breakpoint and step through the code. We're already using it to generate coverage, but it's also a useful debugging tool. We're looking for the item that causes the infinite recursion. Note that we'll need to set the breakpoint before PHPUnit executes the test case such as in the bootstrap file or PHPUnit source code (line 810 of TestCase may work).
When bind-mounting a volume, make sure the www-data user in the container has the same UID as the user that owns the files on the host.
Try running the test without the memory limitation. Obviously we can't allocate as much as the error suggests we may need, but the memory limit may mask another underlying problem. We can kill the container if needed.
I couldn't reproduce this issue using a dummy test in a similar environment (as close as I could get—same container with volume), so the code under test may contribute to the problem.
Your mounted folder probably has all vendors and cache files. Try mounting only the source folder.
This is phpdbg bug. Note how much memory it tries to allocate? It is insane. I tried hard to figure out where the bug exactly: if test script full name (directory + script file name) exceeds certain size then it overflows the stack (yeah, stackoverflow ;) and overwrites integer which specifies how much memory must be allocated. Then normal error handling kicks in: not enough memory to allocate such insane amount. So this is for Krakjoe to fix. Or may be I will make a patch for it in my spare time. If you need to have resolution right now: make sure that directory path your script is in is short.

PHPUnit: bootstrap not being executed?

When running a test, my phpunit.xml is being loaded by PHPUnit. I can see it in the console as --bootstrap parameter, but it seems like it's not being executed?
In the xml I set bootstrap="bootstrap.php"
Is it normal that the xml file contents are echoed just below the line Testing started at... and just above PHPUnit 3.7.21 by Sebastian Bergmann.?
Any way in my bootstrap.php file I just put
die "bootstrap executed";
But never see that. What could be wrong?
Edit: This is the contents of phpunit.xml:
<phpunit bootstrap="./bootstrap.php">
</phpunit>
You need to launch the phpunit in one of the following example:
#for load a bootstrap php file (with full path and file extension)
>phpunit --bootstrap bootstrap.php
or
#for load with your xml configuration
>phpunit -c phpunit.xml
Hope this help

PHPUnit TestSuite Exclude

so I would like to exclude a directoy from my Testsuite just like this:
<testsuite name="PHPUnitWillKillMe">
<directory>src/*/Bundle/*/*Bundle/Tests</directory>
<exclude>src/*/Bundle/*/*Bundle/Tests/Controller/</exclude>
</testsuite>
Everything except for the Controllers should be tested.
The thing is, it does not work. PHPUnit still runs all the tests in src//Bundle//*Bundle/Tests/Controller/ when I run
phpunit --testsuite PHPUnitWillKillMe
Any idea?
Best Regards!
PHPUnit Version I tested this were 3.7.21 and 3.7.28.
I tested it on my Symfony demo project (the Bundles suggests that this is what you are using) and I have the same issue. It seems to be a combination of two problems. First, there is a known bug with running PHPUnit (PHPUnit 3.7.19) with the -c or --config option:
https://github.com/sebastianbergmann/phpunit/issues/928
When running it elsewhere and specifying the config file using --config, the exclude would however stop working.
Second, the exclude directive seems to ignore / fail when there is any globbing (*) in the path, so by removing the globbing, it worked for me:
<testsuites>
<testsuite name="Project Test Suite">
<directory>../src/*/*Bundle/Tests</directory>
<directory>../src/*/Bundle/*Bundle/Tests</directory>
<exclude>../src/Blah/MyBundle/Tests/Controller/</exclude>
</testsuite>
</testsuites>
It's the only way I found to exclude the Tests in MyBundle as required. The globbing did not work for the exclude. But then, it means you have to add as many exclude directives as there are folders you want to ignore.
Probable related gihub issue:
https://github.com/sebastianbergmann/phpunit/pull/573
[...] this fix lands in the 4.0 release as it breaks backwards compatibility.
Solution #1: remove any globbing in your paths
Solution #2: Upgrade to PHPUnit v4.* (not tested by myself, see comments, doesn't solve the problem of exclude paths with globbing)
Just had similar issue, phpunit has quite nice support for groups:
...
--filter <pattern> Filter which tests to run.
--group ... Only runs tests from the specified group(s).
--exclude-group ... Exclude tests from the specified group(s).
--list-groups List available test groups.
...
What you do is
/**
* #group nonRunnableGroupName
*/
public function testSomething()
{ /* test here */ }
And run test like
$ phpunit -c /src --exclude-group nonRunnableGroupName

setting phpunit command from the console symfony

I have already posted this question on php unit first test symfony
I installed phpunit via the composer as a per project installation.
When trying vendor/bin>phpunit -c ../../app every thing is ok and I get a positive answer.
Whereas this command give the answer to all the tests in the tests directory.
But I want the result to every test alone.
When trying /vendor/bin>phpunit -c ../../src/xxx/Bundle/tests/entity/yyy.php and I get the following message : could not load c:\wamp\www\symfony\src/xxx/Bundle/tests/entity/yyy.php Parse PI : PI php never end ... Start ttag expected, '<' not found
and when trying /vendor/bin>phpunit -c ../../src/xxx/Bundle/tests/entity/yyy and I get the following message : could not read "..\..\src/xxx/Bundle/tests/entity/yyy"
Could anybody help me to know how should I write the command and from where execute it???
Any ideas???
Don't use the -c option here. The -c option is a shortcut for --configuration and it points to the directory of a PHPunit configuration file (like app/phpunit.xml.dist). That configuration tells PHPunit where to look for the test classes and some other configuration, like the bootstrap file.
If you want to run tests for a specific test, you can do it like phpunit path/to/tests/MyTest.php. But you'll loose the autoloading then. To get that back, you can use the --bootstrap option to point to the bootstrap file. So it'll be phpunit --bootstrap vendor/autoload.php path/to/tests/MyTest.php.
If you want to run this command more often, you can better edit the app/phpunit.xml.dist file and create a new suite:
<?xml version="1.0" encoding="utf-8" ?>
<phpunit ...>
<!-- ... -->
<testsuites>
<testsuite name="MyBundle">
<file>path/to/tests/MyTest.php</file>
</testsuite>
</testsuites>
<!-- ... -->
</phpunit>
And then run: phpunit -c app --testsuite MyBundle
Happened with me too, but in fact we are misreading the documentation you are forgetting 'app' in the command line look:
phpunit -c app src/AppBundle/Tests/Util/CalculatorTest.php
Note the app parameter in command sentence.

phpunit does not find any tests with director xml tag, but does with (some) file tags

I have this config:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
backupGlobals = "false"
backupStaticAttributes = "false"
colors = "false"
convertErrorsToExceptions = "true"
convertNoticesToExceptions = "true"
convertWarningsToExceptions = "true"
processIsolation = "false"
stopOnFailure = "false"
stopOnError = "false"
stopOnIncomplete = "false"
syntaxCheck = "false"
bootstrap = "test_bootstrap.php"
>
<testsuites>
<testsuite name="UnitTests">
<file>unit/api/2/ApiControllerTest.php</file>
<file>unit/api/2/RoutesTest.php</file>
</testsuite>
it runs the Test files. If I replace the files with
<directory>unit</directory>
// or
<directory>unit/api/2</directory>
// or
<directory>unit/api/2/*</directory>
// or
<directory>unit/api/2/*Test.php</directory>
// or
<directory suffix="Test.php">unit/api/2</directory>
It simply says: No tests executed!
Please, what could be wrong?
Ubuntu 12.04 LTS, php 5.3.10, phpunit 3.7.16
Where in you path relative to the unit directory is the phpunit.xml file?
if your path looks anything like this:
projectroot
|- phpunit.xml
|- unit/
|- api/
You could try setting the directory to the following in phpunit.xml:
<directory>./unit</directory>
And then run phpunit from root like this: phpunit -c phpunit.xml
If that doesn't work, something else is wrong. What happens if you run this:
phpunit ./unit/api/2
If no tests are being run then, please answer the following questions:
maybe your methods in the testcases don't start with 'test'?
Do all testcase files end with Test.php?
Do all testcase classes extend PHPUnit_Framework_TestCase?
Do all testcase classnames end with 'Test'?
PHPUnit defaults to the suffix Test.php, which isn't obvious.
If your tests use another suffix (e.g. TestUser.php or /test/User.php, instead of UserTest.php), the test will be skipped.
This default can be overwritten using the --test-suffix flag on the CLI:
phpunit --test-suffix _test.php
or with the suffix attribute in the XML configuration:
<include>
<directory suffix="_test.php">src</directory>
</include>
Sources:
PHPUnit: The Command-Line Test Runner
PHPUnit: The XML Configuration File
This might depend a little bit on the version of Phpunit.
I could get it to work with two more older ones (3.7.22 and 3.7.38) but had a similar problem earlier. Here is my solution:
I first had the directory configured wrong:
<testsuites>
<testsuite name="Default">
<directory>/tests</directory>
</testsuite>
</testsuites>
As you can see in this wrong example, it's prefixed with a slash ("/"). Removing that slash results in the following XML excerpt that is working fine then:
<testsuites>
<testsuite name="Default">
<directory>tests</directory>
</testsuite>
</testsuites>
Ensure the directory is not prefixed with a slash and that it exists. The existence part is crucial, because the Phpunit testrunner will not display na error message if it does not exists. You will only see that no tests are executed.
No tests executed!
Taking what you have in your question as an example:
<directory>unit</directory>: It fails because the directory does not exists (you think it does, I know, but it fails if the directory does not exists, Phpunit is not lying to you).
<directory>unit/api/2</directory>: If it fails, it fails because the directory does not exists (you think it does, I know, but it fails if the directory does not exists, Phpunit is not lying to you).
<directory>unit/api/2/*</directory>: This will always fail because the directory does not exists. Most file-systems do not allow to use the "*" character in directory- and file-names.
<directory>unit/api/2/*Test.php</directory>: Same here, this is not a valid directory name, it fails because the directory does not exists.
<directory suffix="Test.php">unit/api/2</directory>: If it fails, it fails because the directory does not exists (you think it does, I know, but it fails if the directory does not exists, Phpunit is not lying to you). Additionally the suffix parameter with the value "Test.php" is superfluous because this is the default suffix. As it is superfluous, this is cruft and you should remove it from the XML file.
No software is without bugs and this naturally applies to Phpunit as well, but you should first of all consider that Phpunit is not lying to you in the first place.
I for myself had not problems with the two versions documented after I corrected the directory configuration. Your mileage may vary. This applies to the points 1, 2 and 5 specifically: From your question it looks like those directories do exist, but from the description you give and what is the Phpunit behaviour I can see, those directories do not exist.
Points 3 and 4 should be clear, they simply do not work because you put wildcards into the directory name which was meant to describe a concrete path not to hint that wildcard usage was intended / allowed. You can find this point outlined as well in a previous Q&A question: Attempting to run Phpunit with a configuration XML file results in exception.
The information in this answer is based on
PHPUnit 3.7.22 and 3.7.38 by Sebastian Bergmann.
PHP 5.4.36 by php.net

Categories