テスト駆動開発をPHPで写経-第1章

PHPで[テスト駆動開発](https://amzn.to/37nji9B)を写経してみたのでその記録です。
本記事では第1章のみ紹介します。

# 所感

PHPではコンパイルエラーがないため手順が少し違いました。

# 作業記録

作業ディレクトリphpunitをインストール

```console
composer require --dev phpunit/phpunit
```

phpunitの実行確認

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

p4記載のMoneyTestを追加

```diff
diff --git a/tests/MoneyTest.php b/tests/MoneyTest.php
new file mode 100644
index 0000000..c119b0e
--- /dev/null
+++ b/tests/MoneyTest.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace money;
+
+use PHPUnit\Framework\TestCase;
+
+class MoneyTest extends TestCase {
+    public function testMultiplication() {
+        $five = new Dollar(5);
+        $five->times(2);
+        $this->assertEquals(10, $five->amount);
+    }
+}
```

テスト実行

```console
✔︎ tdd-php vendor/bin/phpunit tests
PHPUnit 7.5.17 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 17 ms, Memory: 4.00 MB

There was 1 error:

1) money\MoneyTest::testMultiplication
Error: Class 'money\Dollar' not found

/Users/ok/data/projects/tdd-php/tests/MoneyTest.php:9

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
```

money\Dollarがないため追加する

```diff
diff --git a/src/Dollar.php b/src/Dollar.php
new file mode 100644
index 0000000..fa36766
--- /dev/null
+++ b/src/Dollar.php
@@ -0,0 +1,6 @@
+<?php
+
+namespace money;
+
+class Dollar {
+}
```

テスト実行

```console
PHPUnit 7.5.17 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 17 ms, Memory: 4.00 MB

There was 1 error:

1) money\MoneyTest::testMultiplication
Error: Class 'money\Dollar' not found

/Users/ok/data/projects/tdd-php/tests/MoneyTest.php:9

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
```

テストコードでrequireが必要なため追加

```diff
diff --git a/tests/MoneyTest.php b/tests/MoneyTest.php
index c119b0e..53d144d 100644
--- a/tests/MoneyTest.php
+++ b/tests/MoneyTest.php
@@ -3,6 +3,7 @@
 namespace money;
 
 use PHPUnit\Framework\TestCase;
+require_once(dirname(__FILE__)."/../src/Dollar.php");
 
 class MoneyTest extends TestCase {
     public function testMultiplication() {
```

テスト実行

```
PHPUnit 7.5.17 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 18 ms, Memory: 4.00 MB

There was 1 error:

1) money\MoneyTest::testMultiplication
Error: Call to undefined method money\Dollar::times()

/Users/ok/data/projects/tdd-php/tests/MoneyTest.php:11

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
```

timesメソッドが必要なため追加

```diff
diff --git a/src/Dollar.php b/src/Dollar.php
index fa36766..f5e0635 100644
--- a/src/Dollar.php
+++ b/src/Dollar.php
@@ -3,4 +3,6 @@
 namespace money;
 
 class Dollar {
+    function times() {
+    }
 }
```

テスト実行

```console
✔︎ tdd-php (master) vendor/bin/phpunit tests
PHPUnit 7.5.17 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 17 ms, Memory: 4.00 MB

There was 1 failure:

1) money\MoneyTest::testMultiplication
Failed asserting that null matches expected 10.

/Users/ok/data/projects/tdd-php/tests/MoneyTest.php:12

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
```

assertが失敗している

テストを通すための実装

```diff
diff --git a/src/Dollar.php b/src/Dollar.php
index 181bea1..2b71b14 100644
--- a/src/Dollar.php
+++ b/src/Dollar.php
@@ -3,6 +3,7 @@
 namespace money;
 
 class Dollar {
+    public $amount = 10;
     function times() {
     }
 }
```

テストを実行

```console
✔︎ tdd-php (master) vendor/bin/phpunit tests
PHPUnit 7.5.17 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 16 ms, Memory: 4.00 MB

OK (1 test, 1 assertion)
```

テスト通った

現在のままでは重複に気づきにくいため修正

```diff
diff --git a/src/Dollar.php b/src/Dollar.php
index 2b71b14..8339073 100644
--- a/src/Dollar.php
+++ b/src/Dollar.php
@@ -3,7 +3,7 @@
 namespace money;
 
 class Dollar {
-    public $amount = 10;
+    public $amount = 5 * 2;
     function times() {
     }
 }
```

テストもまだ通る

```
PHPUnit 7.5.17 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 17 ms, Memory: 4.00 MB

OK (1 test, 1 assertion)
```

小さく変更を重ねていく

timesメソッドで設定するようにする

```diff
diff --git a/src/Dollar.php b/src/Dollar.php
index 8339073..7cf0221 100644
--- a/src/Dollar.php
+++ b/src/Dollar.php
@@ -3,7 +3,8 @@
 namespace money;
 
 class Dollar {
-    public $amount = 5 * 2;
+    public $amount;
     function times() {
+        $this->amount = 5 * 2;
     }
 }
```

timesに渡されている値を使う

```diff
diff --git a/src/Dollar.php b/src/Dollar.php
index 7cf0221..97bb265 100644
--- a/src/Dollar.php
+++ b/src/Dollar.php
@@ -4,7 +4,7 @@ namespace money;
 
 class Dollar {
     public $amount;
-    function times() {
-        $this->amount = 5 * 2;
+    function times($multiplier) {
+        $this->amount = 5 * $multiplier;
     }
 }
```

コンストラクタに渡されている値を使う

```diff
diff --git a/src/Dollar.php b/src/Dollar.php
index 97bb265..301c993 100644
--- a/src/Dollar.php
+++ b/src/Dollar.php
@@ -4,7 +4,12 @@ namespace money;
 
 class Dollar {
     public $amount;
+
+    function __construct($amount) {
+        $this->amount = $amount;
+    }
+
     function times($multiplier) {
-        $this->amount = 5 * $multiplier;
+        $this->amount = $this->amount * $multiplier;
     }
 }
```

これで 2と 5の重複がなくなった

最後に *= を使う

```diff
diff --git a/src/Dollar.php b/src/Dollar.php
index 301c993..8819734 100644
--- a/src/Dollar.php
+++ b/src/Dollar.php
@@ -10,6 +10,6 @@ class Dollar {
     }
 
     function times($multiplier) {
-        $this->amount = $this->amount * $multiplier;
+        $this->amount *= $multiplier;
     }
 }
```

以上