如何模拟实体框架6异步方法? [英] How to mock Entity Framework 6 Async methods?

查看:182
本文介绍了如何模拟实体框架6异步方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是新的嘲弄。我想嘲笑我的基础信息库是依赖于实体框架6的DbContext,但我失败了。我在谷歌搜索了很多,但没有得到任何充分的结果。最后,我得到了一个例子,在测试与异步查询并努力遵循,但它工作了我的。

I am new in mocking. I want to mock up my base repository which is depend on Entity Framework 6 DbContext But I fail. I searched in Google a lot but did not get any sufficient result. At last I got an example at testing with async queries and try to follow but it is worked for me.

下面是我的code:

的DbContext:

DbContext :

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

基础信息库:

Base Repository :

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()失败

Assert.NotEqual() Failure

我觉得问题是

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

但不`吨明白为什么,以及如何解决这个问题。

But don`t understand why and how to solve this.

我使用的:

  • 的Visual Studio 2013旗舰版
  • 起订量
  • 的xUnit

Thank`s提前。

Thank`s in advance.

推荐答案

您的权利与你的 InnerDbContext.Set&LT的问题; T&GT;(); 语句。

You are right the problem in with your InnerDbContext.Set<T>(); statement.

在EF(6.0.2)中的 DbContext.Set&LT; T&GT; 方法不可以 虚拟所以不能用嘲笑起订量。

In the current version of the EF (6.0.2) the DbContext.Set<T> method is not virtual so it cannot be mocked with Moq.

所以,你不能轻易地让你的测试通过execpt改变你的 BaseRepository 的设计不依赖于整个的DbContext 但有一个 DbSet&LT; T&GT;

So you cannot easily making your test pass execpt changing your design of the BaseRepository to not depend on the whole DbContext but on one DbSet<T>:

所以是这样的:

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

然后你就可以在你的嘲笑Dbset直接通过。

Then you can pass directly in your mocked Dbset.

或者你可以创建一个包装接口的DbContext

Or you can create a wrapper interface for DbContext:

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

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

然后使用 IDbContext BaseRepository

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

最后,你只需要改变两行的测试,使其通过:

And finally you just need to change two lines in your test to make it pass:

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

这篇关于如何模拟实体框架6异步方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