在Generic上模拟DbSet <T> .Find是否正确?

问题描述

在C#和EFCore中,我使用以下内容模拟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;
    }

在许多情况下都可以使用,但是我不支持EF .Find()方法

我想这样添加它:

dbSet.Setup(d => d.Find(It.IsAny<int>())).Callback<int>((s) => sourceList.Where(x => x.ID == s));

...但是由于T是泛型,所以我不能依靠ID属性进行检查。

我考虑过两种解决方法

#1:将签名的T:类更改为T:IFindable的某种形式我将.ID始终用作属性,这样就可以了,但随后我需要将一堆IFinable添加到不可测试的类,这很丑陋,或者

#2:输入一个回调,该回调使用反射来读取字段名称/值,查找ID字段并匹配值

#2可能是我会做的。这很丑陋,但至少它包含在此测试帮助器中,不需要回退到非测试代码

有人有更聪明的方式来处理它吗?

解决方法

正如其他人在评论中提到的那样,建议使用内存提供程序。

https://docs.microsoft.com/en-us/ef/core/miscellaneous/testing/

我们将测试倍数用于EF Core的内部测试。但是,我们永远不会尝试模拟DbContext或IQueryable。这样做是困难,麻烦且脆弱的。不要这样做。


如果要继续嘲笑,可以尝试以下方法:

IFindable

这样,您只需在要测试的类上实现IFindable

另外,我会打电话给IEntity {{1}}