私は新しいプロジェクトの始まりに近づいており、私のプロジェクトにユニットテストを含めようとするのは初めてです。
一部の単体テスト自体の考案に問題があります。テストするのに十分簡単な方法がいくつかあります(2つの値を渡して、期待される出力を確認します)。データベースに対してクエリを実行するなど、より複雑なことを実行しているコードの他の部分があり、それらをテストする方法がわかりません。
public DataTable ExecuteQuery(SqlConnection ActiveConnection, string Query, SqlParameterCollection Parameters)
{
DataTable resultSet = new DataTable();
SqlCommand queryCommand = new SqlCommand();
try
{
queryCommand.Connection = ActiveConnection;
queryCommand.CommandText = Query;
if (Parameters != null)
{
foreach (SqlParameter param in Parameters)
{
queryCommand.Parameters.Add(param);
}
}
SqlDataAdapter queryDA = new SqlDataAdapter(queryCommand);
queryDA.Fill(resultSet);
}
catch (Exception ex)
{
//TODO: Improve error handling
Console.WriteLine(ex.Message);
}
return resultSet;
}
このメソッドは基本的に、データベースからデータを抽出するために必要なすべてのビットとピースを取り込んで、DataTableオブジェクトにデータを返します。
最初の質問はおそらく最も複雑です:このような状況で何をテストすればよいでしょうか?
それが解決したら、データベースコンポーネントをモックアウトするか、実際のDBに対してテストするかどうかの問題が生じます。
何をテストしていますか?
私の頭の上の3つの可能性があります。
A. DAO(データアクセスオブジェクト)クラスをテストして、データベースに渡される値/パラメーターを正しくマーシャリングし、データベースから取得した結果を正しくマーシャリング/変換/パッケージングすることを確認しています。
この場合、データベースに接続する必要はまったくありません。データベース(またはJDBC、(N)Hibernate、iBatisなどの中間層)をモックに置き換える単体テストが必要です。
B.(生成された)SQLの構文の正確さをテストしています。
この場合、SQLダイアレクトが異なるため、RDBMSのすべての癖をモックしようとするのではなく、RDBMSの正しいバージョンに対して(おそらく生成された)SQLを実行する(そして、機能を変更するRDBMSアップグレードがキャッチされるようにする)あなたのテスト)。
C. SQLのsemanticの正確性、つまり、特定のベースラインデータセット、操作(アクセス/選択、突然変異/挿入)の正当性をテストしているおよび更新)予想される新しいデータセットを作成します。
そのためには、dbunit(ベースラインを設定し、結果セットを期待される結果セットと比較することができます)のようなものを使用するか、ここで概説する手法を使用して、データベースで完全にテストを実行します:- SQLクエリをテストする最良の方法 。
これが、(IMHO)単体テストが開発者側に誤ったセキュリティの感覚を作り出すことがある理由です。データベースと通信するアプリケーションでの私の経験では、エラーは通常、データが予期しない状態になった結果です(異常な値や欠損値など)。単体テストで日常的にデータアクセスのモックアップを作成する場合、実際にはこの種のエラーに対して脆弱であるにもかかわらず、コードはうまく機能していると思うでしょう。
あなたの最善のアプローチは、テストデータベースを手軽に用意し、ゴツゴツしたデータの塊で満たし、それに対してデータベースコンポーネントのテストを実行することだと思います。その間、ユーザーがデータを台無しにするよりもはるかに優れていることを忘れないでください。
単体テストのポイントは、単体テスト(duh)を単独で行うことです。データベース呼び出しの全体のポイントは、別のユニット(データベース)とのintegrateです。エルゴ:データベース呼び出しを単体テストすることは意味がありません。
ただし、統合テストデータベース呼び出しを行う必要があります(必要に応じて、単体テストに使用するものと同じツールを使用できます)。
神の愛のために、すでに存在しているライブのデータベースに対してテストしないでください。しかし、あなたはそれを知っていました。
一般に、ユーザーの認証、電話帳/組織図のエントリの検索など、各クエリがどのような種類のデータを取得するのかを既に把握しています。関心のあるフィールドと、それらに存在する制約を知っています(たとえば、UNIQUE
、NOT NULL
、 等々)。データベース自体ではなく、データベースと対話するコードを単体テストしているので、これらの機能をテストする方法について考えてください。フィールドがNULL
になる可能性がある場合、コードがNULL
値を正しく処理することを確認するテストが必要です。フィールドの1つが文字列(CHAR
、VARCHAR
、TEXT
、&c)の場合、エスケープされた文字を正しく処理していることを確認してください。
ユーザーがデータベースに何かを入れようとし、それに応じてテストケースを生成すると仮定します。このためにモックオブジェクトを使用する必要があります。
*望ましくない、悪意のある、または無効な入力を含む。
厳密に言えば、データベースまたはファイルシステムからの書き込み/読み取りを行うテストは単体テストではありません。 (ただし、統合テストであり、NUnitまたはJUnitを使用して作成される場合があります)。単体テストは、単一のクラスの操作をテストし、その依存関係を分離することになっています。したがって、インターフェイスレイヤーとビジネスロジックレイヤーの単体テストを記述する場合、データベースはまったく必要ありません。
わかりましたが、データベースアクセスレイヤーの単体テストはどのように行いますか?この本のアドバイスが気に入っています: xUnit Test Patterns (リンクは本の「Testing w/DB」の章へのリンクです。キーは次のとおりです。
queryDA.Fill(resultSet);
を除くすべてを単体テストできます
queryDA.Fill(resultSet)
を実行するとすぐに、データベースをモック/偽造するか、統合テストを実行する必要があります。
私は、統合テストが悪いとは思っていません。それは、異なる種類のバグを捕まえるだけで、偽陰性と偽陽性のオッズが異なります。スロー。
このコードを単体テストしている場合、パラメーターが正しくビルドされていることを検証しますが、コマンドビルダーは適切な数のパラメーターを作成しますか?それらはすべて価値がありますか? null、空の文字列、DbNullは正しく処理されますか?
実際にデータセットを埋めるのは、データベースをテストすることです。これは、DALの範囲外の不安定なコンポーネントです。
単体テストでは、通常、データベースをモックまたは偽造します。次に、依存性注入を介してモックまたは偽の実装を使用して、メソッドをテストします。また、データベース内の制約、外部キー関係などをテストする統合テストもおそらくあるでしょう。
テストするものについては、メソッドがパラメーターからの接続を使用していること、クエリ文字列がコマンドに割り当てられていること、返される結果セットが期待値を介して提供しているものと同じであることを確認しますFillメソッド。注-パラメーターを変更するFillメソッドよりも、値を返すGetメソッドをテストする方がおそらく簡単です。
これを適切に行うには、いくつかの依存性注入(DI)を使用する必要がありますが、.NETにはいくつかあります。現在Unityフレームワークを使用していますが、もっと簡単なものもあります。
このテーマに関するこのサイトからのリンクが1つありますが、他にもあります: 。NETでの依存性注入の例?
これにより、モッククラスにインターフェイスを実装させるだけで、アプリケーションの他の部分を簡単にモックアウトできるため、応答方法を制御できます。しかし、これはインターフェイスに合わせて設計することも意味します。
あなたがベストプラクティスについて尋ねたので、これはIMOです。
次に、必要な場合を除き、dbにアクセスしないでください。
カスケード削除を使用した外部キー関係などの特定の動作をテストする必要がある場合は、そのためのデータベーステストを作成することもできますが、実際には複数の人が単体テストを実行する可能性があるため、通常は実際のデータベースに移動しないことが最適です時間と同じデータベースに行く場合は、予想されるデータが変更されるため、テストが失敗することがあります。
編集:データベースの単体テストでは、これはt-sqlを使用してセットアップ、テスト、および分解を行うように設計されているためです。 http://msdn.Microsoft.com/en-us/library/aa833233%28VS.80%29.aspx
JDBCベースのプロジェクトでは、JDBC接続をモックすることができます。これにより、テストを実行中のRDBMSなしで実行でき、各テストケースが分離されます(データの競合はありません)。
検証を可能にし、永続化コードは適切なクエリ/パラメーターを渡します(例 https://github.com/playframework/playframework/blob/master/framework/src/anorm/src/test/scala/anorm/ParameterSpec。 scala )そして、JDBCの結果(解析/マッピング)を期待どおりに処理します(「データベースからデータを抽出するために必要なビットとピースをすべて取り込み、DataTableオブジェクトにデータを返します」)。
JOOQや私のフレームワークAcolyteのようなフレームワークは、 https://github.com/cchantep/acolyte に使用できます。