ダウンロード CsTdd07.zip (474.5 KB)
業務アプリケーションの開発では、データベースと付き合わないわけにはいきません。しかし、テストファーストはやりにくいものです。今回は、データベースにアクセスするコードを、TDDでどうやって扱うのかをご紹介します。
-
- Page 1
はじめに
データベースを読み書きする部分のユニットテストがやりにくいのには、いくつか理由があります。
- 複数人でテストを同時に実行すると、競合する
- データベースを使ったテストは、時間が掛かる
- データベース内のデータが変わると、テストが失敗する
1番目は、各自の開発環境にテスト用のデータベースを用意することで、解決できます。2番目の問題は、データベースにアクセスするコードをロジックから分離して、データベースに実際にアクセスするテストケースを減らすことで、改善できます(ロジックのテストにはモックやダミーを使います)。3番目は、テストのたびにデータベースの内容を初期化することが基本になりますが、そうするとテストに長い時間が掛かるようになってしまいます。
今回は、ビジネスロジックの開発時にモックやダミーを使いやすくするにはどうするか、また、テスト時にデータベースの内容を安定させるにはどうしたらよいかを、考えてみます。
対象読者
- TDDに興味をお持ちの.NET Frameworkの開発者。
必要な環境
サンプルコードを試してみるには、C# 2010(Expressで可)またはVisual Studio 2012(Expressで可)、およびNUnit 2.6とSQL Server Compact 3.5が必要です。本稿執筆時点では、下記から入手できます。
-
C# 2010 Express: Microsoft Visual Studio Express
Visual Studio Express 2012: Visual Studio Express 2012 for Windows Desktop -
NUnit 2.6: NUnit V2 2.6.1
NUnitのインストール手順: NUnit 2.5 の導入 Step by Step(筆者サイト、旧バージョンでの説明ですが基本的に同じです) - SQL Server Compact 3.5: Microsoft SQL Server Compact 3.5 Service Pack 2
今回はSQL Serverが必要です。無償のExpressやCompact 4.0等で構いませんが、Northwindデータベースを使います。なお、サンプルコードではSQL Server Compact 3.5 SP2を使っていますので、接続文字列やクラス名などは適宜読み替えてください。
とりあえずコードを作ってみる
それでは、Customersテーブルから複数件のデータを取得してくるコードを、とりあえず書いてみましょう。今回は、ADO.NETを使うことにします。
製品のロジックの中に、こんなメソッドを作ります。
| クラス名.メソッド名 | 顧客管理ロジック.前方一致で姓名を検索する()。 |
|---|---|
| 引数 | string型。 |
| 返値 | 顧客情報クラスのコレクション型。Customersテーブルから、顧客のファーストネームまたはラストネームと引数を前方一致で比較して、一致したデータを返す。 |
Nothwindデータベースが初期状態のままなら、次のようなユニットテストを書くことができます。
[TestFixture]
public class 顧客管理ロジックTest {
[TestCase] //製品コード:空のリストを返す。Customerクラスは宣言だけ。
public void 前方一致で姓名を検索するTest_引数が空なら0件() {
var head = "";
IList<Customer> customers = 顧客管理ロジック.前方一致で姓名を検索する(head);
Assert.AreEqual(0, customers.Count());
}
[TestCase] //製品コード:CustomerクラスとSQL文(パラメーター未使用)を実装
public void 前方一致で姓名を検索するTest_ファーストネームが一致() {
var head = "Th";
var customers = 顧客管理ロジック.前方一致で姓名を検索する(head);
var first = customers[0];
Assert.AreEqual("UK", first.Country);
Assert.AreEqual("Around the Horn", first.CompanyName);
Assert.AreEqual("AROUT", first.CustomerID);
Assert.AreEqual("Thomas Hardy", first.ContactName);
}
[TestCase] //製品コード:SQL文を完成させ、パラメタライズドクエリーに修正
public void 前方一致で姓名を検索するTest_ラストネームが一致() {
var head = "An";
var customers = 顧客管理ロジック.前方一致で姓名を検索する(head);
var first = customers[0];
Assert.AreEqual("Germany", first.Country);
Assert.AreEqual("Alfreds Futterkiste", first.CompanyName);
Assert.AreEqual("ALFKI", first.CustomerID);
Assert.AreEqual("Maria Anders", first.ContactName);
}
}
このテストを通すように、製品コードを書きます(実際は、テストケースを1つずつ進めていきます)。
public class Customer {
public string Country { get; set; }
public string CompanyName { get; set; }
public string CustomerID { get; set; }
public string ContactName { get; set; }
}
public class 顧客管理ロジック {
public static IList<Customer> 前方一致で姓名を検索する(string head) {
var list = new List<Customer>();
if(string.IsNullOrWhiteSpace(head))
return list; //引数が空文字のときは、空のリストを返す。
// DB アクセス
using(SqlCeConnection conn = new SqlCeConnection(@"Data Source=C:\Program Files (x86)\Microsoft SQL Server Compact Edition\v3.5\Samples\Northwind.sdf")){
conn.Open();
var cmdText =
@"SELECT Country, [Company Name], [Customer ID], [Contact Name]
FROM Customers
WHERE ([Contact Name] LIKE @p1) OR ([Contact Name] LIKE @p2)";
using (DbCommand cmd = new SqlCeCommand(cmdText, conn)) {
{
var p1 = cmd.CreateParameter();
p1.ParameterName = "@p1";
p1.DbType = System.Data.DbType.String;
p1.Value = head + "%"; //ファーストネームとの前方一致
cmd.Parameters.Add(p1);
} //(変数p1のスコープをここで切っている)
{
var p2 = cmd.CreateParameter();
p2.ParameterName = "@p2";
p2.DbType = System.Data.DbType.String;
p2.Value = "% " + head + "%"; //ラストネーム・ミドルネームとの前方一致
cmd.Parameters.Add(p2);
}
using (DbDataReader reader = cmd.ExecuteReader()) { //クエリー実行
while (reader.Read()) { //結果を一行ずつオブジェクトに詰め替え
var customer = new Customer() {
Country = reader.GetString(0),
CompanyName = reader.GetString(1),
CustomerID = reader.GetString(2),
ContactName = reader.GetString(3),
};
list.Add(customer);
}
}
}
}
return list;
}
}
この記事は参考になりましたか?
- C#で始めるテスト駆動開発入門連載記事一覧
- この記事の著者
-
biac(ばいあっく)
HONDA R&Dで自動車の設計をやっていた機械屋さんが、技術の進化スピードに魅かれてプログラマーに。以来30年ほど、より良いコードをどうやったら作れるか、模索の人生。わんくま同盟の勉強会(名古屋)で、よく喋ってたりする。2014/10~2019/6 Microsoft MVP (Windows Devel...
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
この記事は参考になりましたか?
この記事をシェア
