4.3.2 テストコードの記述方法
先に述べたように、Visual Studio 2005上でのデータベースアプリケーション開発では、データコンポーネント機能(.xsdファイル)を活用すると、データアクセスクラス(DAC)やビジネスエンティティクラス(BEC)を簡単に作ることができる。このデータコンポーネント機能(.xsdファイル)を活用して開発されたモジュールを単体機能テストする際に重要なポイントは、「自動生成されたコードをテスト対象としない」という点である。例えば以下のような点に注意してテストを行う。
-
データアクセスクラス(DAC)に相当するテーブルアダプタクラスをテストする場合
-
自動生成されたADO.NETのコードは、正しく動作して当然だと考える。例えば、そもそもデータベースに適切に接続できるか、クエリを発行できるか、データベースに接続できなかった場合に例外を返してくるか否か、構成設定ファイル内の接続文字列を適切に拾えるのか、といった低水準の動作(ライブラリやウィザードが責任を持ってくれるはずの部分)については検証しなくてよい。
-
しかし、自分で定義したSQL文が誤っている可能性は(他に比べて相対的に)高い。このため、定義したSQL文が期待通りに動作するか否かを中心として検証する。例えば、SELECT文は期待通りの列一覧を取得しているか、WHERE句には正しいフィルタリング条件を指定できているか、期待通りのJOIN処理が行われるか、などを検証するようなテストメソッドを書く。
-
ただし、partial機能を利用してテーブルアダプタクラスを拡張した場合には、各自が記述したコードに対する単体機能テストが必要になる。
-
ビジネスエンティティコンポーネント(BEC)に相当する型付きデータセットクラスをテストする場合
-
基本的に、型付きデータセットはウィザードが自動生成するものである。よって検証対象としなくてよい。
-
自動生成されたデータセットに加工を加えた場合(例えばExpression列を追加したりリレーションシップを追加したりした場合)には、それらが正しく定義できているかを検証するようなテストメソッドを記述する。
上記の解説をまとめると、図4-24のようになる。
|
図 4-24 データコンポーネント機能(.xsdファイル)を使った場合のDACとBECのテスト対象部分 |
テスト対象とすべき部分がはっきりしたら、あとはこれらをテストするためのテストメソッドを記述していけばよい。この際、参照系データアクセス処理をテストする場合と更新系データアクセス処理を記述する場合とで注意すべき点が異なる。これについて以下に簡単にまとめる。
A.参照系データアクセス処理をテストする場合
基本的には、テーブルアダプタ上のメソッドを利用し、正しくデータが取得されたか否かをAssertクラスにより検証すればよい。サンプルコードをリスト4-10に示す。
public class AuthorsDataSetTest
{
[TestMethod]
public void GetDataByTopNormalTest()
{
authorsTableAdapter ta = new authorsTableAdapter();
AuthorsDataSet.authorsDataTable dt = ta.GetDataByTop(5);
Assert.AreEqual(5, dt.Count);
Assert.AreEqual("Dean", dt[4].au_fname);
}
// partialクラス上に定義されたメソッドもテストする
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void GetDataByTopNgNumberTest()
{
authorsTableAdapter ta = new authorsTableAdapter();
AuthorsDataSet.authorsDataTable dt = ta.GetDataByTop(-10);
}
} |
<TestClass()> _
Public Class AuthorsDataSetTest
<TestMethod()> _
Public Sub GetDataByTopNormalTest()
Dim ta As authorsTableAdapter = New authorsTableAdapter()
Dim dt As AuthorsDataSet.authorsDataTable = ta.GetDataByTopOrderByAuId(5)
Assert.AreEqual(5, dt.Count)
Assert.AreEqual("Dean", dt(4).au_fname)
End Sub
' partial クラス上に定義されたメソッドもテストする
<TestMethod()> _
<ExpectedException(GetType(ArgumentException))> _
Public Sub GetDataByTopNgNumberTest()
Dim ta As authorsTableAdapter = New authorsTableAdapter()
Dim dt As AuthorsDataSet.authorsDataTable = ta.GetDataByTop(-10)
End Sub
End Class
|
|
リスト 4-10 参照系データアクセス処理の単体機能テスト |
データアクセスクラスのテストを行う場合には、ロックヒントつきクエリ*97のロックヒント動作に関する単体機能テストは省略することをお奨めする。単体機能テストでは「自分が書いたSQLクエリの動作を検証する」ことを目的とするので、厳密な意味では、指定したロックヒント通りにロックが獲得されることを確認することが望ましい。しかし、現実的にはこの確認作業を自動化することはかなり厄介である。このため、データアクセスクラスのテストに関しては、SQL文の基本的な動作や異常パラメータ値に対する振る舞いなどを中心に実施するとよいだろう。
なお、一般にUPDLOCKロックヒントなどの同時実行制御に関するロックヒントは、短時間トランザクション制御のために利用される。このようなロックヒントは、単体で検証するよりも、後述するビジネスロジッククラスに対する単体機能テストの負荷テストの中で検証した方がより効果的なテストができることが多い(図4-25)。詳細については、「4.4 ビジネスロジッククラスに対する単体機能テスト」の中で解説する。
|
図 4-25 ロックヒントなどの同時実行制御に関連する単体機能テストの実施方法 |
B.更新系データアクセス処理をテストする場合
INSERT処理やUPDATE処理といった更新系データアクセス処理をテストする場合には、これらの処理がテスト用データを破壊してしまう点に注意が必要である。一般に、テストメソッドの実行順序は保証されていないため*98、どのような順序でテストメソッドが実行されても構わないように、各テストメソッドの終了時にはデータを元の状態に復元することが望ましい。
*98 処理順序を保証したテストを行いたい場合には、順序指定テストと呼ばれる機能を利用する。詳細については「4.8.2 汎用テストと順序指定テスト」を参照のこと。 |
これを実現するには、.NET Framework 2.0の新機能であるSystem.Transactions機能(自動トランザクション機能)を活用するとよいだろう*99。リスト4-11に示すように、テストコード全体をTransactionScopeオブジェクトのusingブロックで囲み、テスト終了後にトランザクションコミットせずにスコープを抜ける。このようにすると自動トランザクションがロールバックされ、テスト用データベース内のデータが元の状態に戻る。
[TestClass]
public class AuthorsDataSetTest
{
[TestMethod]
public void UpdateContractByStateTest()
{
// テストケース実施後にデータベースをロールバックするための自動トランザクション
using (TransactionScope scope =
new TransactionScope(TransactionScopeOption.RequiresNew))
{
authorsTableAdapter ta = new authorsTableAdapter();
int affectedRows = ta.UpdateContractByState("CA");
Assert.AreEqual(15, affectedRows);
// データが正しく更新されているかをピックアップして確認
AuthorsDataSet.authorsDataTable dt2 =
ta.GetDataByAuIdWithUpdlock("213-46-8915");
Assert.AreEqual(false, dt2[0].contract);
}
}
} |
<TestClass()> _
Public Class AuthorsDataSetTest
<TestMethod()> _
Public Sub UpdateContractByStateTest()
' テストケース実施後にデータベースをロールバックするための自動トランザクション
Using scope As TransactionScope =
New TransactionScope(TransactionScopeOption.RequiresNew)
Dim ta As authorsTableAdapter = New authorsTableAdapter()
Dim dt As AuthorsDataSet.authorsDataTable = ta.GetDataByAuIdWithUpdlock("213-46-8915")
Dim contract As Boolean = dt(0).contract
Dim affectedRows As Integer = ta.SetNewContractByAuId(False, "213-46-8915")
Assert.AreEqual(1, affectedRows)
' データが正しく更新されているかをピックアップして確認
Dim dt2 As AuthorsDataSet.authorsDataTable =
ta.GetDataByAuIdWithUpdlock("213-46-8915")
Assert.AreEqual(False, dt2(0).contract)
End Using
End Sub
End Class
|
|
リスト 4-11 更新系データアクセス処理の単体機能テスト |
|
|
Insider.NET 記事ランキング
本日
月間