Moqing Enity Framework 6.使用DbSet <>包含()

 yeyeye 发布于 2023-02-11 16:28

我想提出这个问题的背景.如果你愿意,可以跳过.很长一段时间以来,我一直密切关注stackoverflow和其他地方关于代码测试的正在进行的辩论,因为它与EF有关.一个阵营说,由于Linq与Objects&Sql和实现之间的差异,直接针对数据库进行测试.另一个人说通过嘲弄测试.

另一个意见分歧是使用存储库或接受DbContext和DbSet已经提供工作单元和存储库模式的问题.在我使用EF的时候,我已经尝试过这些阵营提供的各种意见组合.无论我做了什么,EF证明很难测试.

我很高兴地发现EF团队使得DbSet在EF 6中更具可模仿性.他们还提供了有关如何模拟DbSet的文档,包括使用Moq的异步方法.在处理涉及Web Api的最新项目时,我意识到如果我可以模拟EF,我可以跳过编写存储库,因为编写它们的正常原因是使事情变得可测试.在阅读了一些博客文章后,灵感来了......

- 背景结束---

实际问题是,遵循EF团队提供的关于如何使用Moq DbSet的示例代码,如果在任何代码中使用.Include(),则抛出ArgumentNullException.

关于SO的其他相关帖子

这是我的DbContext界面:

public interface ITubingForcesDbContext
{
    DbSet Wells { get; set; }

    int SaveChanges();

    Task SaveChangesAsync();

    Task SaveChangesAsync(CancellationToken cancellationToken);
}

这是我的控制器处理的主要实体

public class WellEntity
{
    public int Id { get; set; }
    public DateTime DateUpdated { get; set; }
    public String UpdatedBy { get; set; }

    [Required]
    public string Name { get; set; }
    public string Location { get; set; }

    public virtual Company Company { get; set; }

    public virtual ICollection GeometryItems
    {
        get { return _geometryItems ?? (_geometryItems = new Collection()); }
        protected set { _geometryItems = value; }
    }
    private ICollection _geometryItems;

    public virtual ICollection SurveyPoints
    {
        get { return _surveyPoints ?? (_surveyPoints = new Collection()); }
        protected set { _surveyPoints = value; }
    }
    private ICollection _surveyPoints;

    public virtual ICollection TemperaturePoints
    {
        get { return _temperaturePoints ?? (_temperaturePoints = new Collection()); }
        protected set { _temperaturePoints = value; }
    }
    private ICollection _temperaturePoints;
}

这是直接使用EF DbContext的控制器

 [Route("{id}")]
 public async Task Get(int id)
 {
        var query = await TheContext.Wells.
                                   Include(x => x.GeometryItems).
                                   Include(x => x.SurveyPoints).
                                   Include(x => x.TemperaturePoints).
                                   SingleOrDefaultAsync(x => x.Id == id);
        if (query == null)
        {
            return NotFound();
        }
        var model = ModelFactory.Create(query);
        return Ok(model);
}

最后这是失败的测试......

测试设置---

   [ClassInitialize]
   public static void ClassInitialize(TestContext testContest)
        {

            var well1 = new WellEntity { Name = "Well 1" };
            var well2 = new WellEntity { Name = "Well 2" };
            var well3 = new WellEntity { Name = "Well 3" };
            var well4 = new WellEntity { Name = "Well 4" };

            well1.GeometryItems.Add(new GeometryItem());
            well1.TemperaturePoints.Add(new TemperaturePoint());
            well1.SurveyPoints.Add(new SurveyPoint());

            well2.GeometryItems.Add(new GeometryItem());
            well2.TemperaturePoints.Add(new TemperaturePoint());
            well2.SurveyPoints.Add(new SurveyPoint());

            well3.GeometryItems.Add(new GeometryItem());
            well3.TemperaturePoints.Add(new TemperaturePoint());
            well3.SurveyPoints.Add(new SurveyPoint());

            well4.GeometryItems.Add(new GeometryItem());
            well4.TemperaturePoints.Add(new TemperaturePoint());
            well4.SurveyPoints.Add(new SurveyPoint());

            var wells = new List { well1, well2, well3, well4 }.AsQueryable();

            var mockWells = CreateMockSet(wells);

            _mockContext = new Mock();
            _mockContext.Setup(c => c.Wells).Returns(mockWells.Object);
   }

   private static Mock> CreateMockSet(IQueryable data) where T : class
    {
        var mockSet = new Mock>();

        mockSet.As>()
            .Setup(m => m.GetAsyncEnumerator())
            .Returns(new TestDbAsyncEnumerator(data.GetEnumerator()));

        mockSet.As>()
               .Setup(m => m.Provider)
               .Returns(new TestDbAsyncQueryProvider(data.Provider));

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

        return mockSet;
   }

  [TestMethod]  
   public async Task Get_ById_ReturnsWellWithAllChildData()
    {
        // Arrange
        var controller = new WellsController(_mockContext.Object);

        // Act
        var actionResult = await controller.Get(1);

        // Assert
        var response = actionResult as OkNegotiatedContentResult;
        Assert.IsNotNull(response);
        Assert.IsNotNull(response.Content.GeometryItems);
        Assert.IsNotNull(response.Content.SurveyPoints);
        Assert.IsNotNull(response.Content.TemperaturePoints);
   }

TestDbAsyncQueryProvider和TestDbAsyncEnumerator直接来自引用的EF团队文档.我已经尝试了几种不同的变体,我如何为模拟创建数据,没有任何运气.

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