見出し画像

新しいテスト仕様書の書き方を紹介します!

プロとして仕事をするプログラマーなら誰だって、テスト仕様書を作ることがいかに難しいか、身に染みて知っていることでしょう。

決められた期間できちんと完了し、かつ十分な精度でテストしたものを納品する。
プログラマーの残業の多くは、その両立が難しいために起こると考えても、もしかすると差し支えないかもしれません。

一般論では、理論上ありうる全てのパターンを完璧に網羅するテストは不可能です。
従ってテスト仕様書は、多少なりとも優先度での絞り込みが必要です。
ですがなにをもって重要と見なすかの指標が人によって違うため、複数のキーパーソンの意向をそれぞれ取り込んだ結果、不可能であるはずの全網羅テストを結局やってしまっている、というケースはそれなりに多いのではないでしょうか。

だとすると、十分な品質を担保したいケースにおける 《最低限のテスト》 とは、いったいどこにあるのでしょうか――。

いつもお読みいただきありがとうございます。
それから初めて見てくださった方もありがとうございます。

私は、いつも世界のどこかでプログラムを書いております、プログラミングの専門家・エンジニアの中島と申します。
この 絶対バグらないシステム作ろうぜの会 は、バグの出ないシステム、問題を起こさないチーム運営のやり方などを、なるだけ面白く読めるように工夫しながらお伝えしていく主旨となっております。


1. 完全網羅テストを無理にやろうとすると起こる悲劇

世の中には、「バグを確実に防ぐには、完全網羅テストをするしかない」と思い込んでいる人もいます。
とりわけ、チームリーダーがそういう考え方を持っている場合、その考え方を強行したらどうなるでしょうか。

正解は、“メンバーとの相性次第で製品の品質が乱高下する” です。

メンバーが同じ考えで、残業過多も苦にならないタイプの人ばかりのチームなら、かなり品質の良いものが出来上がるでしょう。
(その人達の健康診断がどうなるかは別として)

ですが、そういうシラミ潰し的なテストが苦手なメンバーの多いチームでは、完全網羅テストを強行すれば、当然ながらテストの品質は平均以下にまで低下してしまいます。

たとえば、ここに1つの 《時刻入力オブジェクト》 があったとします。
このオブジェクトには、00:00 から 23:59 までの時刻が入力できるものとします。

完全網羅テストでは、まず正常系テストだけで1440のテストケースが必要です。
なぜなら1日は1440分だからです。

加えて、入力できないはずの数値を入力するケース数が960、マイナスを数値と見なす場合はさらに540ケース。
そこにさらに、UTF-8 として入力できてはいけないパターンなんかを加えるとすると、時刻入力オブジェクト1つに対する完全網羅テストケースの数はゆうに「京」を超えます。
万、億、兆の次の「京」です。
なぜなら、UTF-8コードは定義上の文字の数が京を超えるからです。

そのようなテストが不可能であることは誰にでも分かります。
それゆえ完全網羅テストを好むタイプの人は、“精神力を保てる範囲でなるだけ多くの” テストをやろうとしてしまいます。

このことはつまり、テストがひと段落つくごとにテスターの精神力が尽きることを示します。
そして精神力が尽きた状態で次のテストを、これまたせっかく回復した精神力が尽きるまでテストしなければいけないのです。

なおかつ、そういうテストを好む人は、往々にしてテスト自体はよくても、テストレビューが甘くなる傾向があるため、テストにかけた工数の割にはクオリティが上がらないことになってしまいます。
また、そのような莫大な量のテストを行う時間を実際には与えられていないプログラマーも世の中には多く、残業を前提とした指示になりがちです。

そのようなブラックなチーム運営をやってしまわないためには、テストを “ユーザーの行動パターン” に基づいて行うことが有用です。

コンピューターにできることを網羅的にテストするのではなく、
『人間がやりうること』
を網羅するイメージです。
なぜなら、システムとは本質的に “人間が使う” ために作るものだからです。

