2014-01-11 16 views
7

私は嘲笑で新しいです。 Entity Framework 6 DbContextに依存するベースリポジトリをモックアップしたいのですが、失敗します。 Googleでたくさん検索しましたが、十分な結果が得られませんでした。やっと私はtesting with async queriesの例を得て、それに従うことを試みるが、それは私のために働いている。ここEntity Framework 6非同期メソッドを模擬する方法は?

は私のコードである:

DbContext:

public class TimeSketchContext : DbContext 
{ 
    public virtual DbSet<EmployeeSkill> EmployeeSkill { get; set; } 
} 

ベースリポジトリ:

public class BaseRepository<T> : IRepositoryBase<T> where T : class, IEntity, new() 
{ 
    protected readonly DbContext InnerDbContext; 
    protected DbSet<T> InnerDbSet; 

    public BaseRepository(DbContext innerDbContext) 
    { 
     InnerDbContext = innerDbContext; 
     InnerDbSet = InnerDbContext.Set<T>(); 
    } 

    public virtual Task<T> FindAsync(long id) 
    { 
     return InnerDbSet.FirstOrDefaultAsync(x=>x.Id == id); 
    } 

}

試験:

[Fact] 
    public async Task DbTest() 
    { 
     var dummyData = GetEmployeeSkills(); 
     var mockSet = new Mock<DbSet<EmployeeSkill>>(); 

     mockSet.As<IDbAsyncEnumerable<EmployeeSkill>>() 
      .Setup(x => x.GetAsyncEnumerator()) 
      .Returns(new TestDbAsyncEnumerator<EmployeeSkill>(dummyData.GetEnumerator())); 

     mockSet.As<IQueryable<EmployeeSkill>>() 
      .Setup(x => x.Provider) 
      .Returns(new TestDbAsyncQueryProvider<EmployeeSkill>(dummyData.Provider)); 

     mockSet.As<IQueryable<EmployeeSkill>>().Setup(m => m.Expression).Returns(dummyData.Expression); 
     mockSet.As<IQueryable<EmployeeSkill>>().Setup(m => m.ElementType).Returns(dummyData.ElementType); 
     mockSet.As<IQueryable<EmployeeSkill>>().Setup(m => m.GetEnumerator()).Returns(dummyData.GetEnumerator()); 

     var mockContext = new Mock<TimeSketchContext>(); 
     mockContext.Setup(c => c.EmployeeSkill).Returns(mockSet.Object); 

     var baseRepository = new BaseRepository<EmployeeSkill>(mockContext.Object); 

     var data = await baseRepository.FindAsync(1); 

     Assert.NotEqual(null, data); 

    } 

    private EmployeeSkill GetEmployeeSkill() 
    { 
     return new EmployeeSkill 
     { 
      SkillDescription = "SkillDescription", 
      SkillName = "SkillName", 
      Id = 1 
     }; 
    } 

    private IQueryable<EmployeeSkill> GetEmployeeSkills() 
    { 
     return new List<EmployeeSkill> 
     { 
      GetEmployeeSkill(), 
      GetEmployeeSkill(), 
      GetEmployeeSkill(), 
     }.AsQueryable(); 
    } 

結果は次のとおりです。

Assert.NotEqual()失敗

私はこの問題は

public BaseRepository(DbContext innerDbContext) 
{ 
    InnerDbContext = innerDbContext; 
    InnerDbSet = InnerDbContext.Set<T>(); <<<<<<<<<<< 
} 

だと思うしかし、なぜ、どのようにこの問題を解決するために理解し `tを。

私が使用しています:

  • のVisual Studio 2013究極
  • 部品番号
  • のxUnit

Thank`sを事前に。

+1

将来の読者のために:あなたが例えばDbContextをどこにでも注入することができます。リポジトリ/インターフェイスに抽象化することはできません。非仮想的なものであることを絶対に嘲笑する必要があります.Microsoft Fakes Assembliesを使用して、これを実現できますオブジェクト上の非仮想メソッドの代替実装を提供できるようにするものです。 –

+1

EFユニットテストツールである「Effort」(https://effort.codeplex.com/)をチェックすることを強くお勧めします。このツールは、テストするためにメモリ内に実際のEFデータベースを作成します。私たちはEFを嘲笑することで頭を悩ませましたが、今日の終わりには、EFモックをテストすることは、リンゴとオレンジの大失敗です。 (一例として、模擬テストではL2EではなくL2Oを使用しています) – RJB

+0

それは素晴らしいツールに見えます。何でもありがとう@RJB –

答えて

8

問題はあなたのInnerDbContext.Set<T>();ステートメントにあります。 EFの現在のバージョンで

(6.0.2)DbContext.Set<T> methodはないvirtualは、それが部品番号と嘲笑することができないあります。

だから、簡単に全体DbContextではなく、1 DbSet<T>に依存しないようにBaseRepositoryのデザインを変更する以外に、あなたのテストパスをすることはできません。

だから、のようなもの:

public BaseRepository(DbSet<T> dbSet) 
{ 
    InnerDbSet = dbSet; 
} 

次に、あなたがすることができますあなたのモックされたDbSetに直接渡してください。

public interface IDbContext 
{ 
    DbSet<T> Set<T>() where T : class; 
} 

public class TimeSketchContext : DbContext, IDbContext 
{ 
    public virtual DbSet<EmployeeSkill> EmployeeSkill { get; set; } 
} 

は、その後、あなたのBaseRepositoryIDbContextを使用します:

それともDbContextのためのラッパー・インターフェースを作成することができます

public class BaseRepository<T> : IRepositoryBase<T> where T : class, IEntity, new() 
{ 
    protected readonly IDbContext InnerDbContext; 
    protected DbSet<T> InnerDbSet; 

    public BaseRepository(IDbContext innerDbContext) 
    { 
     InnerDbContext = innerDbContext; 
     InnerDbSet = InnerDbContext.Set<T>(); 
    } 

    public virtual Task<T> FindAsync(long id) 
    { 
     return InnerDbSet.FirstOrDefaultAsync(x => x.Id == id); 
    } 
} 

そして最後に、あなたはそれを作るためにあなたのテストで2行を変更する必要があります合格:

var mockContext = new Mock<IDbContext>(); 
mockContext.Setup(c => c.Set<EmployeeSkill>()).Returns(mockSet.Object); 
+0

メソッドが 'FindAsync'ですが、実装は' FirstAndDefaultAsync'であるため、下降しています。 – Razort4x

関連する問題