質問

この夏、私は基本的な ASP.NET/SQL Server CRUD アプリを開発していましたが、単体テストが要件の 1 つでした。データベースに対してテストしようとしたときに問題が発生しました。私の理解では、単体テストは次のようにする必要があります。

  • ステートレス
  • 互いに独立した
  • 同じ結果で再現可能、つまり永続的な変更はありません

データベースを開発する場合、これらの要件は互いに矛盾しているように見えます。たとえば、挿入する行がまだ存在しないことを確認せずに Insert() をテストすることはできないため、最初に Delete() を呼び出す必要があります。しかし、それらがまだ存在していない場合はどうなるでしょうか?次に、最初に Exists() 関数を呼び出す必要があります。

私の最終的な解決策には、非常に大規模なセットアップ関数 (ヤバい!) と、最初に実行されてセットアップが問題なく実行されたことを示す空のテスト ケースが含まれていました。これにより、テストの無国籍性が維持されながら、テストの独立性が犠牲になります。

私が見つけたもう 1 つの解決策は、関数呼び出しを簡単にロールバックできるトランザクションにラップすることです。 ロイ・オシェロヴのXtUnit. 。これは機能しますが、別のライブラリと別の依存関係が関係しており、目前の問題に対する解決策としては少し重すぎるように思えます。

では、この状況に直面したとき、SO コミュニティは何をしたのでしょうか?


tgmdbm さんはこう言いました。

通常、お気に入りの自動ユニットテストフレームワークを使用して統合テストを実行します。そのため、一部の人は混乱しますが、同じルールに従いません。多くのクラスの具体的な実装を伴うことが許可されています(ユニットテストを受けたため)。あなたはテスト中です 具体的なクラスが互いにどのように相互作用し、データベースと相互作用するか.

したがって、これを正しく読んだ場合、実際には方法はありません 効果的に データ アクセス層の単体テスト。それとも、データ アクセス レイヤーの「単体テスト」には、データベースとの実際の対話とは関係なく、クラスによって生成された SQL/コマンドなどのテストが含まれるのでしょうか?

役に立ちましたか?

解決

データベースの単体テストを行う実際の方法は、テーブルが存在し、予期される列が含まれ、適切な制約があることを確認すること以外にありません。しかし、通常はそれを行う価値はありません。

通常はそうではありません ユニット データベースをテストします。通常、データベースを使用するのは、 統合 テスト。

通常、統合テストを実行するには、お気に入りの自動化された単体テスト フレームワークを使用します。そのため混乱する人もいますが、同じルールには従いません。多くのクラスの具体的な実装に関与することができます (クラスは単体テストされているため)。具体的なクラスが相互に、またデータベースとどのように対話するかをテストしています。

他のヒント

Dユニット

このツールを使用して、特定の時点でのデータベースの状態をエクスポートし、その後単体テストを行うときに、テストの開始時に自動的に前の状態にロールバックできます。私が働いているところではよく利用しています。

単体テストにおける外部依存関係に対する通常の解決策は、モック オブジェクト、つまり、テスト対象となる実際のオブジェクトの動作を模倣するライブラリを使用することです。これは必ずしも簡単ではなく、工夫が必要な場合もありますが、「独自に開発」したくない場合には、.Net 用の優れた (フリーウェア) モック ライブラリがいくつかあります。すぐに思い浮かぶのは次の 2 つです。

サイモック かなり評判の良いものです。

Nモック 別のものです。

商用のモック ライブラリもたくさんあります。優れた単体テストを書くことの一部は、実際に単体テスト用のコードを設計することです。たとえば、意味のあるインターフェイスを使用して、依存オブジェクトのインターフェイスの「偽の」バージョンを実装することで依存オブジェクトを「モック」することができますが、それでもインターフェイスの動作は変わりません。テスト目的での予測可能な方法。

