こちらの講演時にいただいた質問への回答です。

「テスト自動化とテスト駆動開発」講演資料 - やっとむでぽん

質問5. 実際にTDDで運用したとき、それでも不具合が発生したことがありました。 データの量、質が問題視されたことがありました。 受け取った情報の信憑性は会話しながら模索しないといけないのでしょうか

かつては、TDDしていればテストはそれで十分、それ以上のテストは不要と言われていたことがありました。現在は、TDDだけで品質を確保するのは難しく、それ以上のテストも必要だと言われています。

テスト駆動開発は、開発手法です。開発を駆動するために、プログラマーがフィードバックを得る道具としてテストを書きます。このテストは、開発を進めるには十分ですが、品質を担保するには不十分です。とりわけ、仕様そのものが曖昧だったり、抜け漏れがあるような場合、テスト駆動開発は無力です。

かつて「TDDで十分」と言われていたのは、これは個人的意見ですが、当時実践していたプログラマーがテスト設計もできるようなスーパーマンの人たちで、TDDのサイクルを利用していろいろな観点からテストを十分にできていたからかもしれません。いま挙げた、仕様に問題があるような場合でも、TDDをしながら「この仕様おかしいな?」と気づいて、お客様に問い合わせできていたかもしれません。(TDDには仕様の不備を見つけやすい効果があると、個人的には感じていますが、誰でもそれだけで十分というわけにはいきません。)

そういうわけで、ある意味至極当然ですが、TDDによる開発とは別にテストをすることになります。この「テストをする」は、手動テストと、テストを追加で自動化する両方を含みます。仕様書をレビューしてテスト設計をする活動が開発と並行して進めたり、開発できたものを触りながらテストしたり、開発完了前に自動化したテストを準備したり、チームやプロジェクトのテスト計画をもとした活動になります。

どんなテストが足りないか

まずTDDで書くのはユニットテストコンポーネントテストに当たるのがほとんどです。それ以外のテスト、統合テストやシステムテストなどは、他のアプローチが必要です。またユニットテストでも、TDDだけではテスト観点が足りていないので、あらためて追加のユニットテストをする必要があります。TDDしているなら、追加も自動化するのが自然でしょう。

TDD以外でテストを自動化することを、対比してQAテストと呼ぶこともあります(もっと広い活動を指してQAテストと呼ぶほうが一般的だと思います。ここでは説明のため、TDD後のテスト自動化をQAテストと呼びます)。TDDでは開発を駆動するためのテストを書きましたが、QAテストでは品質を保証するためのテストを書きます。この過程ではTDDで書いたテストも利用されますし、また整理や再構成(リファクタリング)の対象にもなります。QA観点ではテストが足りない場合もあれば、過剰なこともあり、またテストの位置づけを変えたほうが理解しやすかったりもします。

こちらテストを書くか書かないかの判断の話 · GitHubではこのように述べられています。この方は「TDDのサイクルを利用していろいろな観点からテストを十分にでき」そうに思えます。

ある程度実装が固まり、これでいこうと内心思えたタイミングがテストケースの網羅率を上げるタイミングです。ここでは TDD のテストではなく、QA (品質保証) としてのテストの観点に自分の頭を切り替えます。ここで初めて、同値分割や境界値分析による単機能のテスト設計をします (とくに無効同値クラスに分類される異常系の処理のためのテストを充実させることが多いです)。

こちらTDDのテスト vs. QAのための単体テスト について考えてみた - What is it, naokirin?では、TDDで書くテストと、QAのための単体テストの違いについて考察されています。

TDDのテスト 単体テスト
コーディングのため 品質(保証)のため
開発促進のため 欠陥を取り除くため
リファクタリングのため 品質確認のため
テストファーストで行う コーディング後に行う
詳細設計によるテスト 単体テスト設計によるテスト
設計技法としてのテスト 検証と妥当性確認のためのテスト
開発者が即座にフィードバックを得るため
プログラマのためのテスト
三角測量

こちらJaSST'12 TokyoのTDDセッションとWACATEセッションに登壇 - 千里霧中では、goyokiさんが2012年のJaSST(ソフトウェアテストシンポジウム)でのVOTDD(検証指向TDD)で、TDDのサイクルに検証指向(品質保証のひとつの観点)を含めるやり方について、発表とデモをされています。発表スライドが表示されない場合があるようですが、ページ内のリンクからアクセスできます。

資料の最後の方に「VOTDDの定義」の解説ページを追加しています。詳細はそこを参照して頂くとして、非常に簡略化して言うと、TDDでもテストについてもっと気をつければ色々良いことあるよというのがVOTDDです。

TDDでどのくらいテストを書くか、QAテストをどのくらい追加したりリファクタリングしたりするかは、プロダクトや組織によっていろいろです。気になるところをちょっと追加する程度から、何倍ものテストを書き足すところもあります。これは品質保証の戦略と、その中でのテスト自動化の位置づけに関わってくる、大きなテーマの一部でもあり、私が紹介できる範囲を超えています。

自分ならどうするか(TDDと直接関係ない補足)

元の質問に戻って、データというのはシステムへの入力データで、テストで使ったデータが不十分だったり、検討不足だったという状況かなと想像しました。個人的な経験も踏まえて考えてみます。お客様から「これが入力データだから」とデータフォーマットやテストデータを受け取った場合は、

  • 本物(本番データ)と、必ずどこか違う
  • 「0か1だけ」とされているフィールドに2が入るようなことが、最低1箇所はある
  • 本番で想定する件数(データ量)を扱うと、なにか問題が起きる
  • あり得ない矛盾したデータが本番では来る(存在しないデータの更新差分とか、明細が0件のオーダーとか)
  • 「これが最終版です」というバージョンが来てから、また新しいバージョンが届く

こういうことがあると想定します。想定した上で、開発と並行してどんなテストケースが必要か考えつつ、自分たちで使うテストデータを作ります。ここで作ったテストデータは、場合によっては、テスト駆動開発のサイクルで使うデータにすることもあります。あとで手動で流す用にすることもあります。本番環境の実データと比較して、どこが想定と違ったか調べる材料にも使います。

ソフトウェアの性質にもよりますが、別システムから受け取るデータは「得体の知れないよそもの」と思って、実行時のバリデーション(入力チェック、フォーマットチェック、整合性チェック)もかけます(これはfail fastのアプローチでもあります)。お客様のことは信頼しても、お客様が運用しているシステムは信用しないというわけです。バリデーション処理の開発は、いろいろ想像力を膨らませながら異常なパターンを考えて設計します。TDDのサイクルで、新たな可能性に気づいてパターンを補充したりもします。

現実として不具合が発生してしまったら、それ自体は仕方がないので対応します。可能な限り、不具合を再現するテスト(データも含む)を必ず書きます(TDDもそうでなくても)。テストを書いた上で修正をするという順番です。 もうひとつ、不具合がどうして発生してしまったのか分析するのも大事です。テスト漏れだとなったら、既存のテストも見直して漏れがあったら追加して自動化します。ここで新たに(未発生の)エラーを見つけられるかもしれません。コミュニケーションの改善が必要であれば、そうした施策を打ちます。QAチームがいたら分析と対策の活動を主導してくれるはずです。