web-dev-qa-db-ja.com

NUnitでデータベース関連のコードをテストするにはどうすればよいですか?

データベースにヒットするNUnitを使用した単体テストを記述したいと思います。各テストでデータベースを一貫した状態にしたいのですが。トランザクションによって各テストを「取り消す」ことができると思ったので、周りを検索し、2004-05年のトピックに関するいくつかの記事を見つけました。

これらは、各テストの実行後にDB操作をロールバックする機能を組み込んだNUnitのカスタム属性の実装に関して解決するようです。

それは素晴らしいですが...

  1. この機能はNUnitのどこかにネイティブに存在しますか?
  2. この手法は過去4年間で改善されましたか?
  3. これはデータベース関連のコードをテストする最良の方法ですか?

編集:DALを具体的にテストするのではなく、データベースとやり取りするコードの一部をテストしたいだけです。これらのテストを「ノータッチ」で再現性のあるものにするために、テストのたびにデータベースをリセットできたら素晴らしいと思います。

さらに、これを現時点でテスト場所のない既存のプロジェクトに緩和したいと思います。そのため、テストごとにデータベースとデータを最初からスクリプトで作成することは事実上できません。

62
Michael Haren

NUnitに[Rollback]属性が追加されましたが、別の方法を使用することを好みます。 TransactionScope クラスを使用しています。使い方はいくつかあります。

[Test]
public void YourTest() 
{
    using (TransactionScope scope = new TransactionScope())
    {
        // your test code here
    }
}

TransactionScopeにコミットするように指示しなかったので、それは自動的にロールバックします。アサーションが失敗したり、他の例外がスローされたりしても機能します。

もう1つの方法は、[SetUp]を使用してTransactionScopeを作成し、[TearDown]を使用してDisposeを呼び出すことです。一部のコードの重複を削除しますが、同じことを実現します。

[TestFixture]
public class YourFixture
{
    private TransactionScope scope;

    [SetUp]
    public void SetUp()
    {
        scope = new TransactionScope();
    }

    [TearDown]
    public void TearDown()
    {
        scope.Dispose();
    }


    [Test]
    public void YourTest() 
    {
        // your test code here
    }
}

NUnitはTearDownが呼び出されることを保証するため、これは個々のテストのusingステートメントと同じくらい安全です。

とはいえ、データベースにヒットするテストは実際には単体テストではないと思います。私はまだそれらを書いていますが、私はそれらを統合テストと考えています。それでも価値を提供していると私は考えています。私がそれらを頻繁に使用する1つの場所は、LINQ to SQLコードのテストです。デザイナーは使っていません。 DTOと属性を手書きします。私はそれを誤解することが知られています。統合テストは私の間違いを見つけるのに役立ちます。

72
Mike Two

.Net Userグループに行ったところ、プレゼンターは、テストのセットアップとティアダウンにSQLliteを使用し、メモリ内オプションを使用したと述べました。接続を少し変更して明示的に接続を破棄する必要がありましたが、毎回クリーンなDBが提供されました。

http://houseofbilz.com/archive/2008/11/14/update-for-the-activerecord-quotmockquot-framework.aspx

4
nportelli

私はこれらの統合テストを呼び出すでしょうが、問題ではありません。このようなテストで私が行ったことは、テストクラスのセットアップメソッドで、各テストの前に対象となるすべてのテーブルをクリアすることです。私は通常、これを行うためにSQLを手書きして、テスト対象のクラスを使用しないようにします。

一般的に、私はデータレイヤーにORMを使用しているため、そこでは単体テストを作成しません。私が書いていないコードを単体テストする必要性を感じていません。レイヤーに追加するコードについては、通常、依存関係注入を使用してデータベースへの実際の接続を抽象化し、コードをテストするときに実際のデータベースに触れないようにします。最良の結果を得るには、これをモックフレームワークと組み合わせて実行します。

2
tvanfosson

この種のテストのために、私はNDbUnit(NUnitと連携して動作)を試しました。メモリが機能する場合、それはJavaプラットフォームからのDbUnitのポートでした。それは、あなたがやろうとしていることのようなもののための多くの洗練されたコマンドを持っていました。プロジェクトは移動したようですここに:

http://code.google.com/p/ndbunit/

(以前は http://ndbunit.org にありました)。

ソースは次のリンクから入手できるようです: http://ndbunit.googlecode.com/svn/trunk/

1
Scott Lawrence

NUnitから自動的に実行できるように、また他のタイプのテストでは手動で実行できるように、データベーススクリプトを作成することを検討してください。たとえば、Oracleを使用している場合は、NUnit内からSqlPlusを開始し、スクリプトを実行します。これらのスクリプトは通常、記述が速く、読みやすいです。また、非常に重要なこととして、Toadまたは同等の機能からSQLを実行することは、コードからSQLを実行すること、またはコードからORMを実行することよりも優れています。通常、セットアップスクリプトとティアダウンスクリプトの両方を作成し、それらをセットアップメソッドとティアダウンメソッドに配置します。

単体テストからDBを実行する必要があるかどうかは、別の議論です。私はそうすることがしばしば意味をなすと信じています。多くのアプリでは、データベースは絶対的なアクションの中心であり、ロジックは高度に設定されており、他のすべてのテクノロジーと言語およびテクニックはゴーストを通過しています。そして、関数型言語の台頭に伴い、SQLはJavaScriptのように、実際にはここ数年、私たちの鼻の下にあった素晴らしい言語であることに気づき始めています。

余談ですが、Linq to SQL(概念的には使用したことはありませんが)は、私が何をしているのかを認めずにコード内から生のSQLを実行する方法のように思えます。 SQLが好きで、SQLが好きな人もいれば、SQLが好きで、好きではない人もいます。 :)

0
Mike