今回作成するAPIは、前述したようにアプリをGUIからではなく、プログラムから操作するためのユーティリティである。APIの目的は「操作」であり「テスト」ではない。逆にテスト・シナリオの目的は「テスト」であり「操作」ではない。少なくともこれがはっきり分離されるように設計しなければならない。また、アプリの内部実装を知らないテスト担当者でも、APIを使ってテスト・シナリオを実装できるようにすべきである。
ここで公開するインターフェイスの品質で、テスト・シナリオの可読性が決まる。逆説的ではあるが、良いテスト・シナリオが書けるなら、それは良いAPIだといえる。この辺は「ユニット・テストが作りやすいコードが、一般的に良いコードになる」という理論に近い。とはいえ、一度で決定できるような簡単なものではないので、プロダクト・コード同様、リファクタリングを繰り返しながら、インクリメンタルに質を高めていくべきである。
本稿では、APIは.NETのDLLとして実装する。このようにしてCLS(共通言語仕様)に準拠していれば複数の.NET系言語から使用できるので、テスト・シナリオを記述するときに、テスト担当の得意な言語を選択できるというメリットがある。
実装方法は自由で、とにかく対象アプリをインターフェイスの要求どおりに操作できればよい。GUIコントロールを操作することで、要求に応えてもよいし、特殊なテスト用インターフェイスを対象アプリに仕込んでそれを呼び出してもよい。
次章以降ではサンプルを使って、この実装方法を説明する。
アジャイル・コミュニティでも、簡易スクリプトなど、GUI以外から操作する手段を用意して、受け入れテストを自動化する方法を紹介している。
また、ATDD(Acceptance Test Driven Development: 受け入れテスト駆動開発)として、先にテスト・シナリオを書く手法もある。先に受け入れテストを書いた場合、テスト対象のロジックはスクリプトからも呼び出せる必要があり、必然的にGUIから分離されるという考え方である。
本稿で紹介している方法は簡易スクリプトではなくAPIを用いてテスト・プロセスからアプリを操作するというものだが、本質的には同じアプローチである。
この手法になじんできたら、ATDDにもチャレンジしてみてはいかがだろうか。
今回、サンプルとして作成するアプリのGUIは次のような画面にする。これはWindowsフォーム・アプリとして作成している。
この社員管理アプリがテスト対象となる。GUIの動作仕様は以下のとおり。
そのコードは、次のとおり。メイン・ウィンドウとして表示されるWindowsフォームはMainFormクラスに実装する。ビジネス・ロジックはManagementSystemクラスに実装する。今回は、ManagementSystemクラスを結合状態で受け入れテストすることを目標とする。なお、この内容であれば、本来、ユニット・テストで十分なのだが、そこはサンプルということでご容赦願いたい。
using System;
using System.Windows.Forms;
using System.Collections.Generic;
namespace EmployeeManagement
{
// GUI。
public partial class MainForm : Form
{
ManagementSystem system = new ManagementSystem(); // ビジネス・ロジック用のクラス
public MainForm()
{
InitializeComponent();
}
// 追加ボタン押下。
private void buttonAdd_Click(object sender, EventArgs e)
{
if (system.Add(textBoxName.Text, textBoxAge.Text, textBoxPosition.Text))
{
//成功した場合はテキストボックスを空にする。
textBoxName.Text = textBoxAge.Text = textBoxPosition.Text = string.Empty;
}
}
// 検索ボタン押下。
private void buttonFind_Click(object sender, EventArgs e)
{
EmployeeData hit = system.Find(textBoxName.Text);
// GUIに表示。
if (hit != null)
{
//ヒットした場合はデータを表示。
textBoxName.Text = hit.Name;
textBoxAge.Text = hit.Age.ToString();
textBoxPosition.Text = hit.Post;
}
else
{
//失敗したらテキストボックスを空にする。
textBoxName.Text = textBoxAge.Text = textBoxPosition.Text = string.Empty;
}
}
}
// 社員データ。
[Serializable]
public class EmployeeData
{
public string Name { get; set; }
public int Age { get; set; }
public string Post { get; set; }
public EmployeeData(string name, int age, string post)
{
Name = name;
Age = age;
Post = post;
}
}
// ビジネス・ロジック。
public class ManagementSystem
{
List<EmployeeData> allData = new List<EmployeeData>();
// 追加。
public bool Add(string name, string ageString, string post)
{
// 数値化できない場合はNG。
int age;
if (!int.TryParse(ageString, out age))
{
return false;
}
// 名前の重複は許容しない。
if (Find(name) != null)
{
return false;
}
allData.Add(new EmployeeData(name, age, post));
return true;
}
// 検索。
public EmployeeData Find(string name)
{
foreach (EmployeeData element in allData)
{
// 名前で検索。
if (element.Name == name)
{
return element;
}
}
return null;
}
}
}
テスト・シナリオは最初に例示した「リスト1 シンプルなテスト・シナリオ」を使う。
実行環境はVisual Stuido 2010のテスト・プロジェクトを使用する。
今回はテスト・プロセスで動作するクラスとして「EmployeeManagementApp」を作成する。このクラスは、社員管理アプリの起動/終了/操作を目的とする。その実装方法は下記のようにいくつか考えられる(※最後の「Codeer.Friendly」についての詳細は後述するが、今回のケースのような受け入れテストを簡単に実装できるようにするために筆者の会社が開発して無料で公開しているライブラリである)。
そこで、次章以降でそれぞれの実装サンプルを例示する。
Copyright© Digital Advantage Corp. All Rights Reserved.