単体テストとは何か?テストの目的と進め方、注意点などをまとめて解説

2020年12月23日

単体テストの目的

単体テストとはモジュールが期待したとおりの動作をするかの確認を行うテストです。
この工程ではプログラムロジックの誤りの検出、及び修正を行います。
単体テストが不十分な状態で後工程のテストに入った場合には、複雑な発生条件の不具合が検出されにくい、また不具合の原因調査に時間がかかるなどの問題が起こり、開発プロジェクトのスケジュールに影響が出ることもあります。
つまり、単体テストの目的とは、コーディングフェーズで埋め込まれた不具合を早期に修正し、後工程のテスト効率を上げることです。

単体テストの進め方

単体テストは以下のような手順で進めていきます。

  • テスト計画
  • テスト設計
  • テスト準備
  • テスト実施
  • 不具合修正、再テスト

ここからはこれらの内容に解説を加えていきます。

テスト計画

新規開発、大規模な開発では、単体テストフェーズだけでもある程度の期間、工数が必要なため、
最初にテスト計画を作成します。これはテスト担当者が行うものではなく、プロジェクトとして下記内容を決めます。

  • テスト対象、範囲
  • テスト方法
  • エビデンスの取り方
  • スケジュール
  • 工数
  • 担当者

テスト設計

テスト計画で決められたテスト方法にしたがってテスト設計を行います。
単体テストでは、ホワイトボックステストを行うか、ブラックボックステストを行うかが大事なポイントです。
両者はそれぞれの特徴を生かして使い分けをしても構いません。例えば、全体のモジュールテストではブラックボックステストを行い、新規に追加したモジュールに対してはホワイトボックスをあわせて行うなど、費用対効果を考えてテスト方法を決めます。
テスト設計の成果物としてはテストケースを作成します。

テスト準備

単体テストは各モジュール単位のテストを行うため、そのモジュールを動作させるための準備が必要となります。

ドライバ

テスト対象となるメソッドを呼び出すプログラムを作成します。これをドライバと呼びます。

スタブ

テスト対象のモジュールから呼び出す関数に対して固定値などを返すダミーモジュールを作成します。
このダミーモジュールをスタブといいます。

テスト実施

これで準備が整いましたので単体テストを開始します。作成したテストケースをひとつひとつ検証します。
テストの結果がOKの場合は、そのエビデンスを取っておきます。
また、テスト結果がNGの場合、つまり想定以外の動作が見つかったときにはその不具合の内容を記録して下さい。

不具合修正、再テスト

単体テストで見つかった不具合については、プログラムコードを修正して再テストを行います。
そのときに大事な事は、修正したコードの影響範囲をチェックすることです。ある不具合の修正のために、それまで正常に動作していた部分に不具合が生じる場合もあります。
そのため、コードの修正を行ったときには、その影響範囲であるテストケースに対して再テストを行います。

テストの手法の概観

ホワイトボックステスト

テスト対象のモジュールを"箱”に例えたときに、その箱の中身、つまりプログラム構造を理解してテストを行うことをホワイトボックステストと言います。このテストは単体テストで用いられることが多く、また、プログラムをコーディングした担当者が行うことが一般的です。
単体テストでよく使われるテスト技法を下記に挙げます。

制御フローテスト

ひとつの処理に対するプログラムの動作に従って検証を行います。
制御フローの数は膨大になるため、テスト範囲を限定して実施します。

  • 命令網羅:全ての命令を少なくとも1回は実行します
  • 分岐網羅:条件分岐について、すべての分岐を1回は実行します
  • 条件網羅:条件分岐について、その条件の組み合わせのすべてを1回は実行します

データフローテスト

モジュール内で使用されるデータや変数処理の流れに沿って検証を行います。
変数データが「定義」「使用」「消滅」するような処理に着目して想定した処理が正しく実行されるか、無駄なデータ処理をしていないかなどを確認します。

ブラックボックステスト

ブラックボックステストはホワイトボックスと対照的なテスト方法になります。つまり、モジュールのプログラム構造を考慮せずに実施するテスト技法です。
そして、ソフトウェアのテストはほとんどブラックボックステストを基本とします。単体テストの場合は、プログラム構造を着目したホワイトボックスの実施が可能ですが、その後工程である、結合テスト、統合テスト、システムテストにおいては、全体のプログラム構造を考慮したテスト設計はほぼ不可能となります。
ブラックボックステストでは、どのような入力値でテストするかの設計が大事です。代表的な設計技法を下記に挙げます。

