Separate Interactive Test Suites

October 2017
This post is over a year old. Some of this information may be out of date.

On a recent Full Stack Radio episode, Adam Wathan and Taylor Otwell were talking about testing Laravel applications. During the episode, they spoke about isolating interactive integration tests from your normal testing e.g. payment gateways, third-party integrations. One use case would be as contract tests for fakes (really test doubles in general) to mitigate “API drift”.

I’m currently working on an HTTP API that interacts with physical credit card payment terminals and proxies/transforms the responses. I have integration tests for my API controller responses and didn’t want to have to physically interact with the terminal every time, so I built a TerminalGatewayFake test double with hard-coded responses. After each gateway update, we run the "Interactive" test suite to ensure the fakes and real responses line up.

There are a few ways you can isolate these tests either through manual workflows, filters, test suites, and groups. I decided the best way for me was to create a separate test suites.

To avoid running the interactive test suite with the rest of my tests, manually or via a CI job, I had to explicitly include all the other suites using phpunit --test suite API, Feature, Unit. This felt a bit grim and I would rather exclude just that one suite. So I did some digging and found the defaultTestSuite configuration for PHPUnit. Now, I can easily run my desired test suites by just using PHPUnit. Then I can manually run phpunit --testsuite Interactive for my interactive contract tests whenever I feel the need to.

Here is an example phpunit.xml config that utilizes defaultTestSuit option:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         defaultTestSuite="Api,Feature,Unit"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>


        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>

        <testsuite name="Api">
            <directory suffix="Test.php">./tests/Api</directory>
        </testsuite>


        <testsuite name="Interactive">
            <directory suffix="Test.php">./tests/Interactive</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
    </php>
</phpunit>

Want more info?

Get the code from this post.