自動テストの俺的ノウハウ
前書き
kekemoto の自動テストの考え方についての備忘録
この考え方でソーシャルゲームのサーバーを開発1年、運用1年ほどしています。
今のところバグに関しては幸せに暮らせてます。
自動テストの性質
テストコードの作成は簡単なほど良い。
作成にかかるコストはプロダクトが長期に続くほどペイしていきますが、少ないに越したことはないです。
テストコード自体のメンテナンス性も重要であるためです。(テストコードも壊れます)
全てのバグをテストコードでカバーすることはできない。
バグとは想定外のところで起きるので、人間がテストコードを作っている限り、想定外をなくすことはできない。
ある程度の割り切りが必要。
どの粒度までテストするのかを決めておくと良い。
テストコードの有効性を判断するのは難しい。
テストコードを見て「仕様を網羅しているか、穴がないか」を確認するのは結構しんどい
新規作成時はまだしも、時間が経ち仕様が変わっていくとより大変になる
定量的に評価できるとより良い。
テストコードのメンテナンスは蔑ろにされやすい。
テストコードがちゃんとしてなくても、プログラムは実行できてしまう。
前述の通りテストコードの有効性を判断するのは大変で、どのコードに手を入れるべきか簡単に把握できない。
どのテストコードがダメになっているか、定量的に評価できると良い。
以上の自動テストの性質については多くの人の同意が得られるのではないでしょうか?
次の段では、上記の性質を基に kekemoto の自動テストの設計思想を書きます。
作るものや状況によってベストは変わってくるので参考程度にお願いします。
自動テストの設計
前書き
前述の性質の短所をどうやってカバーするのか、具体的な方法を性質ごとに書いていきます。
テスト対象は Web アプリケーションのサーバー側。
MVC で書かれているとする。
テストコードの作成は簡単なほど良い。
モデルのユニットテストは行わなず、コントローラーのテストを行う
コントローラーが正常であればモデルも正常であることが分かるためです。
なんなら「ユニットテストでは大丈夫だったけど結合テストで失敗した」の方が多くないですか?
スタブやモックは作成しないです。
ユニットテストをせず、結合テストを主に行うので、そもそもスタブが活躍しないです。
「テストをしやすくすることで設計も良くなる」という説は信じてないです。
テストは高速には終わりませんが、スタブのためにプロジェクトコードの複雑性が上がったり、モックを作らず簡単に作成できる方が良いです。
影響のあるコントローラーだけのテストであれば、十分高速に終わります。
全体のテストは CI で回しておくと良いと思います。
実装が終わった後にテストを書きます。
後述しますが、カバレッジを満たすようにテストを書きます。
基準が明確なので過不足なく、悩むことなくテストコードを書けます。
これらを実践することで作成コストが激減します。
リクエストを投げてレスポンスが成功していることを確認するだけです。
レスポンスの内容も確認せず、成功したかどうかだけを確認します。
全てのバグをテストコードでカバーすることはできない。
どこまでテストをするかの基準をコントローラーのコードカバレッジ 100% とします。
もちろんコードカバレッジだけで全てが網羅できるわけではないですが割り切りです。
100% は目安で理由があればその限りではありません。
コードカバレッジを基準とする理由としては、
定量的、自動的に評価できる。
かなりの部分のロジックを網羅できる。
データ構造の変更にも対応できる(動的型付けの言語)
命名変更にも対応できる(IDEの弱い言語)
テストコードの有効性を判断するのは難しい。
仕様が変更された機能はテストが失敗し、仕様が追加された機能はカバレッジが減ります。
ガバレッジによって定量的、自動的に評価できる。
仕様の変更による「影響範囲の推定や、テストの抜け漏れの確認」といった手間をなくせます。
テストコードのメンテナンスは蔑ろにされやすい。
テストの有効性が自動的に評価されるので、ダメになった時に、ダメになった箇所がすぐに把握できます。
テストが簡単に作れることで、修正も簡単になります。
自動テストを行う理由
前書き
自動テストは蔑ろにされやすいです。「行う」理由を明確にして動機付けをします。
「行わない」判断をするときに、リスクとリターンを測り、明確な基準で判断できるようにします。
テスト対象は Web アプリケーションのサーバー側
手動でポチポチするより速いし楽
手動でデータを準備したり、手動で API 叩くのを、そのままコードにするだけ(ヘルパーも作る)
作ってる間に何回かテストするので、手動でポチポチする方が面倒。
例:テストを書いていくとバグを見つけて修正する。
影響範囲を正しく見極めて、手動でテストやり直しますか?
自動化して今回の範囲を全部テストしちゃった方が速いし楽。
例:コードレビューで指摘されて修正。
影響範囲を正しく見極めて、手動でテストやり直しますか?
自動化して今回の範囲を全部テストしちゃった方が速いし楽。
例:締切が迫っています。修正した後の手動テスト、手を抜きたくなりませんか?
自動化しておけば問題なし
kekemoto は「まぁ大丈夫だろ」と手を抜いてバグったことがあります。余裕がなくなると こうなりがち
変更を簡単にする
「動いているコードに手を入れて壊してしまうのが怖い」「動くコードに触れるな」
動くコードに触れなくとも結局動かなくなってしまうのがこの業界です。
OSも、ブラウザも、言語も、フレームワークも、なんなら自動でアップデートされてしまうので、 コードに一切手を触れていなくとも動かなくなってしまいます。
動くコードに手を触れ続ける準備をしてこなかったから、毎回爆弾処理のような心理状態でリリースをしなければならなくなるのです。
(ある程度)バグがないことを保証できる
コードカバレッジによって網羅率を保証できる
所感
テスト対象によっては TDD を厳密に守ろうとすると「コスト」と「メリット」が釣り合わない場合があると思います。
「なぜそれをするのか?」を理解し、対象によって最適化をしていくのが重要だと思います。
関連リンク