同値分割法

入力を同じ処理を行うグループに分割し、グループ内の入力を同等に扱う技法です。
同値分割したグループは有効なデータだけではなく、無効なデータにもあります。
入力されるデータをすべてテストするのは無理なため、入力値をグルーピングし、各グループの代表となる値でテストを行います。また、同値分割したグループを「同値クラス」と呼びます。

境界値分析法

同値クラスの境界値付近には不具合が多く発生します。それは、コーディングにおいて、境界値を正しく認識して、その境界値で処理を分けるコードの記述が必要なためです。
このような観点から、境界値とその前後の値でテストを行う方法が境界値分析法です。
具体的な例としては、0から100までの入力があり、50以上で処理内容が変わる場合には、-1、0、49、50、100、101の入力値でテストを行います。
他のテストケース設計技法として「原因結果グラフ技法」「エラー推測」がありますが、実際に使われることはかなり少ないのではないかと思われます。

どこまでテストすべきか

これは、ソフトウェアのテストでは常につきまとう難しい課題です。
開発スケジュールがあり時間切れとなったので、次のテスト工程に進もう、というのはよくありません。
何をもって単体テストを終了とすればよいのか、これは、開発プロジェクトとしてきちんと決めておくべきです。
一般的なソフトウェア製品の開発であれば、単体テストとして、「書いたコードはすべて一度は動かしてみる」を最低限の基準にすることをおすすめします。
それ以上のテストは、開発するソフトウェア製品に求められる品質に応じて、テスト計画の中で決めると良いでしょう。

エビデンスを取る

テスト結果のエビデンス(証拠)をどのような形式(画面キャプチャー、ログファイルなど)で取るかはテスト計画で決めておきます。
エビデンスを残す目的としては下記になります。

  • テスト実施結果の証跡
  • テスト結果のレビューのため
  • 後工程のテスト、及びリリース後に発生した不具合に対する原因分析のため

エビデンスを取る作業は工数もかかりますので、テスト担当者は本当に必要なのか、と考えてしまいます。
しかし、テスト結果を合格と判断するときに、何をもって正常終了と判断したかの報告は必要です。
理想は、それほど工数をかけることなく、処理結果の証跡を残すことです。
後から必要になったときに、調査できる情報だけは記録しておいて下さい。

単体テストの自動化

単体テストは非常に大事な工程であり、しっかり実施することで後工程のテストでの不具合発生を減らすことができます。
ただし、課題としては大きな工数が必要とされることです。その解決方法のひとつにテストの自動化があります。
テストの自動化のメリットには下記のようなものがあります。

  • 繰り返しテストでの工数削減
  • テスト品質の向上
  • 単体テストのスキルが十分でなくてもテスト実施可能
  • 開発プロジェクトとしてのコスト削減

しかし、テストの自動化のためには、ツール導入などの環境構築、運用ルールの整備、また継続的なメンテナンスなど、かなりのパワーがかかるのも事実です。それでも、成功事例も多くありますし、自動化ツールも強力なものが出ていますので、自身の開発プロジェクトで使えそうなものはないか、検討する価値は十分にあります。

単体テストは面倒な作業か

単体テストは面倒な作業でしょうか? ほとんどのソフトウェア開発者は「その通り」と答えるのではないでしょうか。
日頃、単体テストをきちんと実施している開発者であればなおさらです。

ソフトウェア開発の基本として、問題点、不具合はできるだけ上流で修正すること、というセオリーがあります。
修正が下流になるほど、手戻りが大きくなり、修正工数も大きくなってしまいます。
したがって、コーディングに起因するバグは単体テストですべて取る、ということが理想です。
単体テスト以降の工程からは他のプロジェクトメンバーとの共同作業になりますので、単体テストを終えたモジュールこそ、自身の成果物として自信を持ち後工程に投入しましょう。その自信の裏付けとなるものが非常に面倒な単体テストです。
そのため、煩わしい作業ではあるものの、手を抜くことなく、単体テストを実施していきましょう。