laravelのphpunit.xmlで.env対応

ちょっとしたトリックを思いついたので、備忘録。

Laravel(lumen)でプロジェクトを作成すると、PHPUnitの設定ファイル(phpunit.xml)が生成されます。

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

        <testsuite name="Unit Tests">
            <directory suffix="Test.php">./tests/Unit</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>
```

テスト用の環境変数設定は`<php>`要素の`<env>`要素に記述するわけですが、laravel(lumen)では環境変数の切り替えは`DotEnv`で行っているわけですから、これも`.env`ファイルに記述したいと思いませんか？

では、こんなファイルを作成しましょう。

```php:tests/bootstrap.php
<?php
require_once __DIR__.'/../vendor/autoload.php';

try {
    (new Dotenv\Dotenv(__DIR__))->load();
} catch (Dotenv\Exception\InvalidPathException $e) {
    echo ".env for test is missing.";
    exit(1);
}

require_once 'bootstrap/app.php';
```

`tests/.env`ファイルを読み込んで、本来のbootstrapファイルを呼び出すだけのラッパーです。

```:tests/.env
APP_ENV=testing

CACHE_DRIVER=array
SESSION_DRIVER=array
QUEUE_DRIVER=sync
```

最後には`phpunit.xml`を変更します。
`bootstrap=`を先程の`tests/bootstrap.php`に置き換えて、`<php>`要素をバッサリ削除すればOKです。

```xml:phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="tests/bootstrap.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Feature Tests">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>

        <testsuite name="Unit Tests">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
</phpunit>
```

これでphpunitを実行すると、以下のようなシーケンスで処理が流れます。
`phpunit(phpunit.xml)` → `tests/bootstrap.php` （ここで`tests/.env`が読み込まれる） → `bootstrap/app.php`


こういう仕組みを導入しておくと、他のテストドライバからPHPUnitを実行する場合も同じ仕組みが使えます。
例えばPhingのPHPUnitタスクからテスト実行する場合は、`bootstrap`に`tests/bootstrap.php`を指定すればOKです。

```xml:build.xml
    <phpunit codecoverage="true" bootstrap="tests/bootstrap.php">
        <batchtest>
            <fileset dir=".">
                <include name="tests/**/*Test.php" />
            </fileset>
        </batchtest>
    </phpunit>
```