テスト駆動開発(TDD)についてまとめてみた

先日、とある社内の勉強会にて、テスト駆動開発に関してスライドを作成し発表したので、Qiitaにも残しておこうと思い作成しました。

ただ、内容はテスト駆動開発に関して網羅的にまとまっている訳ではなく、書籍「テスト駆動開発」の第三章のTDDのパターンから気になったものをピックアップし、自分の言葉でまとめたものになります。

## TDDの流れを端的にまとめると

1. 最初にテストコードを1つ記述
2. テストを実行し、失敗することを確認
3. 失敗したテストが成功するように、最小限のプロダクトコードを記述
4. 再度テストを実行し、成功することを確認
5. プロダクトコードの振る舞いを変えずにリファクタリングを行う
6. 次のテストコードを記述（1に戻る）

大事なことは、**まず「動くコード」を書き、それから「綺麗なコード」にしていくことである。**
いきなり綺麗なコードを書こうとしてもエラーが起きる可能性が高いので、徐々に綺麗にしていきましょう。

## TDDのパターン（抜粋）

### 仮実装を経て本実装へ
先ほども述べた、まず「動くコード」を書こうという段階において意識すべき大事な部分。
それはまず、**ベタ書きの値**を返してあげようということ。
それでテストが通るようになったら、ベタ書きの値をだんだん本物の式や変数に置き換えていく。
これは、そもそもテストファイルが正常に動作しているかの確認にもなる。

#### 仮実装の有効性
##### 心理的効果
グリーンバーとレッドばーでは、精神状態が全く異なる。
バーがグリーンなら、自分がどこにいるかがわかり、そこから自信を持ってリファクタリングを開始できる。

**この書籍を読み特に感じたことは、開発における精神状態を良い状態で保とうとする姿勢である。**

下の一文は書籍に書かれていたものだが、ユーモアを含みながらも、読んだときはこの重要性をしっかり痛感させられた。

```
「TDDは繰り返しグリーンバーに早く到達する、
最初レッドバーにするものの、レッドバーであるストレスから逃れることを意識」
```

##### スコープ制御
プログラマは次第にこの先起こる問題を予測するのが得意になる。
そのため1つの実例から始め、そこから一般化を行うことで、本質と関係ない問題に気を取られずに作業を行えるようになる。

また、1つずつ進めることで次のテストケースを書くときも、それより前に書いたテストが動くことがわかっているため、その問題のことだけを考えることができる。

つまり、1つずつ細かく区切って開発に取り組むことでやるべきことが明確になる、エラー箇所が大量になりストレスが溜まることがなくなる訳である。


### テストは不安を退屈に変える賢者の石
ストレスレベルが増加すると悪循環が発生する。ストレスがかかればかかるほど、テストを行う頻度が減る（後回し）、テストが減ればエラーが増え、そしてストレスもまた増える

テストを先に行うことで、サイクルが変化する
テストをすぐに走らせればミスの確率が減っていき実感が得られる。結果的にストレスが減っていく


ここでも繰り返し、開発時の精神状態を保つための秘訣の紹介である。要は横着せずに、適宜テストを走らせ、課題を一つずつ埋めていこうということである。


### TODOリスト

着手する前に、必要になりそうなテストをリストに書き出すことが大事である。
下の文章を読んだときは、実装中に迷子になりがちな自分にすごく響いた。

```
「コードを書く際にストレスに悩まされないコツは、
どこに行くべきかがわかるまでは、一歩も踏み出さないことだ。」
```

とにかくまず手を動かしたいときは要注意だと肝に命じなけらばと。

新しく何か必要なことを考えついた時は、「すぐやる」「あとで」のリストに加えるか、今のタスク内ではやる必要なしであるかを素早く判断する必要がある。
	


### シャワーメソッド（意識的休憩）
疲れたり手詰まりになった時は、シャワーを浴び、そして書くべきものが降りてくるまで浴び続ける。
目の前の仕事から離れることで、ようやく足りなかったアイデアに気付けることも多い。

