はじめに
ユニットテストを作っていると、テストコードを書きやすいクラス、書きにくいクラスがありますよね。
ユニットテストを書きにくいクラスのテストコードを頑張って作っても、プログラムに改修が入ると地獄のようなテスト直しが待っており、挙げ句の果てにテストされなくなる、そんな苦い思いをしました。
そもそもなぜユニットテストが書きにくいのか、どうすればいいのか、未来の自分に向けて残します。
そもそもユニットテストの存在意義について考える
ユニットテスト書きたくないですよね、私は嫌いです。
ではなぜ書くのかを考えてみた。
- 良い動機
- 実装したコードの動作確認
- CI/CDでバグ改修がさらなるバグを生んでいないか確認するため
- 悪い動機
- なんとなく
- カバレッジが測定できれば品質を保てるという誤解
ユニットテストを作成して一番助かったのは、目視では気付けなかったバグの発見でした。
Input/Outputの検証をしていると、稀に期待通り動かない時があり、よく見るとロジックがおかしかったり。。。と
他にも、バグを修正したと思いきや他のクラスのテストが失敗。。。原因を調べると他にも修正するべきところがあったことに気づく、なんてこともあります。
個人的に一番ダメな例は、カバレッジ網羅のためにユニットテストを作成することですね。
カバレッジを網羅するためにソースを読み、ソースの分岐を通るためのテストを作る。
出来レースの様なテストコードは意味がない。
ユニットテストを作成する上で意識したいこと
ユニットテストを作成するときは、以下を自問自答するよう心がけるといいだろう。
テストコードは軌道に乗ってしまえば流れ作業のようになってしまうからこそ、
作成の意義や大切にしたい思いを振り返ることが大切。
- ソースコードの中身を細かく見ないで、様々なInput/Outputパターンを試す
- コード作成時には気づかなかったバグを発見できる
- コード作成時には気づかなかった使い方を閃く
- ユニットテストは、ソースコード作成から少し日を開けて作る
- ソースコードの中身を把握していると、どうしても分岐を通るためのテストになりがち。。。
- テストの実装が難しいと感じたら一旦立ち止まる
- おそらくソースコードが難解
- テストが実装できないようなソースコード、果たして数ヶ月後に見返して実装意図が思い出せるだろうか
- 頑張って実装したテスト、ソース改修が発生するたびに直せる?
ユニットテストの作成を妨げる要因
ここにきてやっと本題だが、ユニットテストの作成を妨げる要因はなんだろうか。
様々なブログ、本でユニットテストのあるべき姿が紹介されているが、
あるべき姿とかけ離れた成果物ができてしまうのは何故なのか、
ということを真面目に考えてみた。
要因は、大きく分けて2つあると思う。
- 考え方
- モチベーション
それぞれの要因について、細かく話を進めていく。
考え方
ユニットテストの考え方自体に問題があるのではないだろうか、という観点を掘り下げていく。
ユニットテスト自体が悪いわけではなく、ユニットテストの捉え方の問題である。
テストは、元のソースコードを試験するものである、これは当たり前。
バグが発見されたから治す、これも当たり前。
では、テストコードを作成するには少々難解であったり長いロジックであったが、頑張ってテストを実装した、これはどうだろうか。
私としては、NGである。
何が言いたいかというと、ユニットテストをリファクタリングのきっかけにしてもいいのではないだろうか。
俗に神クラスと呼ばれる超膨大なクラス、メソッドをテストする意味があるのだろうか、ないと思う。
やるべきことは、ユニットテストの実装に手こずるようなクラスやメソッドを、リファクタリングすることなのではないだろうか。
テストをしやすいように元のソースコードに手を加えることに対して抵抗感を感じるかもしれない。
しかし見方を変えれば 単純明快にする 、 結合度を下げる 等と捉えることができるのではないだろうか。
モチベーション
ユニットテスト作成に最も大切なこと、それはモチベーション管理である。
ソースコードを作成している時のワクワク感に比べ、ユニットテストのつまらなさといったら。。。(私の私見です
しかし、ユニットテストはコード作成者の使命だと思っています(だって、ユニットテストだけお願いするのはちょっと。。。
じゃぁモチベーションを維持するためにはどうしたらいいか、
ソースコード製造の4、5倍の期間を確保したい。
ユニットテストは、パターン出しと実装の繰り返しだと考えている。
1日に何度も何度もテストを作っていると、昼食後や夕方のタイミングで思考力が低下し、
パターンのだし漏れや、単純作業によるパターンの実装漏れが発生しかねない。
(最悪の場合、気力が湧かずにカバレッジだけ網羅して終わりなんてことも。。。
1日のうちで精度の高いユニットテストを作れる時間帯は決まっていると思うので、
せいぜい1日半分程度の稼動でテストを作り終えるくらいの期間を設けることがベストなのではないだろうか。
最後に
ユニットテストは品質の向上に有効である反面、ただの時間の無駄遣いにもなりかねない。
いっそのことテストをしない勢力も見かけるが、人の出入りが激しいIT業界で作成者に依存してしまうような作り方は、私は好まない。
泥臭いやり方ではあるが、少しでも存在意義のあるユニットテストを作成していけるよう、
今後も模索していきたい。