Setting up PHPQA for Symfony Project

First, Install PHPQA

1
composer require edmondscommerce/phpqa --dev

You will get options to run recipes, along the lines of:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Writing lock file
Generating autoload files
Symfony operations: 2 recipes (879dfdbdec43c895e4cad33b1dfef4e5)
  -  WARNING  squizlabs/php_codesniffer (>=3.0): From github.com/symfony/recipes-contrib:master
    The recipe for this package comes from the "contrib" repository, which is open to community contributions.
    Review the recipe at https://github.com/symfony/recipes-contrib/tree/master/squizlabs/php_codesniffer/3.0

    Do you want to execute this recipe?
    [y] Yes
    [n] No
    [a] Yes for all packages, only for the current installation session
    [p] Yes permanently, never ask again for this project
    (defaults to n): 

You should say no to the codesniffer recipe (default, just hit return)

You will also get something about PHPUnit

1
2
3
4
5
6
 Adding phpunit/phpunit as a dependency is discouraged in favor of Symfony's PHPUnit Bridge. 


  * Instead:
    1. Remove it now: composer remove --dev phpunit/phpunit
    2. Use Symfony's bridge: composer require --dev phpunit

Again you should ignore this, it is all handled by PHPQA

Remove Cruft That is Added After installing PHPQA

1
rm .php_cs.dist

PHPUnit Configs

First of all, we need to set up some PHPQA configuration for PHPUnit

We will copy the generated XML file first of all

1
2
mkdir qaConfig
mv phpunit.xml.dist qaConfig/phpunit.xml

Then we need to fix the paths, by adding ../

For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="UTF-8"?>

<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->

<!-- here, twice
- once for xsd
- once for bootstrap
 //-->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="../vendor/phpunit/phpunit/phpunit.xsd"
         backupGlobals="false"
         colors="true"
         bootstrap="../config/bootstrap.php"
>
    <php>
        <ini name="error_reporting" value="-1" />
        <server name="APP_ENV" value="test" force="true" />
        <server name="SHELL_VERBOSITY" value="-1" />
    </php>

    <testsuites>
        <testsuite name="Project Test Suite">
<!-- here //-->
            <directory>../tests</directory>
        </testsuite>
    </testsuites>

    <filter>
        <whitelist>
<!-- here //-->
            <directory>../src</directory>
        </whitelist>
    </filter>
</phpunit>

We also need to add PHPQA configurations:

Basic Configs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<phpunit
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="../vendor/phpunit/phpunit/phpunit.xsd"
        cacheTokens="false"
        colors="true"
        verbose="true"
        forceCoversAnnotation="false"
        printerClass="\PHPUnit\Util\TestDox\CliTestDoxPrinter"
        timeoutForMediumTests="30"
        timeoutForSmallTests="3"
        timeoutForLargeTests="300"
        failOnRisky="true"
        failOnWarning="true"
        defaultTestSuite="Project Test Suite"
        beStrictAboutTodoAnnotatedTests="true"
        cacheResult="true"
        cacheResultFile="../var/qa/.phpunit.result.cache"
        executionOrder="depends,random"
        bootstrap="../tests/bootstrap.php"
        convertDeprecationsToExceptions="false"
>

Logging

1
2
3
4
5
6
    <logging>
        <log type="coverage-html" target="../var/qa/phpunit_coverage"/>
        <log type="coverage-text" target="php://stdout"/>
        <log type="coverage-xml" target="../var/qa/phpunit_logs/coverage-xml"/>
        <log type="junit" target="../var/qa/phpunit_logs/phpunit.junit.xml"/>
    </logging>

Kernel Class

As we are not using the App namespace, we need to change the Kernel Class

1
2
3
<php>
        <env name="KERNEL_CLASS" value="\ProjectName\Kernel"/>
    </php>

So the final phpunit.xml file might look something like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version="1.0" encoding="UTF-8"?>

<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
<phpunit
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="../vendor/phpunit/phpunit/phpunit.xsd"
        cacheTokens="false"
        colors="true"
        verbose="true"
        forceCoversAnnotation="false"
        printerClass="\PHPUnit\Util\TestDox\CliTestDoxPrinter"
        timeoutForMediumTests="30"
        timeoutForSmallTests="3"
        timeoutForLargeTests="300"
        failOnRisky="true"
        failOnWarning="true"
        defaultTestSuite="Project Test Suite"
        beStrictAboutTodoAnnotatedTests="true"
        cacheResult="true"
        cacheResultFile="../var/qa/.phpunit.result.cache"
        executionOrder="depends,random"
        bootstrap="../tests/bootstrap.php"
        convertDeprecationsToExceptions="false"
>
    <php>
        <ini name="error_reporting" value="-1" />
        <server name="APP_ENV" value="test" force="true" />
        <server name="SHELL_VERBOSITY" value="-1" />
        <env name="KERNEL_CLASS" value="\ProjectName\Kernel"/>
    </php>
    <logging>
        <log type="coverage-html" target="../var/qa/phpunit_coverage"/>
        <log type="coverage-text" target="php://stdout"/>
        <log type="coverage-xml" target="../var/qa/phpunit_logs/coverage-xml"/>
        <log type="junit" target="../var/qa/phpunit_logs/phpunit.junit.xml"/>
    </logging>
    <testsuites>
        <testsuite name="Project Test Suite">
            <directory>../tests</directory>
        </testsuite>
    </testsuites>

    <filter>
        <whitelist>
            <directory>../src</directory>
        </whitelist>
    </filter>
</phpunit>

Tests Bootstrap File

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#tests/bootstrap.php
<?php 

declare(strict_types=1);

# bring in standard symfony bootstrap
require __DIR__ . '/../config/bootstrap.php';

# truncate test logs
file_put_contents(__DIR__ . '/../var/log/test.log', 'Test started at ' . date('H:i:s') . "\n");
1
ln -s qaConfig/phpunit.xml

This allows us to run ./bin/phpunit from the project root

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
15:29 $ ./bin/phpunit
PHPUnit 8.2.5 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.2.12 with Xdebug 2.6.1
Configuration: /var/www/vhosts/project-name/qaConfig/phpunit.xml
Random seed:   1574263804


Time: 39 ms, Memory: 4.00 MB

No tests executed!

Generating code coverage report in HTML format ... done [20 ms]


Code Coverage Report:   
  2019-11-20 15:30:03   

 Summary:               
  Classes:  0.00% (0/1) 
  Methods:  0.00% (0/4) 
  Lines:    0.00% (0/27)

Configure Infection

We need to tell infection to use our configs, so we need to set up a config file for it in our qaConfig folder

qaConfig/infection.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  "timeout": 10,
  "source": {
    "directories": [
      "src"
    ],
    "excludes": [
      "Kernel.php"
    ]
  },
  "note:": [
    "yes paths are handled inconsistently",
    "the logs paths are from the project root",
    "the tmp path is from the config file location"
  ],
  "logs": {
    "text": "var/qa/infection/log.txt",
    "summary": "var/qa/infection/summary-log.txt",
    "debug": "var/qa/infection/debug-log.txt"
  },
  "phpUnit": {
    "configDir": "../qaConfig"
  },
  "tmpDir": "../var/qa/infection/tmp"
}

Fixing Composer Require Issues

PHPQA Checks for explicit requires of dependencies that are used in project code

As a minimum, we need to add the following:

1
composer require symfony/http-kernel  symfony/dependency-injection  symfony/config  symfony/routing 

Create a README File

We need to have a project README.md file

Create one and document the project in there