HOME > ソフテックだより > 第121号(2010年9月1日発行) 技術レポート「品質向上の取り組み 〜単体試験編〜」

「ソフテックだより」では、ソフトウェア開発に関する情報や開発現場における社員の取り組みなどを定期的にお知らせしています。
さまざまなテーマを取り上げていますので、他のソフテックだよりも、ぜひご覧下さい。

ソフテックだより(発行日順)のページへ
ソフテックだより 技術レポート(技術分野別)のページへ
ソフテックだより 現場の声(シーン別)のページへ


ソフテックだより 第121号(2010年9月1日発行)
技術レポート

「品質向上の取り組み 〜単体試験編〜」

1. はじめに

以前、私が携わっていた組み込み用のソフトウェア開発では、モジュールの組み合わせ確認時に多くの不適合が発生し、なかなか品質が安定しない状況が続きました。調査してみると、原因のほとんどはモジュール単体での確認で発見されるべき不適合、という状況でした。
そのため、まずモジュール単体での完成度を高め、後工程に不適合を残さないようにする必要があると考え、レビューの強化、単体試験(※)の実施を行うことにしました。
今回はその時に実施した単体試験について紹介します。

2. 単体試験について

2-1. 単体試験の方法

モジュール単体での完成度を確認するため、単体試験ではそれらを構成する関数1つ1つに対して試験を行うことにしました。それぞれの関数に対して入力と出力のパターンを決め、試験を行うことで、これまで発生していたような不適合を、早い段階でつぶすことが出来ると考えました。

2-2. 単体試験項目書作成

試験を実施する前に、まず試験項目書を作成します。今回行う単体試験では、関数1つ1つに対して入力と出力を決めていきますが、いくつか注意点があります。

(1). 目標コード・カバレッジを設定する

事前に、目標とするコード・カバレッジを設定し、その目標を達成できるような入力値を設定します。

【コード・カバレッジ(Code Coverage)とは】

コード・カバレッジとは、プログラムのロジックをどの程度網羅したか、を表す指標(基準)です。
よく使われる基準は次の通りです。

C0:
命令網羅(ステートメントカバレッジ Statement Coverage)
プログラム内の命令文をどの程度網羅したかをあらわす基準です。

C0:命令網羅イメージ
図1. C0:命令網羅

図1の例では、①の確認を実施することで、C0カバレッジ100%となります。

C1:
分岐網羅(ブランチカバレッジ Branch Coverage)
プログラム内の分岐をどの程度網羅したかをあらわす基準です。

C1:分岐網羅イメージ
図2. C1:分岐網羅

図2の例では、①と②それぞれの確認を実施することで、C1カバレッジ100%となります。

C2:
条件網羅(コンディションカバレッジ Condition Coverage)
プログラム内の条件をどの程度網羅したかをあらわす基準です。

C2:条件網羅イメージ
図3. C2:条件網羅

図3の例では、①〜④それぞれの確認を実施することで、C2カバレッジ100%となります。

上記以外に、複数条件網羅(マルチコンディションカバレッジ)や経路網羅(パスカバレッジ)などもあります。

今回のプロジェクトでは、C1カバレッジを基準としました。
これは、問題となっているコーディングミスのほとんどは、作成したコードを1度でも確認していれば防げた内容であること、さらに、分岐判断の確認も出来れば、品質は安定するだろうと、考えたためです。C2カバレッジを基準とすることも考えましたが、上記の考えや、コスト・スケジュールの兼ね合いもあり、C1カバレッジを基準としました。

(2). 入出力は漏れなく

試験項目書を作成する際、まず入力項目と出力項目を抜き出しますが、入力項目や出力項目に漏れがあっては意味のある試験はできません。そのため、漏れには注意が必要ですが、見逃しやすいものもあります。

入力では、引数はすぐに思いつきますが、外部変数や、試験対象の関数内からコールする関数の戻り値なども入力として書き出す必要があります。
出力は、関数の戻り値だけでなく、外部変数や、試験対象関数内からコールする関数へ渡す引数の値も出力項目となります。

(3). 入力値は、同値分割を意識する

入出力の項目が出揃ったら、実際にどのような入力値で試験を行うか、を決めていきます。
このとき、同値分割・境界値分析を用いて、入力値を決めます。

【同値分割・境界値分析とは】

同値分割とは、起こりえる全ての事象をいくつかのグループに分けることです。
このグループを同値クラスと呼びます。