データベース モックでは、これは、単体テストで処理するために作成されたテーブル、行、またはデータセット オブジェクトを返すオブジェクトを使用して独自の DB アクセス レイヤーを「モック」することを意味します。

私が働いている場所では、通常、独自のモック ライブラリを最初から作成しますが、そうしなければならないというわけではありません。

そうです、データベースにアクセスするリポジトリとサービスにアクセスするようにコードをリファクタリングする必要があります。その後、それらのオブジェクトをモックまたはスタブして、テスト対象のオブジェクトがデータベースにアクセスしないようにすることができます。これは、データベースの状態を保存し、テストのたびにリセットするよりもはるかに高速です。

強くお勧めします モク モックフレームワークとして。Rhino Mocks と NMock を使用しました。Moq は非常にシンプルで、他のフレームワークで抱えていた問題をすべて解決してくれました。

私も同じ質問をしており、他の回答者と同じ基本的な結論に達しました。実際の DB 通信層の単体テストをわざわざ行う必要はありませんが、モデル関数の単体テスト (データが適切に取得されていること、適切にフォーマットされていることなどを確認するため) を行いたい場合は、ある種のダミー データ ソースを使用してテストをセットアップしてください。取得されるデータを確認します。

私も、単体テストの最低限の定義は、多くの Web 開発活動には適合しないと感じています。ただし、このページでは、より「高度な」単体テスト モデルについて説明しており、さまざまな状況で単体テストを適用するためのアイデアを得るのに役立つかもしれません。

単体テストパターン

まさにこの状況で私が使用しているテクニックを説明しました ここ.

基本的な考え方は、DAL で各メソッドを実行し、結果をアサートし、各テストが完了したらロールバックしてデータベースをクリーン (ジャンク/テスト データがない) にすることです。

「素晴らしい」と思われないかもしれない唯一の問題は、通常は CRUD テスト全体 (単体テストの観点から純粋ではない) を行うのですが、この統合テストでは CRUD + マッピング コードの動作を確認できることです。こうすることで、アプリケーションが壊れた場合に、アプリケーションを起動する前にそれを知ることができます (高速に動作させたいときに大量の作業を節約できます)

スクリプトから生成したデータベースの空のコピーからテストを実行する必要があります。テストを実行してからデータを分析し、テストの実行後にデータが正確に一致していることを確認できます。その後、データベースは使い捨てなので、削除するだけです。これはすべて自動化でき、アトミックなアクションとみなすことができます。

データレイヤーとデータベースを一緒にテストすると、プロジェクトの後半にはほとんど驚きが残ります。しかし、データベースに対するテストには問題があります。主なものは、多くのテストで共有されている状態に対してテストしていることです。1つのテストでデータベースに行を挿入すると、次のテストでもその行も確認できます。
必要なのは、データベースに加えた変更をロールバックする方法です。
トランザクションスコープ クラスは、非常に複雑なトランザクションを処理するのに十分賢く、テスト対象のコードが独自のローカルトランザクションでコミットするネストされたトランザクションです。これは、テストにロールバック機能を追加することがどれほど簡単かを示すコードのシンプルな部分です。

    [TestFixture]
    public class TrannsactionScopeTests
    {
        private TransactionScope trans = null;

        [SetUp]
        public void SetUp()
        {
            trans = new TransactionScope(TransactionScopeOption.Required);
        }

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

        [Test]
        public void TestServicedSameTransaction()
        {
            MySimpleClass c = new MySimpleClass();
            long id = c.InsertCategoryStandard("whatever");
            long id2 = c.InsertCategoryStandard("whatever");
            Console.WriteLine("Got id of " + id);
            Console.WriteLine("Got id of " + id2);
            Assert.AreNotEqual(id, id2);
        }
    }

LINQ to SQL を ORM として使用している場合は、その場でデータベースを生成できます (単体テストに使用されるアカウントから十分なアクセス権がある場合)。見る http://www.aaron-powell.com/blog.aspx?id=1125

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top