繁体   English   中英

是 mocking 数据库集<t> .Find() 在 Generic 上的正确方式?</t>

[英]Is mocking DbSet<T>.Find() on Generic the right way?

在 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:将签名的 where T: class 更改为某种 where T: IFindable 我始终使用.ID 作为属性,这样就可以了,但是随后需要我将一堆 IFinables 添加到我的不可测试类中,这丑陋,或者

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

#2可能是我会做的。 它很丑,但至少它包含在这个测试助手中,并且不需要对非测试代码的回推。

有没有人有更聪明的方法来处理它?

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

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

我们使用测试替身对 EF Core 进行内部测试。 但是,我们从不尝试模拟 DbContext 或 IQueryable。 这样做是困难的、麻烦的和脆弱的。 不要这样做。


如果你想继续mocking,你可以试试这个:

dbSet.Setup(d => d.Find(It.IsAny<int>())).Returns<int>(id => (T)sourceList.OfType<IFindable>().FirstOrDefault(x => x.ID == id));

这样你只需要在你正在测试的类上实现IFindable

此外,我会调用IFindable IEntity

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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