システム開発におけるテストの目的とよくある事例

    システム開発におけるテストの目的とよくある事例

    目次

      はじめに

      自己紹介

      20年弱エンジニアをしています。その大半が保険業界に関わってきました。
      主に汎用機系の仕事にかかわることが多いですが、最近はオープン系の仕事にも携わっています。

      対象

      システム開発の経験があまりない方、テストは実施したことはあるけど何となくでやってしまっている方向けに実経験を交えて独自視点でポイントをお伝えできればと思います。
      現場レベルだと教科書通りとはいかないことも多々あるため、参考になれば幸いです。

      テストの実施目的

      「品質を保証するため」、「品質を上げるため」等、人によって多少捉え方が異なると思いますが、 私が考えるテストの実施目的は、ズバリ、不具合(バグ)を見つけること! です。

      「不具合(バグ)を見つけて修正する」ことを繰り返すことで、最終的には「品質を上げる」、「品質を保証する」につながる訳ですが、このように考えているのにはいくつか理由があります。

       

      不具合(バグ)はどうしても混入してしまう

      不具合の混入原因としては、単純なコーディングミス、仕様の理解が誤っている、技術的な理解不足等様々ありますが、経験則的に不具合はどうしても混入してしまいます。

       

      疑ってかからないと誤りを見逃してしまう

      せっかくテストを実施して不具合が顕在化しても、それを見逃してしまっては意味がありません。

      わかりやすい例で説明しましょう。
      メールや文書を作成したときに、見直したはずなのに誤字脱字が残ったままだったという経験がある方は多いと思います。
      まさにこれです。正しく書いたはず、という意識だと誤りを見逃してしまうことが多々発生してしまいます。

      また、自分で書いたものだと誤字脱字を見逃してしまうけど、他の人が書いたものだと発見できてしまうという方も結構いらっしゃるかと思います。
      正しく書いたはずという思い込みがなくフラットな状態で見るため、発見しやすいのかなと思います。岡目八目という言葉もありますしね。

      私事ですが、私も昔はまさにこの状態に陥っていたことが多かったです。
      一緒に働いていた先輩に、「誤字脱字が多い君に誤字脱字を見つけられるのは悔しい。」ということを言われたこともありました。

      ここでもう一つ面白い例を紹介します。以下の文章を見てください。

      こんちには みさなん おんげき ですか? わしたは げんき です。
      (出典:https://news.livedoor.com/article/detail/4143419/)

      多くの方がぱっと見で読めてしまうと思いますが、実はよく見ると文字の順序が入れ替わっています。
      誤った日本語なのに正しい日本語の様に錯覚してしまう例です。

      誤りがあるかもしれないという意識でいると、文字列が間違っていることに気付けるのではないでしょうか。

      このように、私たちの頭は無意識に都合のいいように理解しようとしてしまうことがあるので、意識的に誤りがないかと疑ってかからないと見逃してしまうことが出てきてしまいます。

      もう一つ私の失敗事例を紹介します。
      顧客帳票(公的な書類)の文言変更時に「と」が「ど」になってしまっているのに気付かず、そのまま顧客に送付されてしまい本番障害になったことがあります。 (ダブルチェックをしていましたが、もう一人の方も気づけませんでした。)

      幸い注意文言の部分だったため業務事故にはなりませんでしたが、非常によくない事例です。

       

      納期、リソースには制約がある

      プロジェクトに関わっているといつもぶつかる大きな壁です。
      データのパターンは規模が大きくなるにつれて指数関数的に増加するため、これをすべて実施して品質保証するというのは大抵の場合難しいです。
      そのため、ホットスポット(※)から優先してテストを実施し、少しでも多く不具合の発見・修正を行い完璧な状態(不具合が0の状態)に近づけていくというアプローチが有効です。

      ※ホットスポット:
      不具合が混在している可能性のが高い部分。
      簡単に説明すると、直近の変更回数が多く行数が多いファイル(コンポーネント)が該当する。
      hotspot値の計算方法が気になる方は検索してみてください。

      テスト方法

      ここではテスト方法について軽く触れておきます。

      開発でよく聞く 「〇〇テスト」 という言葉ですが、テスト手法やテストライフサイクル(テスト工程)のどちらについても使用されるので少し整理しておきましょう。

       テスト手法 :どのような観点、アプローチでテストを実施するかの方法論のこと
       テストライフサイクル :テストを進めていく上での段階のこと
                  一般的に、単体テスト→結合(統合)テスト→システムテストと段階を進めて実施していく。

      テスト手法

      テスト手法は大きく分けて2種類あります。
      ・ブラックボックステスト
      ・ホワイトボックステスト

      ブラックボックステスト

      入力値と出力値に注目したテストです。ロジックについては意識しません。
      入力した値が仕様通りの結果として出力されるかどうかを確認することを目的としています。

      ホワイトボックステスト

      主にロジックに注目したテストです。
      分岐網羅の確認として行われることが多いです。網羅率のみに目が行きがちですが、出力値が仕様通りとなっていることの確認は必須です。

       

      テストライフサイクル

      テストライフサイクルは大きく3種類あります。
      ・単体テスト
      ・結合テスト(統合テスト)
      ・システムテスト

      単体テスト

      単位としては一番小さいテストです。
      現場レベルでは会社や組織によって単体テストで何をどこまでテストするかは結構バラバラです。
      既存改修の場合、規模が小さいと省略され結合テストから入ることも多々あります。

      アプローチの違いとして2種類あります。
      ・コードベースの単体テスト
      ・機能ベースの単体テスト

      ○コードベースの単体テスト

      まさにホワイトボックステストです。
      組織によって変わってきますが、境界値テスト程度のみの実施にとどめている場合も多くあります。
      他のテストで不具合が見つかった場合に原因を特定するために実施するというケースの方が多いかもしれません。

      ○機能ベースの単体テスト

      バリデーションチェック、ソート等、機能が想定通り動作するかを確認するテストです。
      新規開発では必須、既存改修の場合でも影響がある場合は必須です。

      特にソート機能の場合、英数字が混在する項目については特に注意が必要です。
      言語やフレームワークによって英字→数字の順になるか、数字→英字の順になるかが変わってくるので、要件通りにならない可能性があるため調整が必要になる場合あります。
      ただ、こちらが先でないとダメということが少ないため、「承知しました」で済む(実装の仕様がそのまま採用される)ことが多いです。

      結合テスト(統合テスト)

      基本的には、単体テストが終了した後に複数のコンポーネントをまたいで仕様通り動作するか確認するテストです。
      私の経験上ですが、不具合の多くが結合テストで発見されます。

      システムテスト

      主にデータのライフサイクルに関する確認、性能面の確認を行うテストです。
      本来、処理時間がかかりすぎる等の性能面の問題が発見される程度で、ロジック的な不具合はそれほど出ないはずです。

      ただ現実としては、プロジェクトの都合上、期間圧縮のため結合テストが完了していない時点で並行で実施する場合も多く、大量に不具合が出てしまう場合も存在します。(特にウォーターフォールの場合)

      テスト漏れでの障害事例

      ここでは、私の経験上、テストをしっかりしていれば防げたであろう障害事例を紹介したいと思います。

      0件テスト漏れで異常終了

      事象:0件ファイル(空ファイル)が連携されたため異常終了
      原因:0件ファイル(空ファイル)が連携されたときの考慮漏れ
         最低1件はデータがある前提のロジックとなっており、データからキーを取得してDB検索する処理でキーなしで異常終了

      結合テストで0件テスト(※)を実施していれば簡単に見つかる不具合の例です。
      特にバッチ処理で作りこんでしまうことが多いと思います。簡単なテストなので忘れず実施するようにしましょう。

      ※0件テスト:
      データの内容が0件の場合のテスト。入力データ、出力データそれぞれの場合について実施すべきテスト。
      なお、意図的に異常終了させる設計になっている場合もあるため、仕様通りの動きになっているかという観点で確認を行うこと。(異常終了したからNGとは限らないことに注意。)

       

      境界値テストが不十分で処理誤り

      事象:分岐条件が誤っていたため、想定外の処理が行われてしまった
      原因:比較演算子誤り('<=' とすべきところを '<' としていた等)

      境界値の場合、不具合が見過ごされる2つのパターンがあります。
      1つ目は、仕様は正しく理解していたがテストが不十分な場合です。
      2つ目は、仕様自体を誤って理解してしまって誤りに気付かない場合です。

      1つ目に関しては、条件に書かれている値そのものと隣り合う値について、真偽どちらになるのが正しいかを意識すれば発見は容易でしょう。

      問題は2つ目です。仕様を誤って理解していたら誤った結果が出力されていたとしても正しいと勘違いしてしまい発見できません。
      特に 「以上」「以下」  「より大きい」「より小さい」 の表現がある場合は注意しましょう。
      例えば、 「2以上」「2以下」 の場合は 2を含む  「2より大きい」「2より小さい」 の場合は 2を含まない というところです。
      日本語の難しいところですね。

      なお、設計書、テスト仕様書を書く際にも同様の問題が発生するため、十分注意を払う必要があります。

       

      AND,OR,NOTの組み合わせテスト不足で処理誤り

      事象:条件の記載誤りにより、想定外の処理がされてしまった
      原因:カッコの付け忘れ、つけ間違いによって本来想定していたものと異なる条件分岐となってしまっていた

      組み合わせテストを網羅できていれば発見できる例ですが、条件が複雑になると漏れが発生しやすくなるので注意が必要です。
      漏れを防ぐにはデシジョンテーブル(※)を作成するのが有効です。ただし、組み合わせ数が増えるとケース数が膨れ上がるため、取捨選択が必要となる場合があります。

      ※デシジョンテーブル:条件の組み合わせでどのような結果となるかを示した表

      デシジョンテーブルの例
      202302_systest _01

      ・Y:条件に当てはまる
      ・N:条件に当てはまらない
      ・X:条件の組み合わせによって得られる結果(今回の場合は条件に合った金額)

      また、複雑なロジックの場合、シンプルなロジックにできないかという観点でのコードの見直しも非常に有効です。
      コードがシンプルになることでテストもしやすくなり、テスト漏れを防ぎやすくなります。

      さいごに

      いかがだったでしょうか。
      長くなってしまったため、特に伝えたかったことをまとめとして2点再掲します。

      ・テストの目的は不具合を見つけること
      ・不具合(バグ)がないか疑ってかかること

      こちらの記事がテストの意義の理解、品質向上の助けに少しでも貢献できれば幸いです。
      最後までお読みいただきありがとうございました。