[PHP] ゼロから始める PHPUnit + CI (1. PHPUnit を導入しよう）

# 目次

1. PHPUnit を導入しよう（本記事）
2. [CI環境を導入しよう](https://qiita.com/PruneMazui/items/640ca7b7f9a88fd1793c)
3. [コードカバレッジを計測しよう](https://qiita.com/PruneMazui/items/839b437f5e740c46ad09)


# はじめに

プロジェクトに入った時には既にUnitテストの環境があったり、プロジェクトのリーダー的な人が導入進めたりしていて、 ユニットテスト（とCI）はやったことあるけど環境導入までやったことある人って結構限定されるんじゃないかなーと思った。（おそらく）敷居高く感じてる人多いと思うんだけど結構簡単にできるよーってことを示せればと。

これで社内にテストコード書く文化を・・・

### 対象となる人

* PHPer
* ユニットテスト自体はやったことあるけど、環境構築までやったことない人
* 自分のGitHubリポジトリにバッチを貼りたい人

※ ユニットテスト、CIってなんぞやってことには触れません
※ テスト技法については触れません
※ とにかく**導入の敷居を下げる**ことを目的として書いてます。

### 環境

* PHP7.1
* PHPUnit6.4.3
* Composer
* [GitHub](https://github.com/)
* [TravisCI](https://travis-ci.org/)（CIサービス）
* [Coveralls](https://coveralls.io/)（カバレッジレポートサービス）

# サンプルプログラム

**リポジトリはこちら → https://github.com/PruneMazui/phpunit-training**
各リポジトリのコミットが記事の内容に紐づくようにしているので、GitHub側を見ると具体的な変更点が分かって良いと思う。

テスト導入対象のプログラムは簡略化の為、非常に単純なものにした。
初期コミットは以下のような感じ。

**[COMMIT: initial commit サンプルプログラム](https://github.com/PruneMazui/phpunit-training/commit/63c8e005a4392b8ee41874505caa153027a41e7c)**

# 1. PHPUnit を導入しよう

## 1.1 PHPUnit をインストールしよう

**[COMMIT: 1.1 PHPUnit をインストールしよう](https://github.com/PruneMazui/phpunit-training/commit/0adc3702b15423e8604df102e73cacc693611d7f)**

Composer 使って依存関係に PHPUnit を追加（devのみ）。
Composerって何って人は[こちら](https://www.google.co.jp/search?q=Composer)。

```bash
composer require --dev phpunit/phpunit
```
しばらくするとインストールが完了する。
ちゃんとインストールされたかチェック。

```
$ vendor/bin/phpunit --version
PHPUnit 6.4.3 by Sebastian Bergmann and contributors.
```

使っているPHPのバージョンによっては別バージョンのPHPユニットがインストールされる。
（本記事ではこのバージョンで統一）


## 1.2 テストケースを作ろう

**[COMMIT: 1.2 テストケースを作ろう ](https://github.com/PruneMazui/phpunit-training/commit/8cb6fe7efd3ab5de769517991a0941c1434e6532)**

テストケースの書き方は今回は触れないのでこちらを参照 → [PHPUnit 用のテストの書き方](https://phpunit.de/manual/current/ja/writing-tests-for-phpunit.html)

今回は `tests/src/HelloWorldTest.php` に非常に簡単なテストケースを一つ作成した。
後からユニットテストの環境を導入する場合、**この段階でテストの網羅性を気にしていたら中々先に進まず心が折れちゃう場合があるので、まずは`$this->assertEquals(2, 1+1)`レベルで作ってしまう**のが個人的にオススメ。

```php:tests/src/HelloWorldTest.php
<?php
namespace PruneMazui\PhpunitTraining\Tests;

use PHPUnit\Framework\TestCase;
use PruneMazui\PhpunitTraining\HelloWorld;

class HelloWorldTest extends TestCase
{
    public function testToString()
    {
        assertEquals('Hello World!', (string)(new HelloWorld()));
    }
}
```

テストケースを作ったら早速 PHPUnit を実行！

```
$ vendor/bin/phpunit tests
PHPUnit 6.4.3 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 77 ms, Memory: 4.00MB

OK (1 test, 1 assertion)
```

※`tests` ディレクトリ以下（第一引数）の `～～Test.php` というファイル名（PHPUnitデフォルト値）にある、`public function test～～()` な（PHPUnitデフォルト値）メソッドを実行する。


## 1.3 PHPUnit の設定ファイルを作ろう

**[COMMIT: PHPUnit の設定ファイルを作ろう](https://github.com/PruneMazui/phpunit-training/commit/7bdcffee2ed1075af34d5138707df602353a76b5)**

実は前節まででPHPUnitを実行する環境はできているのだが、ユニットテストを置く場所なんてプロジェクト毎に大抵決まっているし実行オプション等も共有したいので、設定ファイルを作ってしまう。

```xml:phpunit.xml.dist
<?xml version="1.0"?>
<phpunit>
    <testsuite name="Application Test">
        <directory>./tests/</directory>
    </testsuite>
</phpunit>
```

PHPUnit実行時に自動的に上記のXMLが読み込まれ、その中にテスト対象のディレクトリが指定されているので捗る。かなり割愛して書いているがXMLの詳細はこちら → [付録C XML 設定ファイル](https://phpunit.de/manual/current/ja/appendixes.configuration.html)

```
$ vendor/bin/phpunit
PHPUnit 6.4.3 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 77 ms, Memory: 4.00MB

OK (1 test, 1 assertion)
```

PHPUnit は `phpunit.xml` → `phpunit.xml.dist` の優先度で自動的にXMLファイルを読み込む。
サンプルプログラムでは `phpunit.xml` は個人用として `.gitignore` に追加した。


## 1.4 初期化スクリプトを作ろう

**[COMMIT: 初期化スクリプトを作ろう](https://github.com/PruneMazui/phpunit-training/commit/327c99810785d39687372089a8233a96a0e4fe73)**

PHPUnit がテストケース実行前に走らせるスクリプトを指定できる。使い方はご自由に。

PHPUnit には `$this->assert～～()` を `assert～～()` と書ける便利なグローバル関数群が用意されているのだが、デフォルトでは読み込んでいない。サンプルプログラムではこれを読み込む初期化スクリプトを組み込んでいる。

**初期化スクリプト**

```php:tests/bootstrap.php
<?php
$reflection = new \ReflectionClass(\PHPUnit\Framework\Assert::class); // PHPUnit 5系だと微妙に場所が違うので注意
require_once dirname($reflection->getFileName()) . '/Assert/Functions.php';
```

**初期化スクリプト読み込みをXMLに追記**

```xml:phpunit.xml.dist
<?xml version="1.0"?>
<phpunit
    bootstrap=".tests/bootstrap.php"
>
    <testsuite name="Application Test">
        <directory>./tests/src/</directory>
    </testsuite>
</phpunit>
```

**テストコードでグローバル関数使用**

```diff:tests/src/HelloWorldTest.php
diff --git a/tests/src/HelloWorldTest.php b/tests/src/HelloWorldTest.php
index 4b9b216..753a5cb 100644
--- a/tests/src/HelloWorldTest.php
+++ b/tests/src/HelloWorldTest.php
@@ -8,6 +8,6 @@ class HelloWorldTest extends TestCase
 {
     public function testToString()
     {
-        $this->assertEquals('Hello World!', (string)(new HelloWorld()));
+        assertEquals('Hello World!', (string)(new HelloWorld()));
     }
 }
```

実行結果は以下の通り。

```
$ vendor/bin/phpunit
PHPUnit 6.4.3 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 94 ms, Memory: 4.00MB

OK (1 test, 1 assertion)
```

# あとがき

これでPHPUnitを使ってのユニットテスト実行環境は整ったはず。
次回は CI環境 を作っていきます。

NEXT. [CI環境を導入しよう](https://qiita.com/PruneMazui/items/640ca7b7f9a88fd1793c)