ですから、普通の人が普通はやらないようなパターンにテスト工数を過度に割き過ぎるのは、はっきりと無駄なのです。

2. 新しい観点の提案

提案1. 失敗者行動パターンテスト

では、人間が使うことを前提としたテストパターンとは、いったいどうやって作ればいいのでしょうか。

まず、正しい手順で正常に使用できている人を想定した正常系テストは、比較的簡単かと思います。
問題はそれが終わった次です。

「正常系が終わったら次は異常系だ」と考えるチームリーダーは、テストが苦手な部下を量産してしまいがちです。
なぜなら、何をもって異常と見なすかは、同じチーム内でもキーパーソンによってバラバラだからです。

精神に不調をきたした変な人だけを異常と見なす人もいれば、自分とソリの合わないあらゆる人種を全て異常者だと切り捨てる乱暴な人もいます。

ですので私個人としては、そもそもテストケースを “正常” と “異常” に分けるのがおかしいんじゃないかなと思うのです。
テストというのはユーザーが操作したときに不具合がないように行うものであって、異常な行動をとるユーザーを想定して行うものではないからです。

ですから私の理屈では、正常系テストの反対は《失敗系テスト》です。
本人にとって都合の悪い現象が起こるとしたら、それはユーザーにとって “失敗” だからです。

“ユーザーが何か失敗をするとしたら、それはどんな行動か”

それを想定するのが、正常系の次に行うべきテストというわけです。
それは、異常な行動をとるユーザーを想定してのテストではありません。
常識のある普通の人が、うっかり失敗したケースを想定してのテストです。

提案2. 失敗者フォロー行動パターンテスト

それから正常系以外のテストを “異常系” と呼ぶ人が忘れがちな観点として、ユーザーは失敗したら次は巧くやる、という点が挙げられます。
つまり、ユーザーは何らかの失敗をしたら、その次にその失敗をフォローする行動をとろうとするということです。

たとえば、

  1. 経費精算システムを使って

  2. 自費で買った文房具の費用を精算しようとしたが

  3. 領収証を添付し忘れてしまった

としましょう。
そのとき、世界中のあらゆるユーザーがそのまま諦めて放置してくれればテストは必要ないのですが、そんなことをする人は普通いません。
ユーザーはなんとかして領収証を追加しようとします

ですので、そのような追加がシステム的にそもそも不可能だとしたら、ユーザーはそのことを「不具合だ」と感じるでしょう。
実際、経費精算システムで精算データの修正ができないのは、世の中的には不具合とされます。

ですがテストケースがザックリ 正常・異常 の2つにしか分かれていないテスト仕様書では、この “失敗をフォローしようとする行動” が想定されていなかったり、または想定はされていても、テスト仕様書のあちこちにバラバラに入り混じっていて具体的な行動パターンを形成していないケースが非常に多いです。
なぜなら、日本人は人種的に「失敗すると問題になるなら、失敗しなければどうということはない」と考えてしまいがちだからです。

ですからテストケースは、ユーザーが失敗した場合のケースを想定したら、次はそのフォロー行動を想定する必要があるのです。

ポイントは全部で4つ。

  • 自身の失敗に “いつ気づくか” によって、その人の行動は変わる

たとえば上記の領収証を添付し忘れたケースでは、提出直後に気づく場合と、1ヶ月後に不意に思い出す場合とでは行動が変わってきます。

  • 失敗に気づくのは本人とは限らない

領収証が添付されていないことに気づくのが本人とは限らないし、上長や管理者が気づくことだってあるでしょう。
それらの人々がフォロー行動を取れるように想定することも重要です。

  • フォローの仕方を調べる行動も想定する

普通はやらないような異常な行動を普通のユーザーがとるとすれば、多くはこのフェーズです。
なんらかの失敗をして、それをどうフォローしたらいいか分からなくて、普通しないような行動をとるのです。
この段階で不具合が発生しないよう、想定することも大事です。

  • フォローできない失敗が、フォロー可能であるかのように見えないようにする

たとえば、一度決定したニックネームが二度と修正できないシステムがあったとします。
このときもし、修正できないことがどこにも表現されていなければ、ユーザーは修正は可能であるものと思いこんで様々な行動をとるでしょう。
そして十分に納得いくまで調べたうえで、修正できないことを「不具合だ」と判断するはずです。
あるいは、あまりに色んなことを試しすぎて、自身のアカウントデータを破壊してしまうかもしれません。

そのようなことにならないよう、「この段階でこのような失敗をするとフォローできない」ということが、何らかの形でユーザーに伝わるようにしておかなければいけません。
それが「伝わらない」こともまた、不具合の一種としてリストアップすべきことです。

提案3. 攻撃者行動パターンテスト

ここまでは、普通の人が普通に使ってて起こりえるテストでした。
それが終わったら、次はそのシステムに対して悪意を持ったユーザーの行動を検討するフェーズを入れます。

この攻撃者行動テストは、セキュリティ上はもっとも重要でありながら、スケジュールを理由に工数が削られてしまいがちです。
そんで、セキュリティを軽視しがちなリーダーに怒りを抱いているサブリーダーが、一番下のメンバーに「時間がないのは分かってるけど何とかして」と何のアイデアもなく無茶ぶりするところまでが あるある です。

そのようなことにならないよう、このフェーズはメンバー全員で重要性を再認識しておくことが重要です。

このとき、スケジュール上でないがしろにされないようにするアイデアとしては、

  • 攻撃者行動パターンテストを、結合テストの最初のフェーズで行う

  • “セキュリティのことだけを考えるキャンペーン期間” を明確に区切って、その期間内に行う

などが考えられます。

また、攻撃者行動パターンテストを行う上でもっとも重要なことは、

  • 実際に行われる可能性がある攻撃から優先的に想定する

  • 盗む価値のある情報が入っている場所を優先的に守る

ことです。

世の中にはセキュリティはとにかく強固であればよいと考え、システム全体を満遍なく守ろうとする人もいます。

ですがそれでは工数や労力がかかりすぎてしまうので、守るべき場所・責められやすい場所を強固にすることが大事です。
そのためには、重要でない場所のセキュリティをあえて落とす必要だってあるかもしれません。

この重要性の低い場所をあえて捨てることができずに、時間を無駄に使ってしまう人は多いです。

もし時間が十分にあるのなら、OWASP TOP10 などを参照して片端から対応してもいいのですが、セキュリティフェーズに十分な時間がないケースが多いのも現実としてあります。
納品まで残り2日しかないといった切迫した状況で、システム全体のSQLインジェクションを最初からチェックしなおすのは現実的ではありません。

あらゆる情報を片端から守るということは、「ユーザーのニックネーム」だとか「昨日食べた食事内容」といった重要性の低い情報も守るということでもあります。
事態が切迫している状況でそんなものを守らせていたのでは、その部分を担うメンバー自身のモチベーションだって落ちてしまいます。

そんなことにならないよう最初からスケジュールに組み込んでおくのが一番大事ではあるものの、それでもやはり “盗む価値のある情報” を優先的に守る意識を持つことは大事でしょう。

提案4. 異常行動者パターンテスト

ここまでユーザーの行動をベースにしたテスト仕様書の書き方を提案してきましたが、ここまでのテストではどうしても網羅できないポイントが1つだけあります。
それは、奇抜な行動をとる人の行動パターンをトレースできないことです。

『失敗者行動パターンテスト』『失敗者フォロー行動パターンテスト』『攻撃者行動パターンテスト』という3種類のテストだけだと、
“普通の人がしない行動をとる人”
のテストができないんです。

中にはいるんですよね。
たとえば、見た目にあきらかに時刻オブジェクトだと分かる場所に「朝」という漢字を入力しようとするとか、アップロードしたいファイルを(ドロップダウンエリアが別にあるのにわざわざ)アップロードボタンそのものへドロップしようとする、といった行動をとるユーザーとかとか。

