y_megane.log

日々の勉強や改善ネタの備忘。

書籍「テスト駆動開発」

古風な環境で働いているため、テストコードを書くという文化が未だにない。
今更ながらテスト駆動開発について学ぶべく、コレを読みました。

テスト駆動開発

テスト駆動開発

書籍の概要

テスト駆動開発」の本だが本書中で書かれているように、品質保証のソフトウェアテストではなく、設計・リファクタリングを正しく導くことが目的。
1部、2部の内容はテストコードの追加、機能実装、リファクタリングの繰り返しで進む。オブジェクト志向、デザパタなど駆使して「キレイな動作するコード」を作っていくので、それらの実践練習としてとても良い。オブジェクト志向やデザパタについて細かく解説されているわけではないが、他の書籍などで学んだ状態から理解度を深めるのに役立つと思う。

あまり書籍の詳細を書くのも良くないと思うので、以下はキーワードと簡単な解説の羅列、所感など。


テスト駆動について

レッド・グリーン・リファクタリング

テスト駆動開発の基本サイクル。
期待する挙動のテストを書き(テストファースト)、動く実装をして、リファクタリングする。
テスト、実装、リファクタリングを常に1歩ずつ進めるべし。
複数機能をまとめて実装しない。まとめてリファクタリングしない。書いたらテストを走らせる。
というのが原則だが、本書中でもステップの小ささは人や状況に寄るので加減してね、とのこと。
確認するまでもないような実装は、そのまま進めればいい。不安があればテストする。

f:id:ymegane88:20190414222746p:plain

テスト駆動を実現するために

仮実装と明白な実装

  • 仮実装:べた書きの値を使ってとにかく動く実装をする
  • 明白な実装:頭の中の実装をコードに落とす

テストを通る実装をする際、明確な答えがすぐ浮かぶならそれで良い(明白な実装)。
そうでないなら、とにかく動く実装(仮実装)をして、リファクタリングする。

三角測量

リファクタリング時に一般化方法が浮かばない場合、2つ以上のテストを書いて一般化のヒントとする。
(例:2つのテスト($5 == $5$5 != $6)からequalsを一般化する方法を考える)

テストケースの書き方

  • 「こうなったらいい」と思うケースを書き、一歩で動かせるところまで後退させる
  • 一般化は末端の実装から始め、テストケースまで到達させる
  • 「何をテストしたいか」後の読み手に分かりやすいケースを書く
  • アサートファースト:最終的に期待することを最初に書く
  • 明示的なテストコード:文脈が分かるように書く
    例として、100円の商品の税込み価格を確認するなら
    △:assertEquals(108, amount)
    ◯:assertEquals(100 * 1.08, amount)

実装の進め方

  • 実装に詰まったらテストが通った時点まで戻して再変更、再テスト。
  • 複雑な仕様を実装するために途中段階のための簡単なテストを作る。
    ($5 + 10CHF = $10を実装するために$5 + $5 = $10を実装する等)
  • テストを通す最低限の実装をして、その時点で不要なものはToDoリストに入れる。

TDDの普及のために

誰かがTDDを行っているなら、不具合が少なく設計がシンプルなことがチームに伝わるはず。
TDDを強制するべきではない(品質保証の仕組ではなく、個人の設計ツールなので強制力はないはず)
要するにまず自分で実践して、結果で魅力を示すべし。

途中からTDDに乗り換えるには

テストを考えずに作られたコードは、そもそも処理が独立しておらずテストが書けない。
テストなきリファクタリングは失敗を招く。テストとリファクタリングデッドロック。鶏と卵問題。

変えなくていいなら変えない。お金を生まないならコストを掛けるべきではない。
必要な時・箇所に対して、ペアプロや機能単位でのテストを行いながら慎重にリファクタリングする。
それを繰り返す内に、頻繁に変更が発生する箇所はTDDに近づいていくはず。

デザインパターン

デザパタは、様々な問題に対してプログラマが共有している一般的な解法、としている。
頻出問題の解き方のパターンを全員が知っていれば、誰が解いても同じ解答になるよね、ということ。
本書ではデザパタを網羅的に説明しているわけではないので本記事では割愛。

まとめと所感

上記の他にもリファクタリングのノウハウや考え方がサンプルや第1部、2部に沿って解説されている。
テスト駆動開発のノウハウや考え方の他に、本書と付録を通して、

  • テスト駆動開発の「テスト」は品質保証のためのソフトウェアテストではない。
  • 設計を導く手段であり、言い換えるならBehavior駆動開発(BDD)
  • BDDに基づいて作られたフレームワークRSpec, Cucumberなど(用語の置換等)
  • Mockなどテストの道具も全体的に当初の意味・用途から外れて用いられている
  • TDDは組織としてのソフトウェアテストの仕組ではなく、個人のコーディングを導くツール
    明日からでも導入できる(環境を制約されていなければ・・・)

など、「テスト駆動開発という開発ツールの(当初の)使い所」が繰り返し書かれている。
特に付録の訳者解説ではテスト駆動開発の起こりから現在までの変遷がまとめられていて自分や周りの人が「テスト駆動やろう」と言い出したときに、何を目的とするかか考えるキッカケになりそう。

テスト駆動開発自体は、総じて求められるレベルが高い。
個人ツールとして導入するのは良いが、チームで取り組む場合はレベルの高い現場でないと厳しい。
ただ、TDD導入までいかなくとも、第1部の写経だけでもすると全体のレベルが上がりそう。
「テストできる実装」を意識するようになると、実装も設計もだいぶ質が上がると思う。

TDDの理論だけでなくリファクタリングの練習問題集としてとても良い。
TDDへの興味の有無に関わらず、オブジェクト指向言語で開発しているのであれば読んで損はない良書。
会社の本を借りて読んでたけど、手元に欲しいので買いましたw