Effort - FirstOrDefaultは、Faking Databaseの場合にnullを返します。


質問

プロジェクトの単体テストを作成しようとしています。取り組みが大変だと思っています。そのアイデアは素晴らしいです。DBContextを偽装するのではなく、データベースをモックします。複雑なスキーマを使用します。

しかし、私は具体的にインメモリデータベースにEffortで作成した後にユーザーのEメールを取得しようとしています。コードはここにあります

MyContext contextx = new MyContext(Effort.DbConnectionFactory.CreateTransient());

var client = new Client
{
    ClientId = 2,
    PersonId = 3,
    Person = new Person
    {
        PersonId = 3,
        EMail = "xxxxx@gmail.com"
    }
};
contextx.Client.Add(client); //<-- client got added, I checked it and is there

var email = contextx.Client.Select(c => c.Person.EMail).FirstOrDefault(); 

上の最後の行では、電子メールxxxx@gmail.comを返すことはできません。代わりに、常にnullが返されます。

何か案は?

受け入れられた回答

あなたの直接の質問に答える

あなたが尋ねた特定の質問について、私は2つのことを提案します:

  1. contextx.Client.ToArray()を見て、あなたが本当にそのコレクションにいくつのメンバーがいるかを見てください。 Clientコレクションが実際に空である可能性があります。その場合、実際にはnullが返されます。または、Clientコレクションの最初の要素にEMail null値がある可能性があります。

  2. contextx.SaveChanges() Clientコレクションを照会する前にcontextx.SaveChanges()を呼び出すと、ビヘイビアーはどのように変化しますか? SaveChangesを呼び出すと、新しく挿入された値がコレクションに存在するかどうかが分かります。これは必須ではありませんが、EffortとDbContext間には奇妙なやりとりがあるかもしれません。

編集: SaveChanges()は答えになることが判明。

一般的なテストの提案

"unit-testing"タグでこの質問にタブを当てたので、ユニットテストの実務家とコーチとして10年間勤めてきたことに基づいて、一般的なユニットテストのアドバイスを提供します。 ユニットテストは、単独で、アプリケーションの様々な小さな部品をテストについてです。通常これは、単体テストがいくつかのクラスと同時に対話することを意味します。これは、ユニットテストが外部ライブラリや依存関係(データベースなど)に依存すべきでないことを意味します。逆に、 統合テストではシステムの多くの部分を一度に実行し、データベースなどの外部依存関係が発生する可能性があります。

これは専門用語では不明瞭ですが、テストの実際の目的をチームの他のメンバーに伝えるためには重要です。

この場合、DbContextに依存する機能の単体テストを実際に行っているか、データアクセスレイヤーをテストしようとしているかのどちらかです。直接DbContextに依存するものの単体テストを書く場合は、DbContextへの依存関係を解除する必要があります。下の「 DbContextの依存関係を解除する」でこれについて説明します。それ以外の場合は、エンティティのマッピング方法など、DbContextの統合テストを実際に試みています。この場合、私は常にこれらのテストを分離し、実際の(ローカル)データベースを使用するのが最良であることを発見しました。プロダクションで使用しているのと同じ種類のローカルにインストールされたデータベースを使用したいと思うかもしれません。しばしば、SqlExpressはうまく動作します。テストがデータベースのインスタンスを指すようにして、テストが完全にゴミ箱に入るようにします。各テストを実行する前に、既存のデータをすべて削除します。既存のデータが矛盾することなく、必要なデータをセットアップできます。

DbContextへの依存を破る

だから、あなたのビジネスロジックがDbContextにアクセスすることに依存しているときに、単体テストを書くにはどうすればよいですか? あなたはそうしない。

データ永続性のためにEntity Frameworkを使用する私のアプリケーションでは、 DbContextへのアクセスが別のデータアクセスプロジェクトに含まれていることを確認します。通常は、Repositoryパターンを実装するクラスを作成し、それらのクラスはDbContext依存することができます。この場合、 IClientRepositoryインターフェイスを実装するClientRepositoryを作成します。インタフェースは次のようになります。

public interface IClientRepository {

    Client GetClientByEMail(string email);

}

次に、メソッドにアクセスする必要のあるクラスは、基本的なスタブ/モック/その他を使用して単体テストできます。 DbContext嘲笑することについて何も心配する必要はありません。データアクセスレイヤーが含まれており、実際のデータベースを使用して完全にテストできます。データアクセスレイヤのテスト方法に関するいくつかの提案については、上記を参照してください。

追加の利点として、このインタフェースの実装は、単一の統一された場所で電子メールアドレスでClientを見つけることが何を意味するかを定義します。 IClientRepositoryインターフェイスを使用すると、「システム内のClientエンティティをどのように照会するのですか?」という質問にすぐに答えることができます。

DbContext依存するDbContextは、ドメインクラスが接続文字列に依存してどこでもADO.Netコードを持つことを可能にすることとほぼ同じテスト問題の規模です。つまり、実際のデータストアを作成しなければならないということです。しかし、特定のデータアクセスアセンブリ内のDbContextへのアクセスが含まれている場合は、 DbContext記述がずっと簡単になります。

プロジェクトの構成に関しては、通常、データアクセスプロジェクトでEntity Frameworkへの参照のみを許可します。私はエンティティを定義する別のコアプロジェクトを用意します。また、コアプロジェクトでデータアクセスインターフェイスを定義します。次に、具体的なインターフェイス実装がデータアクセスプロジェクトに組み込まれます。ソリューションのほとんどのプロジェクトは、単にコアプロジェクトに依存するだけで、実際にはトップレベルの実行可能ファイルまたはWebプロジェクトのみがデータアクセスプロジェクトに依存する必要があります。





ライセンスを受けた: CC-BY-SA
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