そのような、どう考えてもおかしな行動だって、場合によってはプログラムのハングアップなどを呼び起こす可能性などもあり、全く想定しないわけにもいきません。
普通の人や、理知的な犯罪者の行動だけをパターン化していると、そのような奇抜な行動パターンがテストから漏れてしまうのです。

とはいえエンジニアだって “普通の人” であることには違いないので、「異常者の心理を推測せよ」と業務命令を出すことはあきらかに不適切です。
エンジニアはあくまでコンピューターの専門家であって、決して心理学者ではないからです。

そんなときは、あきらかに普通でない動作をあらかじめ想定する方法として、異常な行動をとる人がなぜ異常行動をとるのかの理由を突き詰めて考える方法が有効です。

異常な行動をとるユーザーは、ベンダーからは “なぜかバグをよく拾うユーザー” と認識されることが多いのですが、実際には “その画面の目的を理解する能力がやや低めの人” であるケースがやや多いです。
その画面の使い方が理解できるまでデタラメな操作を繰り返したり、または機能の目的外利用が多いのもこうしたユーザーの特徴です。

つまり、そのようなユーザーの行動パターンは、自身が作った画面を「幼稚園児のような素直な心で」見ることで、あるていどの想定が可能です。

悪意を持っている人の行動は 3. 攻撃者行動パターンテスト の段階で終わっているので、ここでは本当に “訳も分からず適当なことをする人” だけを想定すればOKです。

  • 目立つボタンがあるなら押してみる

  • 文字が入力できる場所に手当たり次第に絵文字を入れる

  • 自分が作った画面を、本来の用途でないことに流用してみる

などです。

3. 行動パターンテストのメリット

テストを完全網羅方式ではなく行動パターン方式で行うと、本番リリースした後にもメリットがあります。
万が一想定が足りなくて不具合が出てしまった場合でも、

  • テスト仕様書のどの部分に

  • どういった観点が足りなかったか

が見えやすくなることです。

不具合というのは、直して再リリースしたらおしまいではなく、同じ問題の発生をどう防ぐかを考えることが重要です。

その際、テストが完全網羅方式で記述されていると、観点の足りなかった箇所がテスト仕様書のあちこちに飛び飛びに散在してしまうことになります。
なぜなら、完全網羅方式のテスト仕様書は、ユーザーの行動を追いかけているわけではないからです。

テスト仕様書のあちこちを、エンジニア自身の責任で細かく修正していては抜け漏れだって多くなるし、先輩から後輩への技術継承も困難になります。

たとえば、通常多くのプログラマーは『ボタンそのものをドラッグしようとするユーザー』なんて存在は想定しないでしょう。
もし仮にたまたまそのようなユーザーがいて、不運にもそれで不具合が発生したとしても、テスト仕様書に『ボタンがドラッグできないこと』というテストケースを追加するだけだと、次の担当者はなぜそんなテストがあるのか理解が出来ません。
場合によっては、なにをすれば合格になるのかも理解ができないかもしれません。

前後のオブジェクトの関係で、たまたまボタンがドラッグできるように見えてしまったのだとしたら、それは設計の段階でそのように見えないよう工夫をすべきで、“そういうユーザーがたった1人いた” ために半永久的に意味の分からないテストケースを追加し続けるのは、どう考えてもブルジットジョブです。

そういった問題のあるテスト仕様書と比べれば、“そのときユーザーがやった一連の行動” をゴソッと一塊で追加した方が、絶対楽に決まってます。
“この画面はこういうことをするユーザーがいるので警戒するように” というメモ書きを残しておくだけでよくなるからです。

つまるところ、コンピュータープログラムというのは “人間が作って人間が使うもの” です。
なのでテストも、“人間が使う” ことを想定した方がいいのではないでしょうかってことで、私なんかはそのように思うわけです。

ではまた。

この記事が気に入ったらサポートをしてみませんか?