Ben
September 3, 2020
In my previous post (Using Laradock with JetBrains IDEA) I spoke about setting up Laradock and IntelliJ IDEA to use PHP in a containerised environment and how this would help with ensuring a clean environment and how it allows you to easily change PHP version and other extensions.
In this post I will quickly go over how to configure IntelliJ IDEA to use the Laradock containers for running unit tests, and why I recommend this approach.
If you did not read my previous post, or do not have Laradock setup yet, I recommend you go back and read it and setup Laradock for your environment as I will be referring to it in this post.
To configure IntelliJ IDEA to use Laradock for the tests we need to configure the following items:
If all the above is configured correctly then you are ready.
Once everything is configured and you have a project you want to create a test for, then in IntelliJ IDEA it is as simple as using the 'Create Test' shortcut, which on my configuration is 'Ctrl + Shift + T', when in the method, class or file you want to test. This will help you create a test for the item you want to test, and can help configure the test framework you are using.
Once you have the test you can simply click the small green arrow, or right click anywhere in the file and click run. Then IntelliJ IDEA will execute the test using the docker environment configured, and if debug is configured correctly then you can also immediately debug the tests as well.
If you are thinking that this is too simple for a blog, then you are correct, then above is the easy case.
If you have a more complex PHP project that has dependencies that you are also working on, and want to run the tests that use those dependencies then you will start to get these strange errors, saying PHP cannot find files that you can clearly see exist.
PHP Warning: require(/opt/project/vendor/composer/../intergral/coms-core-php-library/src/helpers.php): failed to open stream: No such file or directory in /opt/project/vendor/composer/autoload_real.php on line 66
PHP Stack trace:
PHP 1. {main}() /opt/project/vendor/phpunit/phpunit/phpunit:0
PHP 2. require() /opt/project/vendor/phpunit/phpunit/phpunit:59
PHP 3. ComposerAutoloaderInit529a7fbcfe0fdb131521dbb30af51cca::getLoader() /opt/project/vendor/autoload.php:7
PHP 4. composerRequire529a7fbcfe0fdb131521dbb30af51cca() /opt/project/vendor/composer/autoload_real.php:56
PHP Fatal error: require(): Failed opening required '/opt/project/vendor/composer/../intergral/coms-core-php-library/src/helpers.php' (include_path='.:/usr/local/lib/php') in /opt/project/vendor/composer/autoload_real.php on line 66
PHP Stack trace:
PHP 1. {main}() /opt/project/vendor/phpunit/phpunit/phpunit:0
PHP 2. require() /opt/project/vendor/phpunit/phpunit/phpunit:59
PHP 3. ComposerAutoloaderInit529a7fbcfe0fdb131521dbb30af51cca::getLoader() /opt/project/vendor/autoload.php:7
PHP 4. composerRequire529a7fbcfe0fdb131521dbb30af51cca() /opt/project/vendor/composer/autoload_real.php:56
These are caused by the way IntelliJ IDEA mounts the folders into the docker container being used for the tests. There are a few ways to resolve these issues, and they all involve configuring the docker volumes used by the docker container.
If you just want a quick fix then the easiest way is to quickly add the volume needed to the interpreter. This can be done by opening the interpreter settings 'Languages & Frameworks -> PHP' then opening the 'Docker container' settings for the interpreter, then under 'Volume bindings' add the volume required.
The correct path for the volume can sometimes seem a bit strange, but what we are trying to do is replicate the same relative path to the dependency in the container as on your development machine. This is much easier if both the project you are testing, and the dependency are in the same parent directory (as mine are above). Both of my projects are inside the 'coms' directory on my machine (Host path), so inside the container I put them in the same relative locations (Container path).
If everything is setup correctly after this, you should then see that the error you got before has gone away!
The other solutions to this problem can make the problem a bit more complex (depending on your use case).
When defining the repository location for the local dependency in the composer.json file, the default behavior is to use a symbolic link to link the vendor location to the real source. This is what causes the docker containers to fail, as the symbolic link target is not inside the docker container, unless we add the volume mount. Fortunately compose comes with an option to not use a symbolic link, this will then copy the code into the vendor directory meaning docker will mount the directly correctly. This will however mean that any changes in the dependency will not be seen until a 'composer update' is run, slowing down the development.
If you favour this approach then you should be aware of this issue: https://github.com/composer/composer/issues/5048
Another option is to use a docker-compose file that defines the mounts that should be used by the interpreter. Then use the 'Docker compose' option when configuring the PHP interpreter. This will allow the different mounts that are needed to be defined in the code, so they can be shared or simply remembered. This approach can also have some issues, if for example you do not have a simple directory structure to the dependencies then sharing this can be complicated.
Although if you are working in a team this approach can mean that you can define the interpreter in a way that all team members can use it.
I have found over the years, that if you cannot very easily run and debug the tests in the environment you are working in, it makes it much slower to produce quality. I have become accustomed to being able to execute a test directly in IntelliJ IDEA and when I started working on some PHP projects I needed to get this ability back. Although I will admit that the setup required for PHP is much more that say Node.Js, Python or even Java. I found that once it was all setup with Laradock and configured in IntelliJ IDEA, it all behaved the same as the other languages. Allowing me and the team to push forward with our work.
Experienced developer in various languages, currently a product owner of nerd.vision leading the back end architecture.