はじめに
2022年の8月に『テスト駆動開発』(Kent Beck 著、和田卓人 訳)を読んだので、内容の備忘録を残しておこうと思います。本の内容を全部書いていると、記事が明らかに長くなって、一目で辟易とする人が増えて読まれなくなってしまうと思います。軽いメモと思ってください。
原著は2002年に出版されているので、なんと20周年ですね!
名著なので皆さんは読んでいらっしゃると思いますが、この記事にお付き合いいただき、「そんな内容だったな」と思い出していただければ幸いです。
テスト駆動開発(Test-Driven Devvelopment; TDD)の概要
動作する,綺麗なコードを作ることがテスト駆動開発の目的です。
ルール
- 自動化されたテストが失敗したときのみ、新しいコードを書く
- 重複を除去する
手順
2つのルールに従って、レッド/グリーン/リファクタリングのサイクルでプログラムを育てていくことになります。
レッド:実装したい機能に対するテストコードを、いの一番に書きましょう。
まずはテストを書くんです。機能の実装の仕方を思いついた気になって、本体コードを書いてはいけません。
テストファーストが本体の実装をテストしやすい粒度にとどめるため、実装が独立性を保ちやすくなるからです。
グリーン:そのテストを通る本体コードを書きましょう。どんな手を使ってでも!!
先ほど書いたテストは、書いただけなのでもちろん通りません。どんな汚い手段を使ってでもテストを通らせましょう。
テストが通れば、コードを信頼するための軸が作られたことになります。そして、エンジニアは安心感で満たされて、コミュニケーションが増え、フィードバックをポジティブに捉えられるようになります。
リファクタリング:テストを通す過程で生まれた重複を除去していく段階です。
なんとしてでもテストを通るように書いた本体コードは、普通のエンジニアなら到底受け入れられない醜いコードになっているはずです。例えば、以下のようなものですね。
import unittest
import target
class TestSample(unittest.TestCase):
def test1(self):
self.assertEquals(3, target.sum(1, 2))
if __name__ == "__main__":
unittest.main()
def sum(first, second):
return 3
他のテストを追加したら失敗するし、あたいはベタ書きだし、docstringはないし、、、
文句を言い出すとキリがないですが、テストは成功します。そして、test.pyとtarget.pyに重複が見られます!そうです、3
です!!
コードをたくさん書いていかなくたって、重複が生まれてしまうものです。それを溜飲が下がるまでリファクタリングしていきましょう。
def sum(augend, addend):
"""二つの引数の和を返す
Args
augend (int): 被加算数
addend (int): 加数
Returns
int: 二つの引数の和
"""
return augend + addend
リファクタリングでコードを壊してしまいそうですか?大丈夫です。絶対的な信頼を寄せていいテストを持っているので、コードを書き換えるたびにテストを実行してもいいですし、不安を覚えてからテストを動かしてもいいです。すぐに一歩戻ることができます。
今、グリーンの後にリファクタリングをしているので、リファクタリング最中に扱っている問題は一つなので、一歩戻るのも簡単です。
写経してみての雑感
TDDの概要や実践方法に触れました。TDDは自分のプログラミングをどうやって進めるかという話なので、チームメイトみんなで「いっせーのーせ」で始める必要がないから、試しやすいと思います。
『テスト駆動開発』の1章と2章には読みながらTDDの手順を追うことができるので、興味がある人は本を買ったり、図書館で借りたりして写経してみてください!
本書の写経で、僕がTDDを実感したことが以下の点です。
- リファクタリングで重複をまとめていく過程で、デザインパターンの活用が見えてきたり閃いたりする。まさにテストが開発や設計をドリブンしている、前進させる。
- テスト同士が絡み合っていると、たとえ一つだけレッドバーが現れたとしても、潜在的なエラーを疑いたくなってしまう。テストする機能を明確にしてから実装することが、本体コードにもテストコードにも独立性をもたらすので、その疑いが生じない。
- 「書いては消し」を繰り返すので、コードを消すことの躊躇いが薄くなる。自分が書いたコードは愛着が湧いて消しにくいけど、邪魔で醜いものは思い切って消さなきゃ!(本質は、テストがあるので、重要なコードの部分が分かるし、消しちゃってテストが通らなくなったなら、復活させればいいという話)
テクニック
本書の3章は、TDDの方法やパターンを用意しています。その中のいくつかをメモします。
TODOリスト
テストすべき事柄を忘れてしまわないように書き留めるリストを用意しましょう!
リストを作っておけば、実装中のセレンディピティを捕まえておく場所がはっきりしていて逃すこともないし、セレンディピティを追いかけてしまってやりかけを残すことも起きませんね。
いつ作業を一段落させるか
独りでプログラミングをしているなら、次に戻ってきた時に前回の終了が分かりやすいように、最後のテストを失敗した状態で作業を一段落つけよう。
チームでプログラミングをしているなら、自分が書いてないコードにも自信を持たなくてはならないので、テストが全て通る段階で共有して一段落にしよう。
おわりに
さて、簡単に『テスト駆動開発』の内容をおさらいしましたが、実際の本はまだまだ内容てんこ盛りです。また、訳者の方がテスト駆動開発の現在を解説してくださっています。
テストに関する議論が様々あるようですが、それらはまた余力が出てきた時にでもと思います。
本の中で次の言葉が書いています。
TDDはテスト技法ではない。TDDは分析技法であり、設計技法であり、実際には開発のすべてのアクティビティを構造化する技法なのだ。
(『テスト駆動開発』第32章 p.278より抜粋)
TDDはXPのプラクティスの一つですが、開発者独りでも実践しやすいプログラミングプラクティスではあります。
しかし、テストを書いて満足するのではなく、テストを書くことでコードの構造を整える方に頭を使わなくてはいけませんね。
長文、駄文失礼しました。ここまでお読みいただきありがとうございました。