ソフトウェアテスト

ソフトウェアテスト (英: software testing) は、コンピュータのプログラムから仕様にない振舞または欠陥（バグ）を見つけ出す作業のことである。ソフトウェアテストで見つかったプログラム中の欠陥を修正する作業をデバッグという。ソフトウェアテストに成功するとは、テストで欠陥が発見されるか、規定した試験項目にすべて合格するか、規定した品質目標に到達することである。目標とした品質には、規定した試験項目にすべて合格することもある。例えば、OS, プログラミング言語では、仕様を満たしているかどうかの適合試験を規定している。ソフトウェアテストでは、欠陥が存在することを示すことはできるが、欠陥が存在しないことは証明できない。ソフトウェアに仕様にない振舞がないことを保証する作業を証明といい、証明用のシステム、証明しやすい言語も多数存在している。本項では動的なソフトウェアテストを中心に扱う。 ソフトウェアテストの目的には以下が挙げられる。 作業成果物の評価による欠陥の防止（例: 要件、ユーザーストーリー、設計、コード） 明確にした要件を満たすかの検証 完成の確認・動作の妥当性確認（ユーザー等ステークホルダーに対する） テスト対象の品質に対する信頼を積み重ねて、所定のレベルにあることの確証 欠陥の作りこみ防止 故障・欠陥の発見、それによる不十分なソフトウェア品質リスクレベルの低減 意志決定のための情報提供（テスト対象の品質レベル等） 契約上、法律上、または規制上の要件や標準の遵守、また/あるいは準拠の検証 ソフトウェアテストは「変更への信頼」を生むことでソフトウェアの品質・提供速度を向上させる目的・効果を持つ。 ソフトウェアの変更（例: リファクタリング・機能追加）は既存コードの破壊によるバグ（リグレッション）を引き起こしうるため、ソフトウェアエンジニアに対し、コード変更への心理的ハードルとして作用する。このハードルは変更への躊躇いを生み、品質向上の機会を減少させてしまう。 リグレッションテストはコード変更によるバグを発見して欠陥の作りこみを防止し、品質に対する信頼を積み増す。この効果により、新たな変更が既存コンポーネントを破壊しないという信頼（confidence）・安心がエンジニアに生まれる。結果として良い変更の頻度があがり、ソフトウェアの品質・提供速度が向上する。 ただし、一度書かれたソフトウェアが「決して変更されない」場合にはこの効果が発揮されない。（参考: テスト駆動開発） プログラムを実際に動かしてみて行うテストを動的テストと呼び、プログラムを実際に動かしてみることなくソースコードやオブジェクトコードを検証する作業を静的テストと呼ぶ。静的テストには、ツールを用いた静的コード解析の他に、人手で行うコードレビュー、ウォークスルー、インスペクションなどがある。多くの場合、意識されることはないが、コンパイラまたはプリコンパイラはソースコードを静的にテストする。 機能試験・性能試験の指標と分類にISO/IEC 9126 (ISO 9126) の枠組みを利用することがある。 機能試験は、規定した機能を果たすかどうかを試す。 関数であれば、規定した引数を与えると、想定した戻り値を返すブラックボックス試験が機能試験に相当し、単体試験の一部である。 適合試験、単体試験は、機能試験を主とするが、性能試験を含むことがある。 性能試験は、ソフトウェアシステムの性能を測り、必要な性能が出ることを確かめる試験である。入力をどれだけ受付けるか、どれだけの出力が可能か。通信経路数・通信速度、処理件数などプログラム単体では問題が発生しなくても、通信、データベース、入出力 (I/O)、同時に起動するソフトウェアなどの高負荷、長時間使用などの条件下では性能が低下することがある。性能を確認する試験は、システムの性能に影響を与えないように測定する必要があるため、OSやミドルウェアなどでは性能を測定する効率的な計測方法を提供していることもある。 性能試験は、単体試験から実施する場合と統合試験から実施する場合とがある。 過負荷に対する性能試験をストレステストという。 ストレステストは、ソフトウェアシステムに対して高い負荷を与え、処理の低下・抜け、データの破壊、発熱など致命的な問題が、どういう条件で発生するかを試験する。ストレステストを行うことで、高い負荷が加わっている状況でしか発生しない不具合や、発生確率の低い欠陥、著しい性能の低下を発見することがある。性能試験の一部として実施し、対応可能な付加の仕様を確かめることがある。 仕様通りに動いているか、試験仕様に基づいて確認する試験を検証試験 (verification test)、エンドユーザーの意図通りに動いているかどうかを確認する試験を妥当性確認試験 (validation test) という。 決めた仕様に合致しているかどうかを試す試験。プログラミング言語、OS、通信規約、データベースなどの仕様に合致しているかどうかを試す試験を適合試験ということがある。 OS、プログラミング言語、ネットワーク通信プロトコル、データベースなどソフトウェアを動かすための基本的なプラットフォームが、仕様に適合しているかどうかを確認する検証試験 (verification test)。OSの国際規格の一つであるPOSIXでは、 NIST が適合試験のソースコードを公開している。 自動車用OSの国際規格OSEKでは、MODISTARC (Methods and tools for the validation of OSEK/VDX based distributed architectures) がある。 TOPPERS OSでは、TTSP (TOPPERS Test Suite Package) というテスト環境を提供し、適合テスト等を実施しやすくしている。 プラットフォームの適合試験を実施せずに、アプリケーションソフトウェアの試験を実施すると、プラットフォーム仕様の変化に対応できていないことがある。 エンドユーザーが意図している動作をするかどうかを試験することを妥当性確認試験という。 性能試験、システム試験、受入試験の一部として実施することがある。 全体が完成してからテストをすることをビッグバンテストという。規模の小さなプログラムであれば、この手法でうまくいく場合もある。この手法は大規模なプログラムに対して適当でない。なぜなら、大規模なプログラムを一気にテストをして問題が発生したときに、問題の原因を巨大なプログラム中から探すのが困難だからである。また、ソフトウェア中に複数のバグが存在する場合、それらのバグが相互に影響しあい、バグの原因の特定がさらに困難になる場合もある。そのため、ソフトウェアテストでは、最初に単体テストによってモジュール単位のテストを行う。単体テストの問題で、十分にモジュール単位のテストが終わったら、結合テストまたはシステムテストに進む。また、小規模なプログラムであっても、単体テストを行わずに結合テスト又はシステムテストへ入るのはテスト全体の効率を下げる。しかし、再利用性が高く、時間についての制約だけが中心の試験の場合は現場でビッグバンテストを行う場合がある。 単体テストおよび結合テストにおける手法の一つ。単体テストが完了したモジュールのうち、上位モジュールから順に結合させてテストを行なう。この手法の利点は、仕様的な振る舞いを決定する上位モジュールを早期に検証することによって、機能漏れ、仕様の認識違いなどの致命的な不具合を、開発の早い段階で発見できることにある。一方で、数の多い下位モジュールの検証が先送りされるため、開発と平行してテストを進めにくいという欠点もある。 トップダウンテストを行う際には「テストスタブ」を用意しなければならない。 単体テストおよび結合テストにおける手法の一つ。トップダウンテストとは逆に、単体テストが完了した下位モジュールから順に結合させてテストを行なう。この手法の利点は、数が多く独立性の高い下位モジュールから順に検証することで、開発とテストを平行して実施できることにある。一方で、システムの根幹となる上位モジュールで不具合が発見された場合、テストが完了したはずの下位モジュールも影響を受けるという欠点も持っている。単体試験を行う場合に、他の関数等を呼び出している関数を試験する場合に、呼出のない関数を試験してから、呼出をしている試験を行う場合にボトムアップテストになっている。 ボトムアップテストを行う際には「テストドライバ」を用意しなければならない。 プログラムの内部構造に注目したテストをホワイトボックステスト (英: white box test)、プログラムの入力と出力に注目したテストをブラックボックステスト (英: black box test) という。 ホワイトボックステスト (英: white box test) は、プログラムの構造に着目したソフトウェアテストのことである。着目する構造には命令や分岐などがあり、注目した構造に対してどれだけの割合の部分を実行できたかを網羅率で表す。 int abs(int x) { if (x < 0) { x = -x; } return x; } 命令網羅基準を用いてテストを行う場合は、すべての命令を実行すればよい。上記のabs関数では、x = -1 を用いてテストすれば命令網羅基準に従ってテストできたことになる。 判定条件網羅 (英: decision coverage) とも。分岐網羅基準を用いてテストを行う場合は、すべての分岐において、すべての分岐の方向を実行すればよい。上記のabs関数では、x = -1とx = 0を用いてそれぞれテストすれば、分岐網羅基準にしたがってテストできたことになる。分岐網羅は命令網羅の基準を満たす。 条件網羅基準を用いてテストを行う場合は、各々の個別条件について、全ての可能な結果を少なくとも1回はとるように実行すればよい。条件網羅基準は分岐の方向を意識しないため、分岐網羅・命令網羅の基準を満たさないことがある。 なお、判定結果に影響を与えない真理値に関しては省略しても良い。例えば判定条件: x > 0 || y > 0 に対して条件網羅性を満たすようにテストする場合、単純にテストするとx > 0の真偽、y > 0の真偽の両方を考慮して4通りのテストが必要になるが、x > 0が真の場合にはy > 0の真偽は判定条件に影響しないこと（短絡評価）を考慮すれば、以下の3通りのテストをすればよいことがわかる。 x > 0 かつ y > 0（または、x > 0 かつ y <= 0） x <= 0 かつ y > 0 x <= 0 かつ y <= 0 判定条件／条件網羅基準を用いてテストを行う場合は、各々の個別条件について全ての結果を少なくとも1回はとるようにし、かつ各々の分岐について全ての分岐の方向を実行すればよい。 複合条件網羅基準を用いてテストを行う場合は、それぞれの判定における全ての結果の全ての可能な組み合わせを少なくとも1回はとるように実行すればよい。ただし、ある組み合わせは作ることが不可能である場合がある。たとえば、条件 (A > 2) と (A < 10) とでは、可能な組み合わせは3つしかない。 経路網羅基準を用いてテストを行う場合は、すべての経路が少なくとも1回はとるように実行すればよい。反復構造を持つプログラムの全ての経路を特定することは普通は不可能であるから、この場合、完全な経路網羅は実行可能な目標とは考えられない。 ブラックボックステスト (英: black box test) は、プログラムの入出力だけに注目し仕様通りにプログラムが動作するか（もしくは仕様通りに動作しないか）をテストする。プログラムの入力が単一の値である場合は同値分割や限界値分析を、プログラムの入力が複数あり相互に影響を与えるような場合は決定表や原因結果グラフなどを用いて入力を決定する。大域変数の読み書き、通信、割り込みなどが処理中にある場合には、それらも入出力の一つとして扱う。 入力または出力を同じように扱えるグループに値を分けたものを同値クラスと呼び、それぞれの代表的な値を用いてテストを行う。 有効な同値クラスを有効同値クラス、無効（エラー）となる同値クラスを無効同値クラスと呼ぶ。 入力または出力を同じように扱えるグループに値を分け、その境界となる値を用いてテストを行う。プログラムのエラーは分岐の境界で発生する場合が多いため、限界値分析に基づいたテストを行うことで、同値分割に基づいたテストよりも多くの欠陥を発見することができる。 例えば、次のようなプログラムがあったとする。 入力: 時刻 (0:00-23:59) 出力: 10:00≦入力≦20:00であれば通常料金、それ以外であれば割増料金 通常料金の同値クラスは10:00以上20:00以下。 割増料金の同値クラスは0:00以上10:00未満と20:00を超え23:59以下。 無効同値クラスは0:00未満と23:59より大きい場合となる。 　 　　　　　0:00　 10:00 　　 20:00 23:59 －－－－○●－－－－－－－－○●－－－－－－－－－●○－－－－－－－－●○－－－ 無効同値　　　　同値クラス　　　　　同値クラス　　　　　同値クラス　　　　無効同値 クラス 　　　 　(割増料金） (通常料金)　　　　 (割増料金)　　　　クラス　 (エラー) ＜－－－－－－－－－－－－有効同値クラス－－－－－－－－－－＞　（エラー） 　 ●：端を含む ○：端を含まない 同値分割ではそれぞれの範囲から代表的な値を入力として選びテストを行う。 入力例)-1:00、8:00、12:00、22:00、25:00 限界値分析では、入力の範囲を想定される出力ごとに分割し、それぞれの範囲の境界を入力として選びテストを行う。 入力例）-0:01、0:00、9:59、10:00、20:00、20:01、23:59、24:00 決定表（デシジョンテーブルとも）とは、条件(入力)が複数のパラメータから構成されている場合に、 条件(入力)と動作(入出力)の関係を表形式で表したものである。 表の各列が規則(テストケース)を表している。 単体試験 (英: unit test) は、関数、メソッドなどの小さな単位で行うテストのことである。単体テストは、関数の場合には基本はブラックボックステストである。ブラックボックステストが済んだものの品質を確保するためにホワイトボックステストを行う。「Unit Testing」の略である「UT」と呼ぶことがある。また、開発現場によっては「CT（和製: Coding Test）」や「PT（和製: Program Test）」と略すこともある。 単体試験の道具としてJavaではテスティングフレームワークJUnitが有名である。これはJava専用である。他の言語にも同様のものがあり、それらを総称してxUnitと呼んでいる。 統合試験 (英: integration testing) は、単体試験が完了したプログラムを組み合わせて行うテストである。プログラムのどの部分から組み合わせていくかで、トップダウンテストとボトムアップテストに分けることができる。「Integration Testing」の略である「IT」と呼ぶことがある。また、結合テストと呼ぶ場合もある。 統合試験とシステム試験を分ける場合もある。統合試験とシステム試験を分ける場合に、模擬試験 (英: simulation) を統合試験に分類する場合と、システム試験に分類する場合がある。 プログラムを単独ではなく、他のプログラムやハードウェア、通信ネットワーク、データベースなどと組み合わせて実施するテストである。開発環境と実行環境が異なる場合には、実際の実行環境を使って行うこともある。顧客にしか実際の実行環境がない場合には、顧客環境で行う場合がある。実際の環境を利用することが高価であったり時間がかかる場合には、模擬試験環境 (simulator) を作成して実施することがある。この場合には、模擬環境のシステム試験、実環境でのシステム試験と区分する。模擬環境では、複数の事象を同時に発生させることが難しかったり、逆に実環境ではありえない事象を発生させることができなかったり、それぞれの短所・長所を見極めて試験を実施する。エンタープライズ[要曖昧さ回避]系と組込みソフトウェアで本質的な違いがあるわけではなく、OS、言語、ネットワーク、データベース、接続機器数の違いが大きい。 受入試験 (英: acceptance test) は、検収テスト、承認テストとも呼ぶこともある。受入試験は、システムを受け入れるかどうかを判定する試験である。システムの実際の利用者が行う場合と受け入れ試験をシステム運用・保守会社が実施する場合がある。システムが仕様通りの機能や性能を備えているかどうか確認する検証試験だけの場合と、システムが利用者の意図通りに動くかどうかを確認する妥当性試験を含む場合がある。 完成前のソフトウェアを開発者以外に利用してもらい、欠陥を発見してもらうテストのこと。アルファテストは、ベータテストよりも完成度の低い段階（アルファ版）で行うテストである。アルファテストは内部で、ベータテストは外部でという区分をすることがある。オープンソース、オンラインゲームにおいては、ベータテストを広く一般に公開し、宣伝の目的も兼ねて実施する場合がある。ベータテストで配布するソフトウェア（ベータ版）は、基本的には製品版と同等の機能を備えるが、不具合が存在する可能性があるため、利用に際して注意すべきことが注意書きなどに記載している。設計側が予期していない不具合が発生することもあり、注意書きにないことで何を考えなくてはいけないかを想定し、システムのバックアップなどを実施してから導入することを基本とするとよい。 単体テストや結合テストを行う際に、テスト対象のプログラムを呼び出すためのプログラムや、テスト対象のプログラムが利用しているプログラムがまだ使えない（もしくは、テストが完了していないため使うべきでない）場合がある。このような場合に、テスト対象のプログラムを呼び出すためのプログラムをテストドライバ (英: test driver)、テスト対象のプログラムが利用しているプログラムの代替となるプログラムをテストスタブ (英: test stub) という。 int isCompositeNumber(int x) { return !isPrimeNumber(x); } 上記のプログラムは、与えられた値が合成数かどうかを判定するプログラムである。このプログラムをテストするために必要なテストドライバとテストスタブの例を示す。 int main() { int num; for (num = 2; num <= 10; num++) { if (isCompositeNumber(num)) { printf("%d is a composite number", num); } else { printf("%d is not a composite number", num); } } } int isPrimeNumber(int num) { return (num == 2) || (num == 3) || (num == 5) || (num == 7); } このテストスタブは与えられた値が素数かどうかを判定するプログラムとしては明らかに不完全であるが、テストドライバから実行する範囲においては正しい挙動を示すので、指定した範囲でのテストスタブとしては十分な場合がある。しかし実行範囲が変わったときに直し忘れる可能性があるため、テストスタブ名に実行範囲を示す文字を入れる場合がある。 プログラムを修正・変更した場合に、過去に実施したテストを再度実施することを回帰試験 (英: regression test) 又は退行テストという。修正前の試験に再度合格するかどうか、他の機能に影響与えていないかどうか、他の機能が動作するかどうかを確認する。過去のテスト資産を使い、実施する回数も多いことから、実施を省略することがないようにテスト自動化することにより効率化を図る。 回帰試験にて、テストする範囲を全テストケースとするか、(全テストケースを実施した場合に要する時間や工数と修正が及ぼす範囲を考慮して)部分テストケースとするか判断し、また、欠陥を検出する頻度を考慮して高い優先度で実施するテストケースを選択する方法がある。一方で、アジャイル開発手法を選択した場合、ソフトウェアの更新頻度も仕様変更頻度も共に高くなることが見込まれるため、特に開発期間が短いアジャイル開発手法においては、回帰試験が多くの不必要なオーバーヘッドになる可能性がある。回帰試験をサードパーティーに委託する場合、あるいは、ソフトウェアの一部がサードパーティーによって開発される場合、必ずしも修正が及ぼす範囲が判断できるわけではないので、テストする範囲は全テストケースと成らざるを得ない。[要出典] 再現試験 (repeatability test) は、初めて起きた現象・実験結果を確認する追試と、事故・不具合を再現し対策を立てるために実施することがある。 ソフトウェアが複雑になり、機能、関数の数が千以上になってくると、性能試験、機能試験の結果を統計的に処理し、どういう試験を実施するとよいかを統計的に検討することがある。また、テストでは、欠陥が存在することを示すことはできるが、欠陥が存在しないことは証明できないため、いつソフトウェアテストを終了すればよいかを決定するための基準として統計的手法として信頼度成長曲線等を利用する場合がある。信頼度成長曲線を利用する場合には、条件の変化を統計的にうまく扱わないと見落としが発生するか、無駄な作業を続けることがある。 アジャイルテストの4象限とは、テストを「ビジネス面/技術面 x チーム支援/製品の批評」の4象限に分類したものである。例えば単体テストは特定モジュールという技術要素に着目しチームの開発を支援する目的で設定されるテストであり「技術面 x チーム支援」の第1象限に分類される。アジャイルテストの4象限という分類により、各テストが持つ役割を明確に認識することが可能になる。