これに関しては、特に個人開発で詰まった一日の最後に共感できることが多い。
自分の場合、トイレに行く時、散歩中、寝る前に修正すべき箇所に気づいたりするので、意識的にぼーっとする時間を取ることは大事だなと。

また、意識的な休憩の要素として、キーボードの横にペットボトルを置いておき、生理現象に働きかけ適宜休憩を取るようにすることも書かれてあった。


### やり直す
これは自分にとってはまだまだ難しいことである。つい、もう少し粘ったら解決するのではと、根拠なき希望を抱いてしまうからである。

しかし、手詰まりで途方に暮れてしまった時はコードを捨てて、やり直したほうが、結果的に早くゴールに辿り着けるものである。

書籍の中での具体例として、ペアプログラミングをする際に、ペアとなるプログラマの交代は作業やり直しのいいきっかけになるという話があった。新しいペアがこれまでのコードの経緯と無関係にアイデアをくれる訳である。


### 失敗させたままのテスト（個人開発用）
独りでプログラミングしている時、コーディング時間の上手い終わらせ方は、最後の書いていたテストを失敗する状態にして終えること。
そうすることで、次にコーディングに戻ってきたときに、どこから始めるべきか明白になる。
　
これは受験生の時に、あえて区切りの悪いとこで休憩を入れることで、その後勉強に復帰しやすくなるという勉強法を聞き実践したこともあったため、すごく納得できた。

また、失敗しているものの、TDDの手法として一つ一つを細かく分解して取り組んでいるため、比較的簡単にテストを通せるだろうという気持ちで再開できるところが良い点である。

## テスト駆動開発は誤解されがち
読み進めていくと、TDDは
**テスト技法ではなく、分析技法であり、設計技法であり、実際には開発の全てのアクティビティを構造化する技法である**
ということ、そして**テスト**というワードを含んでいることから、ついテスト手法であると勘違いされることが多いことを知った。

テスト駆動開発の名前に含まれる「テスト」という言葉が与える先入観がTDDの正確な理解の妨げになっていたのである。

実際、自分がこの書籍を手に取った時も、読み進めていた中で意識していたことの大半はそうであったと痛感。

## TDDからBDDへ、RSpecの誕生

この誤解を解くために、振る舞い（Behavior）という言葉を用いて、BDDが誕生した。TDDと大きな違いはないものの、使用する語彙を「テスト」から話すことで、より、分析・設計の部分を意識させている。

その具体例としてRSpecの誕生がある。

|変更前  |変更後  |
|---|---|
|assertion  |expectation  |
|test  |example  |
|testcase  |example group  |
|test class  |spec  |

## 受け入れテスト駆動開発(ATDD)
ここまで調べてみると、他のものも気になったので、1つ追加したくなった。

受け入れテストとは、ストーリーを意識したテストである。
そして、**各ストーリーが提供しなければならないビジネス意図を記述したテストである。**ということだ。

### TDD/BDD との違い
よりユーザー向けのテストを想定している
そのため、まず大きな枠組みのテストを作り、その中に粒度の小さなテストを追加していくイメージ。

テストの組み方の難易度が上がるため、Redの時間帯が長いが開発最終段階のテストを早い段階で自動化できるメリットがある。

ユーザー側にわかりやすいテストができるため、要求の齟齬が抑えられるメリットもある。

### 参考・引用記事
[RSpecでBDDしよう](https://speakerdeck.com/yatmsu/rspecdebddwosiyou)
[Coderetreatと、たまたま知ったBDDとATDDについてざっくり調べてみる](https://tech.yayoi-kk.co.jp/entry/2018/12/16/000000)
[実践ATDD ~TDDからさらに歩みを進めたソフトウェア開発へ](https://speakerdeck.com/hgsgtk/atdd-by-genba-example?slide=24)

書籍を読み、一度スライドを作成してからこれらの記事を見つけたのだが、すごく綺麗にまとまっており、参考にさせていただきました。