12章 ユニットテスト
12.1 保守性の重要さ
コードの内部構造についてテストが設けた前提条件をいくつか破っており
具体的にどんな状況なのか、いまいちピンとこない
コード例がパッと思い浮かばない
メタプロで大域的な動きを壊してしまった?→でもそんなコードは書くほうが悪いのでは?
例)依存関係があるメソッドの順序を壊している、setの条件を変えたらgetの方のテストが壊れる、集計系の関数に新しい条件が追加された
少なからず良くない実装と表裏一体にはなってそう
12.2 脆いテストを防ぐ
テストの変更はシステムの明示的な契約を破りつつあることを示し、一方で先に挙げた別種の場合のテスト変更は、意図されていない契約を破りつつあることを示す
「契約による設計(Design by Contract; DbC)」を前提に置いていそうな表現
自分が書いたばかりのコードの専念するテストを書くほうが、そのコードがシステム全体にどう影響するか理解するよりずっと楽な場合が多いのだ
Privateメソッドへのテストを書きたくなるモチベーションってそういうのがあるのか、と思った(Privateメソッドへのテストを書こうとしていた話を聞くと、「テスト行数を短くしてテストの可読性を上げたい」という人ばかりだったのでこの視点はなかった)
科学(science)というよりは技法(art)だが
めちゃくちゃ細かい話だけど、技法=artなのか。技法というよりは職人芸みたいなニュアンスで捉えるほうが自然なのかな?
勿論エンジニアの知識不足というのもあるんだろうけど、脆いテストを"テストしやすい"ようにサポートするテストライブラリがあるから脆いテストが量産されるんだろうな...と思ったり...
テスト技法について全く言及がないのは当たり前だからなのか、知らないのか。前者?
テスト技法:cf.)同値分割、境界値分析
12.2でというよりは、このユニットテストの章全体で言及がないのが気になる
ユニットテストならばカバレッジで測定可能なので触れていないのかも。テスト技法はどちらかといえばブラックボックステストに効く
14章に書いてて欲しいけど書いてない
テストサイズによって重視すべき価値観のグラデーションがあると良い
Googleにしか書けない大規模テストの内容が多いから優先順位が低い?
12.3 明確なテストを書く
テストが失敗する場合、エンジニアの最初の仕事は、以上の2つの場合のどちらに失敗が属するかを特定し、それから実際の問題の原因を追求することである
12.3.2 メソッドではなく、挙動をテストせよ
BDD(Behavior Driven Development) の考え方が解説されてる
「テスト駆動開発」の付録Cに時系列込みで説明があったのとほぼ同じ内容
12.3.3 テストにロジックを入れるな
12.4 の方に循環的複雑度の話を先に書いちゃった
例12-15と全く同じようにして/のバグを隠したテストを見つけたことがあったので、なんか当時を思い出してしまったw
いいはなしだw
12.4 テストとコード共有:DRYではなくDAMP
DRYすぎるコード
各テストケースの循環的複雑度は可能な限り1にする、という話題が今日の職場で挙がった
循環的複雑度ではtry ~ catch はカウントしないが、createForumAndRegisterUsers() ではエラーを握りつぶすことで実質条件分岐を行っている
テストに条件分岐をつけたいなら分岐が必要な数だけテストケースを分割すべきだし、それによって組合せ爆発が起こるならばそれはメソッドが複雑すぎる
自分たちの現場では、テストコードは循環的複雑度=1じゃないとpushできないようにまさにしていたので、共感できた
静的解析でできますね、たしかに
循環的複雑度自体の扱いの話: 宣言的に書かれていれば循環的複雑度は低いのか?
「実際には分岐発生してますよね?」
表示が絡むと崩れるかどうかのラインがどうしても生まれる
バグは見つかっただろうか
validateForumAndUsers のassertion が逆になっている
12.5 結論
12.6 要約
全体的に、そんなに新しいこととか難度が高いことは書いてなくて、基本を丁寧にやりましょうみたいな章に個人的には感じた。
みんなからのコメント
Googleにしかできないとしたら、それはなぜか?
全般的にそこまで難しさは感じなかったけど、実態としてどれくらい徹底できているのか?っていうのはあるのかもしれない。どのプロダクトでもこれが実施できているのが基本ですってなると、日本でもそういう企業は少ない気がする。ひとえにレビュアーがそこそこいるっていうことなんだろうか?普通の会社だとそこまでレビュアーがいない?
規模と範囲にしかり、保守性と明確性にしかり、自分たちの言葉でテストに備わっているべき特性を言語化できているところかな?言っていることは同じだけど、「テストは読みやすく壊れにくいものにしましょうね」を言い続けているだけよりは実現容易性が全然変わってきそう
言語化はやろうと思わないとやれないので、そういう動機づけがあるのがさすがGoogle
スケールさせる、属人性を排除する、という視点に立っているからこそ
完全に感覚ですが、Developerがユニットテストを書きたくない、という人がまだ多い気がします。書こうと声掛けしても、優先度を下げてしまうOTZ
書く組織と書かない組織とで世界線が違い
1回書いちゃうとカバレッジ下げたくなくなっちゃう、逆に書いてないと書いたところで保守性は向上しないし、自動テストの実行環境が整ってないことが多いので恩恵を感じにくい
テストを書く習慣のある現場でも、「テストはテストできない」という矛盾に向き合うのはそれなりに難易度が高い
現場でどこまでできているか?
基本はすべてできているかな。初期値設定の共有とかはやりがちな気がするけど
脆いテストが上がってきたときに、リジェクトする手段がコードレビューしかないのがちょっとしんどい
まさにロジックを含んだテストコードを先週末突っ返したところでした
本章はシニアエンジニアはだいたい心得ている内容ではあるが、手法化して浸透させるまでは行ってない
これまでの章と比較してそんなにハードル高いという印象はなかった。ただ、品質としての保守性についての考えが理解されていなくて、例えばt-wadaさんの「質とスピード」の講演が何度も色んな会社で再演されていることからも、日本の当たり前になるのはまだ先なのかなと感じた
作って終わりだと必要性が相対的に低い
「エンジニアリング組織論への招待」でPjMとPdMの違いが語られていて、ビジネスモデルはPdMの方向に行っているのに習慣が変わってない
この本があるのになぜ実践する企業はすくないのか?
この章に関しては実践しているのでは?と感じたが、もしできていないなら、エンジニアがテストコードを書くことに抵抗感だったりつまらなさを感じているのかもなーと思った
QAがテストしてくれるから、Devはコードを書ききればいいという一種の役割分担みたいなところはある気がする。個人的には、Devに単体テストを求めるのであれば、QAもUnit Testを書けて然るべきではと考える
ホワイトボックステストは実装者が書くのが一番コストが低いのでDevが書くのが一番、QAは見つけたバグにテストを足せるのが理想
ペアプロでプロダクトコードとテストコードを同時進行で実装すると良い
それの乗り越え方はなにか?
t-wadaさんの「質とスピード」もそうだけど、同じことを色んな人が話してそれを社内でも共有して段々と当たり前の考えになることで文化として根付くのかない
色んな人が話すのが大事
今日もたまたま「Jestではじめるテスト入門」の1章 なぜテストを書くのか が凄いよかったって話をしたのですが、同じ話を色んな人がしたり、同じような話を同じ人が何回もしたり出来るといい
テストを書くのが楽しいと思えるようにするための活動をしていくとか。方法はなんでもいいけど、例えばモブプロしたり、テストのエキスパートの方が書いたテストと自分たちのテストを見比べてみたりとか
自動テストピラミッドの原則にとらわれずまずは、どのレイヤでもいいから自動テストを作ってみること。E2Eで作ってみて、これはメンテしんどいね、効率悪いねって実感できると、Unit Test書かざるを得なくなる状況になる方が、チームが成長できる。
テストがあって助かる状況はライブラリアップグレードとリファクタリング。テストを書く習慣がない現場だとリファクタリングは根付いてる可能性が低いので、まずはセキュリティリスクを説明しやすいライブラリアップグレードから
手で検証することのしんどさを体感してもらって、実際にアップグレードが必要なライブラリ数を示して絶望してもらう
問題から目をそらすアプローチをしない現場であることは最低条件ではある。。。
ライブラリのアップグレードをサボっていると言語とFWがアップグレードできなくなり、言語とFWに致命的な脆弱性が発見されたら終わりの状態になる
ステップを小さくするとしたらどうできそうか?
本書を見ながら、例えば毎日一個ずつ、「これはできているかな?」を顧みるようにしてみるとか?