単体テストを徹底解剖!

単体テストとは-テスト工程全体における位置づけとその役割-

やまぐち

やまぐち

開発エンジニア/Perl/PHP/リーダー/ボールド歴4年

システム開発に従事している方であれば、少なからず『単体テスト』と言う言葉を耳にしたことがあると思います。

テスト工程中の一つのテスト方法として認識している方も多いと思いますが、実は単体テストには、結合テストやシステムテストと言った後、他の工程のテストとは比べものにならないくらい重要な役割があることをご存知でしょうか?


1.単体テストとは?

プログラムの作成が終わった段階で行うテストを「単体テスト」と言います。プログラムを手続きや関数といった個々の機能ごとに分割し、それぞれについて動作検証を行う手法のことを指します。

1-1.単体テストの意義

そもそもテスト工程とは、作り上げたシステムが一つの問題も内包しない完璧な状態にするために、不具合を洗い出す工程です。その出発点となる単体テストは、多くの不具合を取り除くことができる唯一の作業工程と言うことができます。正しく動作することは当然のことですが、単体テストは不具合を多く取り除くために、出せる限りの不具合を出し尽くすことを最大の目的としているのです。

ですので、単体テストで全ての不具合を取り除くことができれば、後工程のテストで不具合が発生することは、理論的にはあり得ない、と言う結論になります。「結合テスト」「システムテスト」で発生する不具合は、全て単体テストの不備に起因すると言っても過言ではありませんから。

また結合テスト以降は、「なぜ単体テストで不具合を見つけられなかったのか?」と言う原因究明や、不具合を発生させないための再発防止策等も併せて考えなければならないため、簡単に不具合対応ができなくなってしまいます。

関連記事

だからこそ、単体テストで不具合を出し尽くさなければならないのです。不具合を出し尽くすために、単体テストでの全パターンテストが必須になると言うこともお分かりいただけると思います。

1-2.単体テストの利点

単体テストは、プログラム完成直後の一番「どう動くべきか」が明確に記憶に残っているホットな時期に検証できる点、またテスト対象を他のプログラムから切り離して徹底的に検証できるところが利点として挙げられます。

その反面、テスト対象を動作させるための『付加コード』を作成する必要がある場合や、付加コードを含めた“テスト環境”を管理する「作業負荷」が大きくなってしまう、と言う欠点があることは否めません。

またこの作業負荷は、プロジェクトの規模が大きくなるほど、また改修を重ねて期間を経るほど増大する傾向にあります。

1-3.単体テストの課題

完成したプログラムが想定通り動作するかを確認する、と言う意味では、他のテストと確認する観点は同じですが、経験上、単体テストは軽視されることが多いように見受けられます。

それは、単体テストがプログラム作成と同じ『製造(実装)工程』に含まれるプロジェクトが多いことが考えられます。そのため、単体テスト項目が不具合の出ない(テストの意味がないと言っても良い)内容になってしまい、結果、後続の結合テスト等で大きな不具合が発見されることも少なくありません。

では効果的に品質を向上するために、どのように単体テストを進めれば良いのかを紐解いてみましょう。


2.単体テストの方法

単体テストは、テスト対象の内部構造に着目する「ホワイトボックステスト」とテスト対象の入出力に着目する「ブラックボックステスト」と言う2つのテスト方法があります。

またテスト対象となるプログラムに入力データを渡す「ドライバ」や、テスト対象から出力データが渡される「スタブ」を利用して単体テストを実施することもあります。

2-1.ホワイトボックステスト

ホワイトボックステストは、プログラムが想定通りに動作するかを確認するテストです。テスト対象の“内部”を意識し、どのような構造であるかを踏まえたテストケースを作ります。

何をどのようにテストするかと言う「テスト項目」は、分岐条件やエラー時のメッセージ出力設定など、プログラム内部の詳細情報について記載されている『詳細設計書』をベースに作成されます。ホワイトボックステストは条件分岐や繰り返し処理、例外処理など、あらゆる事態に対して動作確認を行えます。

プログラム上の記載ミスや処理間違いによるエラーなど、単純なミスがないかを検証できますが、ベースとなる詳細設計書の内容が間違っている場合は、ホワイトボックステストで不具合を検証することができない、と言うデメリットもあります。

このように、プログラムの構造やロジック、制御の流れなどが正常か否かを検証するため、「作り手側のテスト」とも言われています。

2-2.ブラックボックステスト

ブラックボックステストは、プログラムが要求仕様を満たしているかを確認するテストです。テスト対象の内部を意識せず“外部仕様”から、想定される入力やそれに対する出力結果を確認するテストケースを作成します。またテスト項目は、人の目に触れるプログラムの動作が記載されている『基本設計書』をベースに作成されるため、テスト結果は人間が合否判断しなければならないことも多くあります。

ブラックボックステストは性能の確認だけでなく、使い易さや分かり易いデザインかなど、ユーザーの目に見える範囲のテストも行うことからUIUXの観点での確認も含んでいます。そのため「ユーザー側のテスト」とも言われます。

2-3.ドライバとスタブ

ドライバ
  • テスト対象から見て『呼び出し元(親プログラム)』。
  • 入力データをテスト対象に渡す。
スタブ
  • テスト対象から見て『呼ぶもの(子プログラム)』。
  • 出力データをテスト対象から受け取る。

単体テスト実施時に、関係する全てのプログラムが揃っているとは限りません。とは言え、他のプログラムの完成を待っていては開発が進みませんから、一時的に“代用品”を作成してテストを行う必要があります。それが「ドライバ」と「スタブ」です。

ドライバから渡される入力内容をテスト対象で処理する、またはテスト対象から出力される結果をスタブに渡す、と言った入出力値の流れを確認することから、主にブラックボックステストで利用されます。


3.単体テストで確認すべきところ

単体テストのテスト方法は「ホワイトボックステスト」と「ブラックボックステスト」の2種類があることは先に述べた通りですが、単体テストは、前提として「ホワイトボックス」と「ブラックボックス」両面のテスト観点が必要であり、その全パターンを確認する必要がある、と言うことが最も重要です。

ホワイトボックステストとブラックボックステストの確認すべき点は、それぞれ下記の内容になります。

ホワイトボックステスト

  • プログラム内の変数に正しい値が設定されているか
  • プログラム中の分岐条件が正しいか
  • プログラム中の繰り返し処理が無駄なく正しいか

ブラックボックステスト

  • プログラムへの入力値は想定されているものか
  • プログラムから出力される値は想定通りか

ホワイトボックステストは、あくまでプログラムの中の確認になっており、その結果からそのプログラムに問題がないと判断します。一方ブラックボックステストは、プログラムを機能として捉え、要求された仕様通りの入出力を満たしているかを確認します。

例えば『納品書』のような帳票を発行するプログラムのタイトル部分に関する単体テストを実施する場合、ホワイトボックステストでは、

  • タイトルを格納する変数に「納品書」という文字列が設定されているか
  • タイトルを印字する位置情報を格納する変数に「位置(座標)」が正しく設定されているか
  • タイトルの色やフォント、サイズを格納する変数に正しく値が設定されているか

と言ったプログラム内部を確認しますが、ブラックボックステストは、

  • 納品書が出力されるか
  • 帳票のタイトルに「納品書」と印字されているか
  • タイトルの印字位置は正しいか
  • タイトルの色やフォント、サイズが正しいか

など、実際に出力する内容を確認します。どちらのテストも確認すべきことは『タイトルが正確に出力(印字)されるか』ですが、それぞれ確認する観点が異なることが見て取れるのではないでしょうか。


4.他のテストフェーズと単体テストとの関係

単体テスト以外のテストフェーズには、単体テスト完了後に実施するものや、それぞれのテストフェーズの確認観点の一つとして実施するものもあります。それぞれのテストタイミングやテストの概要は下記の通りです。

4-1.結合テスト

結合テストは、複数のプログラムやモジュールを同時に稼働させ、モジュール同士を結合した際に、意図した通り動作するかを確認します。

ただ動作するか、をテストするのではなく、オペレーションと動作の組み合わせが正しいか、仕様通りに機能しているかについても検証します。

前段階である単体テストによって、個々で正しく動作することが確認された機能やモジュールを対象としていますので、単体テストで実施したテスト項目は、結合テストではほとんど行わないか、軽く確認するレベルに留めることが一般的です。

4-2.システムテスト

システムテストは「総合テスト」とも呼ばれ、実際のシステムの利用状況を想定して、本番と同じ環境で多角的にテストを行います。

システムの一部だけでなく、システム全体(ハードウェアも含めて)のテストが実施されるため、開発環境では分からなかった不具合や、ハードウェア環境に関係する不具合も検出できます。

「単体テスト」や「結合テスト」を終えた開発の最終段階(納品前)に全体を通して確認することで、システム品質を担保し、納品後の残存リスクをできるだけ減らすことを目的としています。

4-3.受入テスト

受入テストとは、納品されたシステムやソフトウェアに対して、ユーザー企業側が、導入しても問題ないかを判定するためのテストです。

機能・性能が要件に合致しているか、業務として利用できるシステムであるかなど、最終的な確認を行います。仮に、業務に適合していない、あるいはそもそもユーザー要件が妥当ではなかったと判断された場合、追加費用を払って改修すべきか否かを検討します。

4-4.回帰テスト

回帰テストとは、プログラムの一部分を変更したことで他に影響が出ていないかを確認するためのテストです。

プログラムやシステムは一つ一つの機能が複雑に絡み合っていることが多く、ある不具合を修正したら隠れていた別の不具合が見つかったり、正常に動いていた機能が動かなくなったりすることもあります。

関係ない部分に思えても想定外の不具合が発生することもありますから、プログラムに何らかの修正や変更を加えた時は、回帰テストは欠かせません。


5.単体テスト自動化ツールの紹介

単体テストを自動化するツールには、『テストフレームワーク』と呼ばれるものがあります。よく知られているのはJava用の『JUnit』ですが、他プログラミング言語用にもフレームワークが存在します。

プログラミング言語テストフレームワーク
JavaJUnit
PHPPHPUnit
C/C++CppUnit
.NETNUnit

これらを総称して『xUnit』と言います。xUnitフレームワークは、テスト実行およびテスト結果の検証機能を提供します。また一つ一つのテストケースは全てコードとして作成されるので自動実行が可能となりますが、テストケース自体は自分で作成しなければなりません。

前に述べた通り、単体テストは全てのテストケースを実行する必要がありますので、バッチ等で自動化することができれば、多数のテスト項目を漏れなく実行することができ、より高い効果が期待できます。

例えば、夜間バッチで全てのテストケースを実行しておくと、前日の修正によって既存コードにエラーが発生していないかを確認(回帰テスト)することが可能となります。


6.まとめ

「単体テストはほどほどに、不具合は全て結合テストで洗い出す」と言うプロジェクトもよく見受けられます。開発スケジュールやテスト実施者と言った人的リソースの確保が難しく、こう言った方針を取らざるを得ないのかも知れません。

ですが、単体テストを軽視したことによって後続の工程で重篤な不具合対応に迫られ、結果開発スケジュールがよりタイトなものになってしまった、と言うこともよくあることです。

また単体テストはテストケースが多く、全て人間の手で実行するのは大変な時間を要しますが、必ずしも人の目を必要とする確認観点だけではないことも事実です。適宜自動化ツールを活用しながら、しっかりとした単体テストを実行することを心掛けてみてください。そうすれば、作成したプログラム品質が格段に向上するのを目の当たりにすることでしょう。

私たちは、全てのエンジニアに市場価値を高め自身の望む理想のキャリアを歩んでいただきたいと考えています。もし、今あなたが転職を検討しているのであればこちらの記事をご一読ください。理想のキャリアを実現するためのヒントが見つかるはずです。

『技術力』と『人間力』を高め市場価値の高いエンジニアを目指しませんか?

私たちは「技術力」だけでなく「人間力」の向上をもって遙かに高い水準の成果を出し、関わる全ての人々に感動を与え続ける集団でありたいと考えています。

高い水準で仕事を進めていただくためにも、弊社では次のような環境を用意しています。

  • 定年までIT業界で働くためのスキル(技術力、人間力)が身につく支援
  • 「給与が上がらない」を解消する6ヶ月に1度の明確な人事評価制度
  • 平均残業時間17時間!毎週の稼動確認を徹底しているから実現できる働きやすい環境

現在、株式会社ボールドでは「キャリア採用」のエントリーを受付中です。

まずは以下のボタンより弊社の紹介をご覧いただき、あなたの望むキャリアビジョンをエントリーフォームより詳しくお聞かせください。

コメント

公式アカウントLINE限定!ボールドの内定確率が分かる無料診断実施中
公式アカウントLINE限定!
ボールドの内定確率が分かる無料診断実施中