前のパートに戻る 完了して次のパートへ  

  0-3 テストの役割と重要性

テストの役割と重要性


本教材は Laravel 製のアプリケーションを対象としているので、「ウェブアプリケーションソフトウェア」についてのテストを扱います。また「テスト駆動開発」を学ぶことが主題です。しかし、後述しますが、「テスト駆動開発」はソフトウェアテストのためのフレームワークではありません。効果的にテストを書くためには別途ソフトウェアテストの知識が必要です。ソフトウェアテスト全般だとあまりにボリュームが大きすぎるので、自動テストに関係のある部分のみを抜粋して取り上げます。


ソフトウェアテストの定義と目的

本教材での「テスト」は正確には「ソフトウェアテスト」のことを指しています。「ソフトウェアテスト」の定義を最初に明確にしておきます。「ソフトウェアテスト」とは。Wikipedia による定義を引用すると、

ソフトウェア(英: software)は、コンピューター分野でハードウェア(物理的な機械)と対比される用語で、何らかの処理を行うコンピュータ・プログラムや、更には関連する文書などを指す。ソフトウェアは、一般的にはワープロソフトなど特定の作業や業務を目的としたアプリケーションソフトウェア(応用ソフトウェア、アプリ)と、ハードウェアの管理や基本的な処理をアプリケーションソフトウェアやユーザーに提供するオペレーティングシステム(OS) などのシステムソフトウェアに分類される。
https://ja.wikipedia.org/wiki/ソフトウェア

ウェブアプリケーションはアプリケーションソフトウェアのいち分類であり、主にブラウザとウェブサーバが通信してデータのやり取りを行うものを指します。

ソフトウェアテスト (Software testing) は、コンピュータのプログラムから仕様にない振舞または欠陥(バグ)を見つけ出す作業のことである。
https://ja.wikipedia.org/wiki/ソフトウェアテスト

つまり、「ソフトウェアテスト」とはなにかを簡潔にいうと、アプリケーションが仕様に合致しているかどうかを確認し、不具合を見つけ出すために行うもの、といえます。


ソフトウェアテストの分類と概要

テスト工程

ソフトウェアテストの工程は、大きく分けて以下の3つに分類されます。

  • 単体テスト(ユニットテスト)
  • 機能テスト(フィーチャーテスト)
  • 受け入れテスト(アクセプタンステスト)

それぞれ、以下が正しく実装されているかどうかをチェックします。

  • 内部設計
  • 外部設計
  • 要件定義

ウォーターフォールスタイルの開発では、下図のように、左側の矢印上に配置された開発工程が、右側の矢印上に配置されたテスト工程がそれぞれ対応しています。

各開発工程の定義についても記載しておきます。

  • 「要件定義」とは、ソフトウェアが提供するべき機能や満たすべき性能を明確にする作業です
  • 「外部設計」とは、ソフトウェアの外部(ユーザー、他のソフトウェア、データベースなど)との入出力をどうするかを決める作業です
  • 「内部設計」とは、ソフトウェアの内部でどのように処理を行うかを決める作業です

アジャイル開発とテスト駆動開発の組み合わせにおいても基本的にこれらの対応は変わりませんが、要件定義のあと(あるいは要件定義しながら)機能テスト + 外部設計 + 実装から始めたり、要件定義のあと単体テスト + 内部設計 + 実装から始めたり、ウォーターフォールのように直線的、分断的にならないことも多々あります。

「教材の概要」でも述べましたが、本教材では単体テストと機能テストのみ、かつそれらの自動テストを扱い、受け入れテストおよび手動テストは対象ではありません。また、用語についてはこれ以降「ユニットテスト」「フィーチャーテスト」を統一して使用します。


ブラックボックステストとホワイトボックステスト

ソフトウェアの内部(処理やデータの流れ)を理解せず(あるいは無視して)行うテストを「ブラックボックステスト」といいます。反対に、ソフトウェア内部の作りに応じた形で行うテストを「ホワイトボックステスト」といいます。一般的にはユニットテストは「ホワイトボックス」で行うことが多いですが、テスト駆動開発の場合、最初はブラックボックスで始め(まだプロダクションコードがないので当然ですが)、必要であればあとからホワイトボックス的にテストケースを増やしていく、というやり方になります。

テスト駆動開発では、テストコードを書きながらプロダクションコードを書いていくので、プロダクションコードを書いてからまとめてテストコードを書くよりは、内部の作りを意識して書くことになりますが、意識としてはブラックボックステストの意識をやや強めに持っておくといいのではないかと思います。


効果的なテストケースの作り方

コードカバレッジ

コードカバレッジ(網羅率)は、記述されたコードのうち、テストで通過した(実行した)部分の割合を示す数値です。

コードカバレッジにはいくつか種類がありますので、ご紹介します。

  1. ステートメントカバレッジ: すべての命令を一度通ると100%となる
  2. ブランチカバレッジ: 各分岐の真・偽をそれぞれ通ると100%となる
  3. 複合条件カバレッジ: 分岐の条件のすべての組み合わせを試すと100%となる

番号の小さいほうが、100%になるパターンが少なくなります。

たとえば、ある料金計算のプログラムが、以下のような仕様になっているとします。

  • 5000円以上または同一商品を5点以上購入で5%オフ
  • 毎月5のつく日(5、15、25日)にクーポン発行

すべての組み合わせを網羅すると以下のようになります。

それぞれのカバレッジを100%にするために必要なパターン数は、

  1. ステートメントカバレッジ: 1
  2. ブランチカバレッジ: 4
  3. 複合条件カバレッジ: 6

となり、条件が複雑であると、十分なテストケースを実行するためには事前にこうしたパターンの洗い出しをしておかないと、どのくらいのパターンがあるのか瞬時には判断できません。

特に金額計算や、サービスのコアな機能において複雑な条件がある場合は、複合条件カバレッジ100%を目指すのがいいでしょう。

ちなみに、後述しますが、PHPUnit を使ったコードカバレッジはステートメントカバレッジに基づいた率です。


同値クラスと境界値

ある条件を満たす値がひとつでないことがあります。上の例でいうと、「5000円以上」の条件を満たす値は、仮に購入可能上限金額が設定されていないとすれば、 無限 - 5000 個もの値が条件を満たすことになります。それらすべての値を入力値としてテストすることは無意味であり、条件を満たす値の群(値域)から代表的な値をひとつ選んでテストするのが一般的です。条件を満たす値域を「有効同値クラス」といい、反対に条件を満たさない値域を「無効同値クラス」といいます。

境界値は文字どおり境界にある値です。「5000円以上」という条件であれば、4999 と 5000 が境界値です。両方の値をテストすれば、もし仮に条件の記述を間違えて if ($price > 5000) と書いてしまっていたら、その間違いを発見できるでしょう。

議論

0 質問

このコースの評価は?