如何模拟Entity Framework 6异步方法?

 龙帅1314的爱_530 发布于 2023-02-04 14:22

我是嘲笑的新手.我想模拟我的基础存储库,它依赖于Entity Framework 6 DbContext但是我失败了.我在Google搜索了很多但没有得到任何足够的结果.最后我得到了一个使用异步查询进行测试的示例,并尝试关注但它对我有用.

这是我的代码:

DbContext:

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

基础知识库:

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

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

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

}

测试:

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

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

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

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

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

        var baseRepository = new BaseRepository(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 GetEmployeeSkills()
    {
        return new List
        {
            GetEmployeeSkill(),
            GetEmployeeSkill(),
            GetEmployeeSkill(),
        }.AsQueryable();
    }

结果是:

Assert.NotEqual()失败

我认为问题是

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

但不明白为什么以及如何解决这个问题.

我在用 :

Visual Studio 2013 Ultimate

起订量

的xUnit

提前谢谢.

1 个回答
  • 你是对的,问题出在你的InnerDbContext.Set<T>();陈述中.

    在EF(6.0.2)的当前版本的DbContext.Set<T>方法是 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; }
    }
    

    然后使用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);
        }
    }
    

    最后,您只需要在测试中更改两行以使其通过:

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

    2023-02-04 14:26 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有