PHPUnitを使えるようにする。

- 環境
    - macOS Mojave バージョン10.14.2
    - Composer version 1.8.0

# 前提
- [Composer](https://getcomposer.org/)がインストールされていること
    - ComposerはPHP向けのツールで、ライブラリなどの依存関係を管理してくれます。

# プロジェクトの情報や依存関係を記述するcomposer.jsonを作る

```bash
$ composer init

                                            
  Welcome to the Composer config generator  
                                            


This command will guide you through creating your composer.json config.

Package name (<vendor>/<name>) [hoge/fuga]: 好きに/書く
Description []: 説明文を書く
Author [ponsuke <ponsukeのメールアドレス>, n to skip]: n
Minimum Stability []: dev
Package Type (e.g. library, project, metapackage, composer-plugin) []: project
License []: お好きに

Define your dependencies.

# 必要なパッケージを定義します。
Would you like to define your dependencies (require) interactively [yes]? yes
Search for a package: php
Enter the version constraint to require (or leave blank to use the latest version): 7.3.1
Search for a package: 

# 開発やテストに必要なパッケージを定義します。
Would you like to define your dev dependencies (require-dev) interactively [yes]? yes
Search for a package: phpunit/phpunit
Enter the version constraint to require (or leave blank to use the latest version): 7.5.2
Search for a package: 

# 以下の内容が、composer.jsonとして出力されます。
{
    "name": "tryphp/qiita",
    "description": "Sample For Qiita post.",
    "type": "project",
    "require": {
        "php": "7.3.1"
    },
    "require-dev": {
        "phpunit/phpunit": "7.5.2"
    },
    "license": "MIT",
    "minimum-stability": "dev"
}

Do you confirm generation [yes]? yes
```

# 依存するライブラリをComposerでインストールする

```bash
$ composer install
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 28 installs, 0 updates, 0 removals
  - Installing sebastian/version (2.0.1): Downloading (100%)         
  - Installing sebastian/resource-operations (dev-master 4d7a795): Cloning 4d7a795d35 from cache
  - Installing sebastian/object-reflector (dev-master 7707193): Cloning 7707193304 from cache
  - Installing sebastian/recursion-context (dev-master dbe1869): Cloning dbe1869c13 from cache
  - Installing sebastian/object-enumerator (dev-master e6be0a5): Cloning e6be0a5481 from cache
  - Installing sebastian/global-state (2.0.0): Downloading (100%)         
  - Installing sebastian/exporter (dev-master c8c4f19): Cloning c8c4f196e3 from cache
  - Installing sebastian/environment (dev-master 585fbcd): Cloning 585fbcdeff from cache
  - Installing sebastian/diff (dev-master 6906fbe): Cloning 6906fbe334 from cache
  - Installing sebastian/comparator (dev-master 33825cd): Cloning 33825cd25f from cache
  - Installing phpunit/php-timer (dev-master 9ef9968): Cloning 9ef9968ba2 from cache
  - Installing phpunit/php-text-template (1.2.1): Downloading (100%)         
  - Installing phpunit/php-file-iterator (dev-master 2da97ea): Cloning 2da97ea973 from cache
  - Installing theseer/tokenizer (1.1.0): Downloading (100%)         
  - Installing sebastian/code-unit-reverse-lookup (dev-master 22f5f5f): Cloning 22f5f5ff89 from cache
  - Installing phpunit/php-token-stream (dev-master 6df086c): Cloning 6df086c042 from cache
  - Installing phpunit/php-code-coverage (dev-master afe4b8a): Cloning afe4b8aa75 from cache
  - Installing doctrine/instantiator (dev-master 8c8c1af): Cloning 8c8c1afee0 from cache
  - Installing symfony/polyfill-ctype (v1.10.0): Downloading (100%)         
  - Installing webmozart/assert (1.4.0): Downloading (100%)         
  - Installing phpdocumentor/reflection-common (1.0.1): Downloading (100%)         
  - Installing phpdocumentor/type-resolver (0.4.0): Downloading (100%)         
  - Installing phpdocumentor/reflection-docblock (4.3.0): Downloading (100%)         
  - Installing phpspec/prophecy (dev-master 7e27218): Cloning 7e27218052 from cache
  - Installing phar-io/version (2.0.1): Downloading (100%)         
  - Installing phar-io/manifest (dev-master 7761fca): Cloning 7761fcacf0 from cache
  - Installing myclabs/deep-copy (1.x-dev 3e01bda): Cloning 3e01bdad3e from cache
  - Installing phpunit/phpunit (7.5.2): Downloading (100%)         
sebastian/global-state suggests installing ext-uopz (*)
phpunit/php-code-coverage suggests installing ext-xdebug (^2.6.1)
phpunit/phpunit suggests installing phpunit/php-invoker (^2.0)
phpunit/phpunit suggests installing ext-xdebug (*)
Writing lock file
Generating autoload files

$ ls -l
total 136
-rw-r--r--@  1 mana  staff    344  1 20 19:11 composer.json
# composer.lockは、ダウンロードしたパッケージとそのバージョンが書き込まれていて、プロジェクトをそれらの特定のバージョンに固定します。
-rw-r--r--@  1 mana  staff  52362  1 20 16:37 composer.lock
# vendorディレクトリが作成されて、その配下にライブラリがインストールされます。
drwxr-xr-x@ 15 mana  staff    480  1 20 19:03 vendor
```

# PHPUnitのパスを通す
```bash
# .bash_profileにphpunitのパスを書いて
$ echo 'export PATH="/Path/To/vendor/bin/phpunit:$PATH"' >> ~/.bash_profile
# 反映して
$ source ~/.bash_profile
# 確認します。
$ phpunit --version
PHPUnit 7.5.2 by Sebastian Bergmann and contributors.
```


# ソースを格納する `src` と `tests` を作る

```bash
# srcディレクトリは、ソースファイルを格納するディレクトリ
$ mkdir src

# testsは、テストコードのファイルを格納するディレクトリ
$ mkdir tests

$ ls -l
total 136
-rw-r--r--@  1 mana  staff    344  1 20 19:11 composer.json
-rw-r--r--@  1 mana  staff  52362  1 20 16:37 composer.lock
drwxr-xr-x@  2 mana  staff     64  2  4 22:09 src
drwxr-xr-x@  2 mana  staff     64  2  4 22:10 tests
drwxr-xr-x@ 15 mana  staff    480  1 20 19:03 vendor
```

## `scr` ディレクトリをマッピングするために `autoload` をcomposer.json定義する
名前空間からパスへの相対的なマッピングを定義します。
名前空間のプリフィックス"App\\"で`src/` を定義すると、`App\Hoge\Fuga`クラスをソースでロードする場合は、オートローダーが `src/App/Hoge/fuga.php` という名前のファイルを探します。
名前空間のプリフィックスは、似たプリフィックスと区別できるように`\\`で終わらせる決まりです。

```json:composer.json
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
```

## 対応付けのためのクラスマップ生成

```bash:
$ composer dump-autoload
Generated autoload files containing 543 classes

# PSR-4の参照はすべて、vendor/composer/autoload_psr4.phpにある連想配列に定義されます。
$ cat vendor/composer/autoload_psr4.php 
<?php

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'phpDocumentor\\Reflection\\' => array($vendorDir . '/phpdocumentor/reflection-common/src', $vendorDir . '/phpdocumentor/reflection-docblock/src', $vendorDir . '/phpdocumentor/type-resolver/src'),
    'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'),
    'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
    'Prophecy\\' => array($vendorDir . '/phpspec/prophecy/src/Prophecy'),
    'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator'),
    'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'),
    'App\\' => array($baseDir . '/src'),
);
```

## PHPUnitの設定ファイルとなるphpunit.xmlを作る
- [3. XML 設定ファイル &mdash; PHPUnit latest Manual](https://phpunit.readthedocs.io/ja/latest/configuration.html#)

```xml:phpunit.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!-- <phpunit>要素で、PHPUnitのコア機能を設定します。 -->
<phpunit colors="true" bootstrap="vendor/autoload.php">
    <!--<testsuites>要素と<testsuite>要素で、テストスイート群やテストケース群の中からテストスイートを構成します。-->
    <testsuites>
        <testsuite name="Test suite">
            <!--テストコードを作成するディレクトリとして作成したtestsディレクトリを指定します。-->
            <directory>./tests</directory>
        </testsuite>
    </testsuites>
    <!-- <filter>要素とその子要素で、コードカバレッジ対象のファイルのホワイトリストを設定します。 -->
    <filter>
        <whitelist>
            <directory suffix=".php">./src/</directory>
        </whitelist>
    </filter>
</phpunit>
```
```bash
$ ls -l
total 136
-rw-r--r--@  1 mana  staff    856  1 20 15:17 associativeArray.php
-rw-r--r--@  1 mana  staff    345  2  4 22:46 composer.json
-rw-r--r--@  1 mana  staff    263  1 20 18:41 composer.json.bak
-rw-r--r--@  1 mana  staff  52362  1 20 16:37 composer.lock
-rw-r--r--@  1 mana  staff    612  2  7 22:15 phpunit.xml
drwxr-xr-x@  2 mana  staff     64  2  4 22:09 src
drwxr-xr-x@  2 mana  staff     64  2  4 22:10 tests
drwxr-xr-x@ 15 mana  staff    480  1 20 19:03 vendor
```


# 参考
- [PHPUnitの使い方メモ - Qiita](https://qiita.com/__init__/items/a4c314c330b87fa03ba1)
- [composerについて初期学習まとめ - Qiita](https://qiita.com/eidera/items/3e0b2b41253e1563be46)
- [PHPUnit で PHP コードのユニットテストを行う | エレパ スタッフブログ](https://www.elp.co.jp/staffblog/?p=5890)