This is the second part of a series on creating a PHP package.
In the previous part, we initialized a project using the composer and wrote the code itself. In this part, we will integrate the PHPUnit into our project and write tests.
Code should be covered with tests. This will help to avoid bugs when modifying the code. When we connect the CI to the repository, tests will run automatically as pull requests are created.
1. Installing PHPUnit
Let's add PHPUnit to our project as a dev dependency. To do this, run in the console:
composer require --dev phpunit/phpunit
Note that we specified --dev
option. This means that we want to include itin as a dev dependency.
Dev dependencies only needed during development and not needed in production.
In production, we will install dependencies with --no-dev
option that prevents dev dependencies from being installed.
A new dependency will appear in the composer.json
file:
"require-dev": { "phpunit/phpunit": "^10.2" }
After executing the command, the composer will also create another composer.lock
file.
What are the differences between composer.json
and composer.lock
files?
When dependencies are installed, the current versions of libraries are written to the composer.lock
file.
When we runcomposer install
, we will download the versions of the packages that are specified by composer.lock
.
But composer update
will re-read composer.json
, install the latest versions of libraries and update the composer.lock
file to keep the latest versions.
Usually, composer update
is executed during development and composer install
is executed during deployment.
This allows keeping the same versions of dependencies across all servers and guarantees that the code deployed across the cluster will work the same.
Our tests will be located in the tests
folder. We need to tell the composer to load these files, but only in the development environment. To do this after require-dev
add another section:
"autoload-dev": { "psr-4": { "Demyanovs\\PHPHighlight\\Tests\\": "tests/" } }
2. Writing unit tests
Now let's write the tests themselves.
tests/HighlighterTest.php
We can run each test from the console:
./vendor/bin/phpunit tests/HighlighterTest.php
To run all tests at once, we need to create a configuration file.
3. Configuring PHPUnit with XML
To simplify the testing process and run all tests at once, let's create the phpunit.xml.dist
configuration file at the root of the project.
What are the differences between phpunit.xml.dist
and phpunit.xml
?
Usually phpunit.xml.dist
contains configurations, default values, and secrets that can't be shared or committed to the repository.
In production, we can override these values with the phpunit.xml
file.
phpunit.xml
. should be ignored by git and should not be committed to your repository. It may contain confidential information, such as database access.
It is similar to how Symfony overwrites the environment variable values from the .env
file using the .env.local
file.
I will give a ready-made version of the file, but it can contain many settings.
See the documentation for details.
<?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.2/phpunit.xsd" backupGlobals="false" colors="true" processIsolation="false" stopOnFailure="false" bootstrap="vendor/autoload.php" cacheDirectory=".phpunit.cache" backupStaticProperties="false" > <coverage> <report> <text outputFile="php://stdout" showOnlySummary="true"/> </report> </coverage> <php> <ini name="memory_limit" value="-1"/> <ini name="display_errors" value="1"/> <ini name="error_reporting" value="-1"/> </php> <testsuites> <testsuite name="general"> <directory>tests</directory> </testsuite> </testsuites> <logging/> <source> <include> <directory suffix=".php">./src</directory> </include> </source> </phpunit>
Now to run all the tests at once just execute the command
./vendor/bin/phpunit
Moreover, let's add this command to the composer into scripts section:
"scripts": { "test": "./vendor/bin/phpunit" }
Now we can run this script with the command:
composer test
It's convenient to group different commands in the composer. We will add more commands later.
4. Code coverage
PHPUnit can also check how many tests are covered in your code. Programs with high test coverage have a lower chance of containing bugs than programs with low coverage.
The necessary settings are already in the XML file, but you also need to install Xdebug for PHP and enable xdebug.mode = coverage
directive in php.ini.
Now brief information about code coverage is displayed in the console.
The report can also be generated in HTML form with a detailed description of classes and methods. To generate such report run the command
./vendor/bin/phpunit --coverage-html=report-html
where report-html
is the name of the folder where details will be saved.
What's next?
This time we covered our code with tests. Next, we will integrate automatic code style validation.