1. Including PHPUnit tests in SonarQube analysis

    In my previous article I explained how to set up SonarQube to analyze PHP source code. This article describes how to include the results of PHPUnit tests in this analysis.

    I assume you have PHPUnit installed or else you would not be able to run your PHPUnit tests. I prefer to install it globally so the phpunit command runs from every folder..

    The setup described here only includes the necessary configuration files and settings. Adjust them to the needs of you project.

    1. Folder structure
    2. PHPUnit configuration file
    3. Running tests
    4. Analyzing test results
    5. Example files
    6. Links

    Folder structure

    All tests are stored together with the rest of the project, but in a separate folder.

    This is the basic folder structure I use for PHP components, which is inspired by the default structure used by Apache Maven:

    my-project
    ├─ build
    └─ src
       ├─ main
       |  └─ php
       |     └─ kwebble
       |        └─ namespace
       |           └─ MyClass.php
       └─ test
          └─ php
             ├─ kwebble
             |  └─ namespace
             |     └─ MyClassTest.php
             ├─ bootstrap.php
             └─ phpunit.xml
    

    In this structure:

    • build is generated during testing and not stored in version control.
    • src contains all source code
    • main contains all source code used at runtime. This folder is also configured as the PSR-4 autoload folder for Composer.
    • test contains all source code used for tests, including support classes if necessary.
    • kwebble is the top namespace for my PHP classes.

    Test classes have the same namespaces as the classes they test, but as you can see they are stored in different folders.

    The name of a test class is equal to the class it tests plus the Test suffix.

    PHPUnit configuration file

    The PHPUnit configuration is stored in my-project/src/test/php/phpunit.xml, in the PHP test code folder. Here is an example configuration:

    <phpunit
       bootstrap="bootstrap.php"
       stderr="true"
    >
        <testsuites>
            <testsuite name="My project">
                <directory>.</directory>
            </testsuite>
        </testsuites>
        <logging>
            <log type="coverage-clover"
                 target="../../../build/tests-clover.xml"/>
            <log type="junit"
                 target="../../../build/tests-junit.xml"
                 logIncompleteSkipped="false"/>
        </logging>
    </phpunit>
    

    This configuration defines:

    • bootstrap.php, which contains code to set up the PHP environment.
    • a testsuite that uses the current folder . to search for tests.
    • the generated output in clover and junit format. Thes files are stored in the my-project/build folder of the project

    The code in bootstrap.php sets up the PHP environment so that the test can run:

    <?php
    $rootPath = realpath(__DIR__ . '/../../..');
    $vendorPath = $rootPath . '/vendor';
    $testClassPath = $rootPath . '/src/test/php/kwebble/namespace';
    
    $loader = require $vendorPath . '/autoload.php';
    $loader->addPsr4('kwebble\namespace\test\', $testClassPath);
    

    It includes the Composer autoloader so the tested classes can be found and also adds the classes with the tests.

    Running tests

    Together the configurations in these files should be able to run the tests. From the base folder of the project run PHPUnit with this command:

    phpunit -c src/test/php/phpunit.xml

    The results of the test run are stored in the my-project/build folder.

    Analyzing test results

    The SonarQube configuration to read the test results is set in sonar.properties:

    sonar.tests=src/test/php
    sonar.php.tests.reportPath=build/tests-junit.xml
    sonar.php.coverage.reportPath=build/tests-clover.xml
    sonar.coverage.exclusions=src/test/php/**/*.php
    

    It defines these properties:

    • sonar.tests the path to the tested code.
    • sonar.php.tests.reportPath the path to the file with test results.
    • sonar.php.coverage.reportPath the path to the file with test coverage data.
    • sonar.coverage.exclusions the excluded source code, so the tests themselves are excluded from the analysis.

    With this configuration run the SonarQube analysis by executing the sonar-runner command. After completion you can view the unit test related metrics and the Unit Tests Coverage widget of SonarQube:

    Example files

    On GitHub you can find a small component that uses the same files and configurations described in this article. You can use it as a base for your own projects or just to view a working example.