Phpstorm code coverage with docker container.

How do you do code coverage with phpstorm?

I've already setup my project to be able to run, test, and debug (xdebug) with phpstorm tools.
But i can't seem to run code coverage with phpstorm.

It runs the following command to container when i do 'Run TestFileName(PHPUnit) with coverage':
[docker-compose://[/path/to/project_name/docker-compose.yml]:php-dev/]:php -dxdebug.remote_port=19000 -dxdebug.coverage_enable=1 vendor/phpunit/phpunit/phpunit --coverage-clover /opt/phpstorm-coverage/project_name@TestFileName.xml --configuration /var/project_name/phpunit.xml Tests\Unit\TestFileName /var/project_name/tests/Unit/TestFileName.php --teamcity --cache-result-file=/var/project_name/.phpunit.result.cache

When the command line finish executes successfully, it generates a coverage file, that should be read by phpstorm.
But it seems like, phpstorm can't access the coverage file

Resulting in 0% coverage in phpstorm, but the coverage files is actually created in the php container in /opt/phpstorm-coverage/project_name@TestFileName.xml that is passed in the coverage-clover options.

Is there any way to change the location for phpstorm to read coverage files?

Thank you.


As mentioned in the support ticket, logs could help us to find out what is really happening, so please collect these (it would be better if you could share these via the existing ticket).

Also, I am wondering, what version of Docker-compose are you using?



Solved, miss config setting in phpunit file for coverage.

The phpstorm coverage works now!


Thank you.


How did you solve ? In phpunit.xml ? Could you post an example. I'm trying with:

<log type="coverage-clover" target="/tmp/coverage.xml"/>

but it seems ignored


Januar Steven Could you kindly share how you solved it? Thanks


Configuration in phpunit.xml should not matter here because when you invoke Run | Run 'MyTest' with Coverage, PhpStorm passes --coverage-clover /opt/phpstorm-coverage/phpunit_docker@MyTest.xml that overrides it.

Do you see this argument being appended to the command?


This one is a bit old, but I landed here and was annoyed that there was no answer, so here's how I fixed it:

I had a mapping in my docker-compose.yml

version: '3.7'

- ...
- var/coverage:/opt/phpstorm-coverage

And as it happens, the mapped directory in my host was owned by root.

So, on the host, I changed the owner to my user and gave it 777 permissions.

Problem solved.


Eugene Morozov Yes, the --coverge-clover argument is being added correctly.

I've done some more testing. Here are my findings:

It seems like the coverage file is not being generated in /opt/phpstorm-coverage. I've tried mapping the directory, as Herberto suggests, to a "coverage" sub-directory in the projects root. If the coverage file is being generated, I'll be able to see it in this directory.

version: '3.7'

- ./coverage:/opt/phpstorm-coverage

But after running tests with coverage using PHPStorm, the directory remains empty.

I suspected that it may have something to do with the fact that my interpreter is set to create a new container on every run (i.e. use docker-compose run). So I copied PHPStorm's "Test with coverage" command, ran bash in the container, pasted the command and executed it. After that, I checked the /opt/phpstorm-coverage directory.

[host]$ docker-compose run test /bin/bash
[container]$ php /app/vendor/phpunit/phpunit/phpunit -dzend_extension=...
[container]$ ls /opt/phpstorm-coverage

And sure enough, the generated coverage XML file was there!

If I disconnect from the container, the coverage file will be lost. This is to be expected. However, I'm not sure why it's not being generated in the first place when the tests are run via PHPStorm. Perhaps the container is stopping before the file has a chance to be generated?

To clarify: I cannot set my interpreter to connect to an existing container (using docker-compose exec) since my container is not a web-server. It's just a pre-configured PHP environment, so it just runs and terminates immediately.


So, here's a screencast:

The image I am using also doesn't have a daemon running in the foreground, so it terminates as soon as code execution stops. As you can see, PhpStorm manages to pull the coverage XML from the container before it dies.

We need a project that would reproduce the issue. Or, I can share mine for you to play around, but I think the former is preferable.


I found a clue. The coverage works on one project, but didn't on any others. They have the identical settings, but they're isolated and complete different projects. They use different containers, networks, etc.

But when I run PHPUnit tests with coverage where it doesn't work, I have the same error: Directory "/opt/phpstorm-coverage" could not be created

I checked that directory and found that it's not empty, it has results, but from the other project that doesn't have such problem… 

I'm assuming that PHPStorm somehow re-use containers or storage and this leads that its mount correctly, but in different container, that leads to permission issues.


Eugene Morozov I've created a proof of concept project based on your video:

The test runs OK but no coverage is shown on the IDE (IntelliJ IDEA 2021.3.1, Ultimate Edition), probably due to coverage mapped directory being empty. The php-cli container is run and removed everytime the tests are performed.

Can anyone please link the ticket that was mentioned at the beginning, so I can provide logs?



As far as I could concern, that was a support ticket that is not available to the public (unlike the YouTrack report), so I would suggest submitting your own support ticket or YouTrack bug report:

1. docker-compose down 

2. create in your project a directory '.coverage'  (maybe add to gitignore)

mkdir ./.coverage

3. add under "volumes" the following line:

- ./.coverage:/opt/phpstorm-coverage/


docker-compose up -d

FWIW, it turns out that my problem was using intellij idea via snap. After installing it via jetbrains-toolbox, the issue was fixed and php coverage was reported successfully.

Hope this helps,




I think things changed since the last comment. I made it work like this:

  1. In Settings > PHP > CLI Interpreter > …. > CLI Interpreters > + add a remote PHP Intepreter of type Docker compose
  2. In this new PHP interpreter > Lifecycle > Select Connect to existing container ('docker-compose exec'):
  3. Make sure this interepreter is selected when running the tests with coverage:

    Edit Run Configuration:
  4. the coverage will open automatically when using Run with coverage.

Please sign in to leave a comment.