How to add an item to a Mock DbSet (using Moq)

后端 未结 2 971
悲&欢浪女
悲&欢浪女 2020-12-23 12:25

I\'m trying to set up a mock DbSet for testing purposes. I used the tutorial here, http://www.loganfranken.com/blog/517/mocking-dbset-queries-in-ef6/ and slightly modified i

相关标签:
2条回答
  • 2020-12-23 13:08

    To handle .Find(), we can use reflection in a similar manner, with a few assumptions about conventions when utilizing Find.

    (hopefully this isn't out of line, I've had this Q/A bookmarked for years, and was looking for a Find implementation...)

    Implement another helper as so:

    static object find(IEnumerable<object> oEnumerable, object[] keys)        
    {
        // assumptions: primary key of object is named ID
        // primary key of object is an int
        // keys passed to .Find() method is a single value of int type
        foreach (var o in oEnumerable)
        {
            var t = o.GetType();
            var prop = t.GetProperty("ID");
            if (prop != null)
            {
                if (prop.PropertyType == typeof(int))
                {
                    if ((int)prop.GetValue(o) == (int)keys[0])
                    {
                        return o;
                    }
                }
            }                
        }
        return null;
    }
    

    and in the mock setup example provided by Daniel above:

    dbSet.Setup(d => d.Find(It.IsAny<object[]>())).Returns((object[] oArray) => find(sourceList, oArray) as T);
    

    Beacuse we have no way (or desire, usually) to determine the primary key in the way that EF would, I'm making the assumption that "ID" is the key field name (which matches my own conventions), but this could be expanded upon to accept a number of variations. I'm also assuming that only one integer is passed to Find (as is my standard convention), but this could also be expanded on for more robust support.

    0 讨论(0)
  • 2020-12-23 13:19

    myDbSet is not real implementation of DbSet but a mock which means it's fake and it needs to be setup for all methods you need. The Add is not exception so it needs to be set up to do what you need otherwise it does nothing.

    Add something like the following and when the myDbSet.Add("d"); is called then the 'd' is added to the list and can be returned later.

    dbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>((s) => sourceList.Add(s));
    

    Complete code

    private 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;
    }
    

    Output

    hello debug
    preCount = 3 postCount = 4
    
    0 讨论(0)
提交回复
热议问题