模拟验证DbSet失败,并且未验证GetEnumerator

问题描述

我正在尝试使用最小订量(moq)模拟我们的数据库。 这里的问题是,EntityFramework中的某些方法返回DbSet对象,这些对象在我的代码中使用foreach进行了迭代。

现在我致电VerifyNoOtherCalls();在定义的测试方法的末尾。但是这里的测试使我大吃一惊,因为foreach循环从IEnumerable接口调用了GetEnumerator(),我没有验证。但这是不可能的,因为DbSet本身不实现GetEnumerator(),并且moq不允许在Lambda中调用ToList()。

现在我有两个问题:

  1. DbSet如何实现IEnumerable接口,而不直接或在基类中实现GetEnumerator方法
  2. 如何运行测试?我已经在互联网上找到了一些说明,所以我决定自己模拟DbSet:
        public static DbSet<T> GetQueryableMockDbSet<T>(List<T> sourceList) where T : class
        {
            var queryable = sourceList.AsQueryable();

            var dbSet = new Mock<DbSet<T>>();
            dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
            dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
            dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
            dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
            dbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>((s) => sourceList.Add(s));

            return dbSet.Object;
        }

但是,这也不起作用。

解决方法

第一个问题,DbSet<> has an explicit implementation for IQueryable.GetEnumerator()。这样就可以将DbSet用作IEnumerable<>,而不会造成混乱的智能感知,并且通常不会直接在DbSet上调用这些方法。

我不太肯定为什么您发布的代码无法正常工作,但是您可以尝试在GetEnumerator()上模拟dbSet.AsIEnumerable<T>()

不过,在更高的层次上,我发现在嘲笑 DbSet中没有什么价值(像 service 一样对待它,您需要模拟和验证其方法) 。我将重点放在伪造上(将其像一个集合一样处理,可以指定其内容)。因此,根据我的经验,致电VerifyNoOtherCalls()可能无济于事。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...