2016-10-04 17 views
3

私は現在、リストとして一般的にモックDbSetsに拡張メソッドを使用しています:一般的にDbSet.FindメソッドをMoqでモックする方法はありますか?

public static DbSet<T> AsDbSet<T>(this List<T> sourceList) where T : class 
    { 
     var queryable = sourceList.AsQueryable(); 
     var mockDbSet = new Mock<DbSet<T>>(); 
     mockDbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider); 
     mockDbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression); 
     mockDbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType); 
     mockDbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator()); 
     mockDbSet.Setup(x => x.Add(It.IsAny<T>())).Callback<T>(sourceList.Add); 
     mockDbSet.Setup(x => x.Remove(It.IsAny<T>())).Returns<T>(x => { if (sourceList.Remove(x)) return x; else return null; }); 

     return mockDbSet.Object; 
    } 

しかし、私はテーブルの主キーに基づいて検索する検索方法を、模擬する方法を把握することはできません。私は、データベースを調べ、PKを取得し、そのフィールドのFindメソッドをモックすることができるので、各テーブルの特定のレベルでそれを行うことができます。しかし、私は一般的な方法を使用することはできません。

EFが自動的に生成した部分クラスに追加して、属性または何かを持つPKであるフィールドをマークすることもできます。しかし、100を超えるテーブルがあり、手動でこれを管理する人に頼っていると、コードを管理するのが難しくなります。

EF6はプライマリキーを見つける方法を提供しますか、それともデータベースに接続した後でのみ動的に認識しますか?

+2

あなたは次のようなものをお探しですか?[リンク](http://stackoverflow.com/a/25199983/5048049)そうでなければ、あなたは何を探していますか? – peval27

+1

これは私が説明した最初の選択肢です。これは、一般的なセットの汎用モックではなく、ActiveLoanセットの特定のモックを作成しています。 –

答えて

4

これを熟考した後、私は現在利用可能な「最良の」解決策を見つけたと思う。私はちょうど拡張メソッドの型を直接チェックする一連のif文を持っています。それから私は、見つけた振る舞いを設定し、私が完了したときにそれをジェネリックに戻すために必要なタイプにキャストします。それは擬似ジェネリックでしかありませんが、私は他の何かをよく考えることはできません。

 if (typeof(T) == typeof(MyFirstSet)) 
     { 
      mockDbSet.Setup(x => x.Find(It.IsAny<object[]>())).Returns<object[]>(x => (sourceList as List<MyFirstSet>).FirstOrDefault(y => y.MyFirstSetKey == (Guid)x[0]) as T); 
     } 
     else if (typeof(T) == typeof(MySecondSet)) 
     { 
      mockDbSet.Setup(x => x.Find(It.IsAny<object[]>())).Returns<object[]>(x => (sourceList as List<MySecondSet>).FirstOrDefault(y => y.MySecondSetKey == (Guid)x[0]) as T); 
     } 
     ...  
+0

ニース。私のすべてのエンティティは "Id"の同じプライマリキーを持っているので、 "y.MetSetKey"を "y.GetType()"に置き換えることでこれをより一般的にすることができました。 – Jared

1

私の知る限り、この質問に対する「ベストプラクティス」の回答はありませんが、ここに私がどのようにアプローチしたかが記載されています。プライマリキーを識別するAsDbSetメソッドにオプションのパラメータを追加しました。その後、Findメソッドを簡単にモックアップできます。

public static DbSet<T> AsDbSet<T>(this List<T> sourceList, Func<T, object> primaryKey = null) where T : class 
{ 
    //all your other stuff still goes here 

    if (primaryKey != null) 
    { 
     mockSet.Setup(set => set.Find(It.IsAny<object[]>())).Returns((object[] input) => sourceList.SingleOrDefault(x => (Guid)primaryKey(x) == (Guid)input.First())); 
    } 

    ... 
} 

私はそれはあなたが作業しているかと思われたとして、主キーとして使用されている単一のGUIDを前提にこれを書いたが、あなたは、より柔軟性が必要な場合は、原則としては、適応するのに十分な簡単なはず複合キーなど

私は次のクラスに終わった
0

public static class DbSetMocking 
{ 
    #region methods 

    public static IReturnsResult<TContext> ReturnsDbSet<TEntity, TContext>(this IReturns<TContext, DbSet<TEntity>> setup, ICollection<TEntity> entities, Func<object[], TEntity> find = null) 
     where TEntity : class where TContext : DbContext 
    { 
     return setup.Returns(CreateMockSet(entities, find).Object); 
    } 

    private static Mock<DbSet<T>> CreateMockSet<T>(ICollection<T> data, Func<object[], T> find) 
     where T : class 
    { 
     var queryableData = data.AsQueryable(); 
     var mockSet = new Mock<DbSet<T>>(); 
     mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryableData.Provider); 
     mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryableData.Expression); 
     mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryableData.ElementType); 
     mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryableData.GetEnumerator()); 

     mockSet.SetupData(data, find); 

     return mockSet; 
    } 

    #endregion 
} 

使用することができます。

private static MyRepository SetupRepository(ICollection<Type1> type1s, ICollection<Type2> type2s) 
{ 
    var mockContext = new Mock<MyDbContext>(); 

    mockContext.Setup(x => x.Type1s).ReturnsDbSet(type1s, o => type1s.SingleOrDefault(s => s.Secret == (Guid) o[ 0 ])); 
    mockContext.Setup(x => x.Type2s).ReturnsDbSet(type2s, o => type2s.SingleOrDefault(s => s.Id == (int) o[ 0 ])); 

    return new MyRepository(mockContext.Object); 
} 
関連する問題