境界値分析とは、同値クラスから代表値を選ぶ時に、境界値付近の値を選ぶ考え方です。これは、プログラムで不等号を使用している部分でのバグが多い、という経験則から来ています。

例えば、ある引数の値が1〜10までの整数を正しい値として処理する場合の入力値を決めることとします。
まず同値クラスへの分割ですが、0以下のグループ、1〜10のグループ、11以上のグループに分けられます。
次に同値クラスから代表値を選びますが、境界値を選ぶと、0、1、10、11の値が必要になります。さらに同値クラスの境界値以外の値も選ぶことで、より正確な試験を行うことが出来ます。
この例での入力項目は、-10、0、1、5、10、11、100などの入力パターンとなります。(緑字は同値クラスの代表値、青字は境界値)

実際の試験項目書は、図4 試験項目書サンプルのようになります。こちらもわかりやすく、同値クラスの代表値は緑字、境界値は青字で表記しています。

(4). 入力値は、一意の値を宣言する

入力値は一意の値を宣言する必要があります。
これは例えば、項目書の入力欄に「正常値を入力」や「異常値を入力」と書いてはいけないという意味です。
手を抜くとこのように書きたくなる場合もありますが、正常値を入力、と書いてしまうと、全ての正常値に対して試験した(保障した)ことになってしまいます。

このような注意点を意識しながら試験項目書を作成していきます。
作成した試験項目書は、下図のようになります。

試験項目書サンプル
図4. 試験項目書サンプル

2-3. 単体試験実施

試験項目書が完成したところで、作成した試験項目書に従い試験を行っていきます。

試験をする際、正常値あれば比較的容易に入力値を作り出せると思いますが、異常値などは容易に作り出せない場合があります。そのような場合には、スタブやドライバを作成し、試験します。(正常値であっても、作成できるならスタブ・ドライバを作成し、使用します。)

【スタブ(Stub)・ドライバ(Driver)とは】

スタブとは、試験対象モジュールの下位にあたるダミーモジュールです。
試験対象から呼び出され、任意の戻り値や外部変数操作、引数操作などを行います。

ドライバとは、試験対象モジュールの上位に当たるダミーモジュールです。
試験対象へ任意の引数を指定して、呼び出します。

スタブ・ドライバ
図5. スタブ・ドライバ

スタブ・ドライバを作成することで、以下のようなメリットがあります。

  • モジュール単位(関数単位)で試験が可能
  • 試験を並列に実施することが可能
  • 稀なエラーケースを確実に発生させることが可能
  • 再テストが容易

2-4. 単体試験実施結果

作成した試験項目書の内容を確認し、問題なければ試験は完了し、次の工程に進みます。問題がある場合には、修正後、再試験を行います。

今回のプロジェクトでこの試験を実施し、モジュール単体での品質が問題無いことを確認し、次の工程に進みました。
すると、コーディングミスのようなつまらない不適合は全く発生せず、結合後の工程は、非常にスムーズに進められました。
それまでの悩みであった、品質の低い状態でモジュールを結合してしまい、無駄な時間を消費してしまう問題から、開放されました。

3. 終わりに

今回は、以前の開発で導入した単体試験について、紹介しました。

以前の開発では組み合わせ時に問題が発生し、品質を確保するためにスケジュールが遅延し、さらにそれに伴うコスト悪化を繰り返してしまいました。しかし今回の単体試験を行うことにより、不適合の早期発見ができ、スケジュール遅延やコスト悪化を発生させずに開発を完了させることが出来ました。
ただし、組み合わせ以降のスケジュール遅延やコスト悪化は防ぐことは出来ましたが、単体試験工程では予定より3割程多くの時間をかけました。関数1つ1つというこれまでより細かい確認を実施したため、試験項目書作成や試験自体にも時間がかかります。これは仕方ないところもあるかも知れませんが、より効果的に試験を実施する方法については、今後の課題と考えています。
今回紹介したような単体試験では、試験項目や試験データを自動的に生成するツールもありますので、それらの導入も含めて検討し、今後さらなる品質向上に努めて行きたいと考えています。

(T.O.)

[注釈]
『単体試験』は、別名ユニットテストや、内部試験など様々な呼び方がありますが、ここでは単体試験と呼びます

関連ページへのリンク

関連するソフテックだより

ページTOPへ