在实体框架中使用DbSet而不是IDbSet模拟数据库上下文类

时间:2016-07-10 18:31:16

标签: entity-framework mocking dbcontext dbset mockdbset

我正在开发一个Asp.Net mvc应用程序。我正在对我的应用程序进行单元测试。我使用Moq来模拟对象。在我的测试中,我需要模拟数据库上下文及其DbSet。我可以模拟数据库上下文和测试。但问题是我必须在上下文类中将DbSet<Entity>实体更改为IDbSet<Entity>实体。

这是我如何模拟上下文类

的示例
[TestMethod]
    public void GenerateItemCode_IncreaseDigit()
    {
        var data = new List<Item>{
            new Item{
                Id = 2,
                ItemCode = "CD345678"
            }
        }.AsQueryable();
        var dbSetMock = new Mock<IDbSet<Item>>();
        dbSetMock.Setup(m => m.Provider).Returns(data.Provider);
        dbSetMock.Setup(m => m.Expression).Returns(data.Expression);
        dbSetMock.Setup(m => m.ElementType).Returns(data.ElementType);
        dbSetMock.Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

        var storeContext = new Mock<StoreContext>();
        storeContext.Setup(x => x.Items).Returns(dbSetMock.Object);

        ItemRepo itemRepo = new ItemRepo(storeContext.Object);
        string itemCode = itemRepo.GenerateItemCode();
        Assert.AreEqual(itemCode, "CD345679");
    }

这是上下文类

 public class StoreContext : DbContext, IDisposable
    {
        public StoreContext():base("DefaultConnection")
        {

        }

         public virtual IDbSet<Item> Items { get; set; }
 protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {

        }
    }

当我使用IDbSet而不是DbSet时,我的应用程序性能下降。因为我不能使用如下

context.Items.Include("Promotions")//Cannot use Include with IDbSet
context.Items.AddRange(items)//cannot use AddRange with IDbSet
context.Items.RemoveRange(items)//cannot with IDbSet

所以我在上下文类中从IDbSet更改为DbSet,如下所示

public virtual DbSet<Item> Items { get; set; }

然后单元测试开始抛出错误。因为上下文类的项目不能用我嘲笑的方式来模拟。以下是错误的屏幕截图。

enter image description here

所以我在单元测试中从IDbSet更改为DbSet。然后错误变成这样。

enter image description here

如何为单元测试模拟上下文类的DbSet实体?

1 个答案:

答案 0 :(得分:1)

问题更新后,我可以重现您的问题。你只是忘了转换到正确的界面IQueryable:

  var dbSetMock = new Mock<DbSet<Item>>();
      dbSetMock.As<IQueryable<Item>>().Setup(m => m.Provider).Returns(data.Provider);
      dbSetMock.As<IQueryable<Item>>().Setup(m => m.Expression).Returns(data.Expression);
      dbSetMock.As<IQueryable<Item>>().Setup(m => m.ElementType).Returns(data.ElementType);
      dbSetMock.As<IQueryable<Item>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

如果您想知道为什么必须进行强制转换,以便可以设置提供程序,因为IQueryable的显式接口实现。更多信息:https://msdn.microsoft.com/en-us/library/aa288461(v=vs.71).aspx