简体   繁体   中英

Mocking database context class with DbSet instead of IDbSet in Entity Framework

I am developing an Asp.Net mvc application. I am doing unit testing to my application. I use Moq to mock objects. In my test I need to mock database context and its DbSets. I can mock database context and test. But the problem is I have to change from DbSet<Entity> Entities to IDbSet<Entity> Entities in context class.

This is example of how I mock context class

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

This is context class

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

        }

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

        }
    }

When I use IDbSet instead of DbSet, my application goes down in performance. Because I cannot use as below

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

So I changed from IDbSet to DbSet in context class as below

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

Then unit tests start throwing errors. Because items of context class cannot be mocked with the way I am mocking. Below is the screenshot of errors.

在此处输入图片说明

So I changed from IDbSet to DbSet in Unit Test. Then the errors become like this.

在此处输入图片说明

How can I mock DbSet entities of context class for unit tests?

After the question update I can reproduce your problem. You have just forget to cast to the correct interface 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());

If you want to know why you must cast to make it possible to setting the provider that because the explicit interface implementation of the IQueryable. More info :https://msdn.microsoft.com/en-us/library/aa288461(v=vs.71).aspx

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM