「ソフテックだより」では、ソフトウェア開発に関する情報や開発現場における社員の取り組みなどを定期的にお知らせしています。
さまざまなテーマを取り上げていますので、他のソフテックだよりも、ぜひご覧下さい。
ソフテックだより(発行日順)のページへ
ソフテックだより 技術レポート(技術分野別)のページへ
ソフテックだより 現場の声(シーン別)のページへ
私はWindowsアプリケーション開発を担当する機会が多い入社15年超の社員です。今回のソフテックだよりでは、Microsoft Visual Studioに標準で搭載されているユニットテストのフレームワーク MSTestを使った単体試験についてご紹介させていただきます。
単体試験(内部試験やユニットテストと呼称されることもあります)は、一般的にプログラムを構成するモジュールが設計どおり正しく動作することを検証する対応になり、モジュール製作者が対応することが多いのが特徴です。試験対象としては、プログラム構成単位となるクラスなどのインターフェース(関数やメソッド)が対象となる場合が多いと思います。
以前『ソフテックだより第121号:品質向上への取り組み〜単体試験編〜』でも取り上げさせていただきましたように、個々のモジュールの品質が低いと結合試験(組合試験やシステムテストと呼称されることもあります)の時にシステム品質が安定せずに大きな問題となります。
ユニットテストのフレームワーク(ツール)を活用することで、単体試験の確認を自動化させるアプローチが可能になりますが、対応イメージや特徴などを記載していきます。
MSTestは、Microsoft Visual Studioに標準搭載されているユニットテスト用のフレームワークです。
C++、C#、または Visual Basic で作成されたマネージアセンブリ(*.dll、*.exe)の参照から、クラスのメソッド呼び出し、適切なパラメータを渡して、戻り値が期待された値かを確認します。
MsTestにおける、単体試験の対応方法をTargetApp(ターゲットアプリケーション)のテストプロジェクト作成→Calculateクラスモジュールのテスト実行を例にして、以下に簡単に示します。
図1. MSTest:対応イメージ例
(1) ユニットテスト用のプロジェクトを作成
図2. MSTest:テストプロジェクトの作成
(2) テスト対象 の参照を追加
↓↓↓
図3. MSTest:テストプロジェクトへのテスト対象 参照追加
(3) テストコードを記述
下記の例では、TargetApp プロジェクトに定義されたCalculateクラスのテストコード記述例を示します。
※ Calculate クラスの下記3つのメソッドの単体試験を行うテストコードになります。
/// <summary>
/// ユニットテスト1 クラス
/// </summary>
[TestClass]
public class UnitTest1
{
/// <summary>テスト対象クラス</summary>
static Caluculate _Target = null;
/// <summary>テストデータ</summary>
static double[] _TestData = new double[] { 5.67, 1.23, 4.56, 3.45, 2.34 };
/// <summary>シグマ計算 期待値</summary>
static double _TestExpectedSigma = 17.25;
/// <summary>平均計算 期待値</summary>
static double _TestExpectedAverage = 3.45;
/// <summary>標準偏差計算 期待値</summary>
static double _TestExpectedStandardDev = 1.56977705423413;
/// <summary>
/// 最初のテスト実行前の処理
/// </summary>
/// <param name="testContext">[in] テストコンテキスト</param>
[ClassInitialize()]
public static void ClassInitialize(TestContext testContext)
{
//テスト対象インスタンス生成
_Target = new Caluculate();
}
/// <summary>
/// 全てのテスト実行後の処理
/// </summary>
[ClassCleanup()]
public static void ClassCleanup()
{
_Target = null;
}
/// <summary>
/// 各テストを実行する前の処理
/// </summary>
[TestInitialize()]
public void TestInitialize()
{
}
/// <summary>
/// 各テストを実行した後の処理
/// </summary>
[TestCleanup()]
public void TestCleanup()
{
}
/// <summary>
///Sigma のテスト
///</summary>
[TestMethod()]
public void Calculate_Sigma_Test()
{
double dActual = _Target.Sigma(_TestData);
Assert.AreEqual(_TestExpectedSigma, dActual);
}
/// <summary>
///Average のテスト
///</summary>
[TestMethod()]
public void Calculate_Average_Test()
{
double dActual = _Target.Average(_TestData);
Assert.AreEqual(_TestExpectedAverage, dActual);
}
/// <summary>
///StandardDev のテスト
///</summary>
[TestMethod()]
public void Calculate_StandardDev_Test()
{
double dActual = _Target.StandardDev(_TestData);
Assert.AreEqual(_TestExpectedStandardDev.ToString("F10"), dActual.ToString("F10"));
}
}
図4. MSTest:テストコードの記述例
(4) テストコードの実行
図5. MSTest:テストプロジェクト実行結果
上記のような対応方法の流れで、「テストコード」と呼ばれる単体試験用のプログラムコードを書くことにより単体試験を自動実行できます。
ユニットテスト用のフレームワークは、MSTest以外にもサードパーティでいくつか提供されているものがあります。統合開発環境のVisual StudioでWindowsアプリケーションを開発する際には、ほとんどのフレームワークがユニットテスト用のプロジェクトを作成することで簡単に単体試験を行えるようになるので重宝します。
MSTestに限りませんが、ユニットテスト用のフレームワークを活用する上での利点として、下記のような点が挙げられます。
(1) 単体試験用のプログラムコードを書くことで、テスト対象の問題に気づく機会になる。
(2) 入力と期待値が明確で、様々なテストデータパターンが想定される試験を的確に試験できる。
(3)モジュールに変更を加えずに試験できる。
(4) ユニットテスト環境の再利用性。
テストフレームワーク利用時の注意点について下記に示します。
(1) 入力に対する期待値が一意に決まらないものは試験対象にできない。
(2) UI操作/表示周りの確認は試験対象にできない。
(3)やみくもにテスト対象にすると対応コストが膨大になる。
MSTestでは、複数のユニット試験を組み合わせて順番に単体試験を行うことも可能です。
(1) 複合的なテストパターンの試験を実行する。
図6. MSTest:順序指定テストの追加
(2) テストパターンデータを外部ファイルから読み込む。
(3) 処理時間に関するテストが可能。
using System.Diagnostics; //Stopwatchクラス利用
/// <summary>
///StandardDev の処理時間テスト
///</summary>
[TestMethod()]
public void Calculate_StandardDev_TestTime()
{
Stopwatch swTime = new Stopwatch();
//ターゲットモジュールの処理時間
swTime.Start(); _Target.StandardDev(_TestData);
swTime.Stop();
//処理時間が100msを越えていればエラー
if (swTime.ElapsedMilliseconds > 100)
{
Assert.Fail("Calculate_StandardDev(...) 処理時間100msオーバ");
}
}
図7. MSTest:テストコードの記述例 (処理時間テスト)
WindowsアプリケーションでMSTestを活用する方法についてご紹介させていただきました。
これまで単体試験を人手で行っていたことで、時間の制限からデータパターンの網羅率が低い問題や、単純作業の連続に起因した確認ミスや見逃しの問題などがあり、単体試験以降のフェーズで不具合が発生することもありました。
テストフレームワークを活用することで、この手の問題は減らせる可能性があり、適切な用途に利用することでシステムの品質を向上させることができると思います。
今回のソフテックだよりで取り上げさせていただいた内容が、Windowsアプリケーション開発時の品質向上の手助けになれば幸いです。
(M.S.)
関連ページへのリンク
関連するソフテックだより