このPHPがテンプレートエンジンのくせに慎重すぎる 付録: phpspec篇

## この記事は何か

[このPHPがテンプレートエンジンのくせに慎重すぎる (前篇)]の内容をPHPUnitではなく[phpspec]に置き換えたものです。phpspecを使った開発フローの初歩の例として参考になると思います。

というか最初はPHPUnitではなくphpspecで押し通すつもりでしたが、期待してた[phpstan-phpspec]が最新版のphpspec+PHPStanでは動作ないことがわかったので断念しました。とはいえ、静的解析に期待し過ぎなければphpspecも良い選択肢だと思いますよ。

[phpspec]: https://www.phpspec.net/
[phpstan-phpspec]: https://github.com/proget-hq/phpstan-phpspec
[このPHPがテンプレートエンジンのくせに慎重すぎる (前篇)]: https://qiita.com/tadsan/items/bf61520eb2d455e0e8b4

## テスティングフレームワークのインストール

PHPUnitが有名ですが~~有名すぎておもしろくないので~~、ここでは[phpspec]を入れていきます。

```sh
$ composer require --dev phpspec/phpspec
```

Composer経由でクラスをロードするために`composer.json`を編集して設定します。

```diff
diff --git a/composer.json b/composer.json
index 943af4f..d559d78 100644
--- a/composer.json
+++ b/composer.json
@@ -14,5 +14,15 @@
     ],
     "require-dev": {
         "phpspec/phpspec": "^6.1"
+    },
+    "autoload": {
+        "psr-4": {
+            "Bag2\\Hello\\": "src"
+        }
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "spec\\Bag2\\Hello\\": "spec"
+        }
     }
 }
```

`composer.json`に書く時は、名前空間の`\`を`\\`のように二重にすることを忘れないでください(これはJSONの制約です)。また、名前空間の最後にも`\\`を付けることをを忘れないでください。`autoload-dev`の名前空間の最初に`spec\\`を付けているのはphpspecの作法です。

この設定の意味について詳しく知りたい人は[includeって書きたくない僕たちのためのオートローディングとComposer - Qiita](https://qiita.com/tadsan/items/a78c9160418200e2d47a)を読んでください。

せっかくなので、もうひとつ。依存関係が増える前にテキストエディタで`composer.json`を弄っておきます。

```diff
diff --git a/composer.json b/composer.json
index d559d78..56ca999 100644
--- a/composer.json
+++ b/composer.json
@@ -24,5 +24,8 @@
         "psr-4": {
             "spec\\Bag2\\Hello\\": "spec"
         }
+    },
+    "config": {
+        "sort-packages": true
     }
 }
```

この設定をすると、`composer require`で依存関係が増えたときにパッケージ名を勝手にソートしてくれるようになります。

手作業で`composer.json`を編集した後は、必ず`composer validate`で検証してください。また、オートロード関連の設定をした後は`composer dump-upload`を実行してください。

<img width="235" alt="スクリーンショット 2020-01-28 23.21.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/f8397a56-1c59-15cb-b0a5-55e449c3c901.png">

次に`.phpspec.yml`を設定しておきます。

```.phpspec.yml
suites:
    acme_suite:
        namespace: Bag2\Hello
        psr4_prefix: Bag2\Hello
```

これはphpspecにクラスを生成させるための設定です。

## specの追加

phpspecについて詳しく知るには[Introduction — phpspec 5.x documentation](https://www.phpspec.net/en/stable/manual/introduction.html)を読んでください。

specファイルを作るには`phpspec describe`コマンドを使います。詳しくは動画を見てください。

![phpspec-describe.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/180413d6-8328-9428-dc5d-edcd651929db.gif)


いきなりですが、phpspecではいきなり`phpspec run`します。

![phpspec-run.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/746915ab-93cd-c84e-7dfb-7adf16b4c977.gif)

すると、空のクラスのファイルが生成されます。

次に、またおもむろにspecファイルを書き変えます。

```diff
diff --git a/spec/HelloSpec.php b/spec/HelloSpec.php
index 0b11c59..f2f2317 100644
--- a/spec/HelloSpec.php
+++ b/spec/HelloSpec.php
@@ -7,8 +7,8 @@ use PhpSpec\ObjectBehavior;

 class HelloSpec extends ObjectBehavior
 {
-    function it_is_initializable()
+    function itはHelloを返す()
     {
-        $this->shouldHaveType(Hello::class);
+        $this->to('World')->shouldReturn('Hello, World!');
     }
 }
```

そのあと`phpspec run`を実行すると、なんと空のメソッド実装が現れます。

![phpspec-run-2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/99e1e0f9-cdb9-6be0-c662-abce5aba17e3.gif)

`phpspec run`を実行してグリーンになればOKです。

<img width="625" alt="スクリーンショット 2020-01-28 23.51.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/82ae20df-b6ea-8862-00a0-964c3dad2a98.png">

次にspecを増やしてみましょう。

```diff
diff --git a/spec/HelloSpec.php b/spec/HelloSpec.php
index f2f2317..9e212de 100644
--- a/spec/HelloSpec.php
+++ b/spec/HelloSpec.php
@@ -10,5 +10,6 @@ class HelloSpec extends ObjectBehavior
     function itはHelloを返す()
     {
         $this->to('World')->shouldReturn('Hello, World!');
+        $this->to('Miku')->shouldReturn('Hello, Miku!');
     }
 }
```

`phpspec run`を実行する赤く表示されます。

<img width="625" alt="スクリーンショット 2020-01-28 23.50.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/b6b9dd27-f3a4-6093-a9e0-83a49a52ba6c.png">

そりゃそうだ、`return 'Hello, World!';`なんて書いてるんだから。なので、しっかり実装していきます。

```diff
diff --git a/src/Hello.php b/src/Hello.php
index 50771a1..498da61 100644
--- a/src/Hello.php
+++ b/src/Hello.php
@@ -4,8 +4,8 @@ namespace Bag2\Hello;

 class Hello
 {
-    public function to($argument1)
+    public function to(string $name): string
     {
-        return "Hello, World!";
+        return "Hello, {$name}!";
     }
 }
```