2016-09-19 9 views
1

オブジェクトのlinq拡張子の設定方法は?私の場合はDbSetです。ここに私のコードは次のとおりです。Moq - setup拡張子はどこですか?

System.NotSupportedException:

this.workflowStateSet 
    .Setup(m => m.Where(It.IsAny<Expression<Func<Model.WorkflowState, int, bool>>>())) 
    .Returns(new List<Model.WorkflowState>().AsQueryable()); 

しかし、それは私に例外ではない非常に身近な例外を与えるm => m.Where<WorkflowState>

:発現は が嘲笑オブジェクトに属していないメソッドを参照します

私はどんなヒントにも感謝します。

+2

Linqメソッドをモックしたいですか?彼らはすべて静的で一般的なので、かなり恐ろしいです。なぜこれが必要なの?あなたのテストのための要素のいくつかのダミーシーケンスを作成できませんか? – HimBromBeere

+0

ええ、できません。拡張メソッドは静的メソッドの周りの構文的な砂糖であり、静的メソッドをオーバーライドすることはできません。 – Will

+0

@ウィル - 私はそれらを嘲笑しない、私はそれらを設定したい。まあ、私はそれがボックスの中でどのように動作するのかわかりませんが、セットアップは特定のメソッドのデコレータのようなものを作成します。したがって、実際に呼び出すことなくメソッド呼び出しの結果を設定することができます。それじゃない? – Qerts

答えて

2

この拡張メソッドはモックDbSet

public static class MockDbSetExtensions { 
    public static Mock<DbSet<T>> AsDbSetMock<T>(this IEnumerable<T> list) where T : class { 
     IQueryable<T> queryableList = list.AsQueryable(); 
     Mock<DbSet<T>> dbSetMock = new Mock<DbSet<T>>(); 
     dbSetMock.As<IQueryable<T>>().Setup(x => x.Provider).Returns(queryableList.Provider); 
     dbSetMock.As<IQueryable<T>>().Setup(x => x.Expression).Returns(queryableList.Expression); 
     dbSetMock.As<IQueryable<T>>().Setup(x => x.ElementType).Returns(queryableList.ElementType); 
     dbSetMock.As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(() => queryableList.GetEnumerator()); 
     return dbSetMock; 
    } 
} 

を助けるそして、あなたはこのようにそれを使用することができます。

//Arrange 
var data = new List<Model.WorkflowState>(); 
//you would populate your list as needed. 
//convert it to a mock DbSet that uses the list as its datasource 
var workflowStateSet = data.AsDbSetMock(); 
var dbSet = workflowStateSet.Object; 

//Act 
var items = dbSet.Where("Your expression here"); 

//Assert 
//.... 
1

リポジトリパターンを使用して、抽象化のレイヤーをデータ検索に追加します。次に、この抽象化を嘲笑することができます。

の場合は、例えば、あなたがインターフェイスを作成し、別のクラスにこの

var result = DbSet.WorkflowState.Where(w => w.stateId == 1); 

動くようにこのコードを何かを呼び出すのではなく、その後、1に等しいSTATEIDとワークフローをすべて取得し、しようとしていましたメソッドシグネチャの呼び出し元のコードでは

public interface IWorkflowStateSetRepository{ 

    IQueryable<Model.WorkflowState> GetAllWorkflows(int state); 
} 

実装

public class WorkflowStateSetRepository : IWorkflowStateSetRepository{ 

    public IQueryable<Model.WorkflowState> GetAllWorkflows(int state){ 
     return DbSet.WorkflowState .Where(w => w.stateId == state); 
    } 
} 

は(おそらくあなたのIoCコンテナから)IWorkflowStateSetRepositoryのインスタンスを取得し、代わりにGetAllWorkflows()メソッドを呼び出します。これにより、以前と同じ結果が得られますが、テストでインターフェースをモックし、そのメソッドへの呼び出しを設定できるようになりました。

このコードはより保守的であり(適切な名前の変数とメソッドを使用して)、意図をより良く伝えます。


ここで、リポジトリパターンについて詳しく説明します。

http://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

+0

リンクはコメントではなく回答として投稿する必要があります。この場合、あなたの答えは何ですか? –

+0

私たちはここにリンクオンリーの回答が好きではありません。代わりに、この質問の対象となる部分を抽出します。 – HimBromBeere

1

あなたは本当DbSetインスタンスをモックアップしようとしていますか?エラーメッセージがあなたに説明しようとするので、これは機能しません。型を模倣するには、インタフェースであるか、仮想メンバ(抽象メンバも仮想である)を持つ必要があります。

あなたはデシベルセットで検索される設定内容にコンストラクタのパラメータを使用することができ、以下のクラスのようなもの

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Data.Entity; 
using System.Linq; 
using System.Linq.Expressions; 

public class DbSetMock<T> : DbSet<T>, IDbSet<T> 
    where T : class 
{ 
    private readonly ICollection<T> _contentCollection; 

    public DbSetMock(IList<T> contentCollection = null) 
    { 
     _contentCollection = new Collection<T>(contentCollection ?? new List<T>()); 
     AddedEntities = new List<T>(); 
     RemovedEntities = new List<T>(); 
     AttachedEntities = new List<T>(); 
    } 

    public void OverrideContentCollection(IEnumerable<T> newData) 
    { 
     _contentCollection.Clear(); 
     _contentCollection.AddRange(newData); 
    } 

    public IList<T> AddedEntities { get; private set; } 

    public IList<T> AttachedEntities { get; private set; } 

    public override ObservableCollection<T> Local 
    { 
     get 
     { 
      throw new NotImplementedException(); 
     } 
    } 

    public IList<T> RemovedEntities { get; private set; } 

    public Type ElementType 
    { 
     get 
     { 
      return typeof(T); 
     } 
    } 

    public Expression Expression 
    { 
     get 
     { 
      return _contentCollection.AsQueryable().Expression; 
     } 
    } 

    public IQueryProvider Provider 
    { 
     get 
     { 
      return _contentCollection.AsQueryable().Provider; 
     } 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     return _contentCollection.GetEnumerator(); 
    } 

    public override T Add(T entity) 
    { 
     AddedEntities.Add(entity); 
     _contentCollection.Add(entity); 
     return entity; 
    } 

    public override T Attach(T entity) 
    { 
     AttachedEntities.Add(entity); 

     var matchingEntity = _contentCollection.SingleOrDefault(x => x.Id == entity.Id); 
     if (matchingEntity != null) 
     { 
      _contentCollection.Remove(matchingEntity); 
     } 

     _contentCollection.Add(entity); 

     return entity; 
    } 

    public override TDerivedEntity Create<TDerivedEntity>() 
    { 
     throw new NotImplementedException(); 
    } 

    public override T Create() 
    { 
     throw new NotImplementedException(); 
    } 

    public override T Find(params object[] keyValues) 
    { 
     throw new NotImplementedException(); 
    } 

    public override T Remove(T entity) 
    { 
     RemovedEntities.Add(entity); 
     _contentCollection.Remove(entity); 
     return entity; 
    } 
} 

例えば、IDbSetをモックアップするか、カスタムDbSetクラスを作成しようとすることができます。

これが役に立ちます。