簡體   English   中英

如何模擬Entity Framework 6異步方法?

[英]How to mock Entity Framework 6 Async methods?

我是嘲笑的新手。 我想模擬我的基礎存儲庫,它依賴於Entity Framework 6 DbContext但是我失敗了。 我在Google搜索了很多但沒有得到任何足夠的結果。 最后我得到了一個使用異步查詢進行測試的示例,並嘗試關注但它對我有用。

這是我的代碼:

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>();  <<<<<<<<<<<
 }

但不明白為什么以及如何解決這個問題。

我在用 :

  • Visual Studio 2013 Ultimate
  • 起訂量
  • 的xUnit

提前謝謝。

你說得對,問題出在你的InnerDbContext.Set<T>(); 聲明。

在當前版本的EF(6.0.2)中, DbContext.Set<T>方法 不是 virtual因此無法使用Moq進行virtual

因此,除非將BaseRepository的設計更改為不依賴於整個DbContext而是依賴於一個DbSet<T>否則您無法輕松進行測試通過:

所以類似於:

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

然后你可以直接在你的模擬DbSet中傳遞。

或者您可以為DbContext創建一個包裝器接口:

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

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

然后使用IDbContextBaseRepository

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);
    }
}

最后,您只需要在測試中更改兩行以使其通過:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM