Entity Framework: 可以完全模拟 DbContext 吗?

Entity Framework: Can a DbContext be fully mocked?

出于测试目的,我想创建一个自动生成的 EF 上下文的模拟 class(首先是数据库)。 为此,我生成了一个匹配接口并使自动生成的 class 实现该接口(只需将接口添加到 T4 模板即可)。所以现在我的 EF 上下文看起来像这样:class MyContext : DbContext, IContext

IContext 具有 MyContext 和 DbContext 的所有属性。 下一阶段是创建一个实现相同接口的模拟 class。所以现在我还有:class MyContextMock : IContext.

现在是有问题的部分:我的部分代码使用了 DbContext 的 属性,名为 Configuration,类型为 DbContextConfiguration(此 属性 允许我关闭 "auto detect changes" 功能) .问题是现在我需要为我的模拟创建一个 DbContextConfiguration 实例,但 DbContextConfiguration 只有内部构造函数并且它没有实现任何接口。这意味着我无法直接创建它的实例,也无法继承它(感谢 Microsoft)。

我已经成功地使用反射创建了一个 DbContextConfiguration 实例,但遗憾的是它无法使用。我可以提供有关此尝试的更多详细信息,但这就像深入内部对象实例化的深兔子洞,我看不出这种方法将如何工作。

那么 Entity Framework 真的是不可模仿的吗?或者有什么我可以做的吗?

它比您尝试做的要简单得多,当然可以模拟 DbContext。这是一个很好的 article/tutorial 开头:

https://msdn.microsoft.com/en-us/library/dn314429.aspx

假设您使用的是 EF 6+

在您的特定情况下,将 method/property 添加到您的 IContext 似乎是一个更好的选择,它可以切换 AutoDetectChanges 功能:

public interface IContext {
    //....
    bool AutoDetectChanges { get; set; }
    bool LazyLoadingEnabled { get; set; }
    //etc..
}

您甚至可以将其包装成某种配置 class:

public interface IContext {
    //....
    IContextOrmOptions Options { get; set; }

}

public interface IContextOrmOptions {
    bool AutoDetectChanges { get; set; }
    bool LazyLoadingEnabled { get; set; }
    //etc..
}

//real implementation
public class EntityFrameworkContextOrmOptions : IContextOrmOptions {
    private DbContext _dbContext;
    public EntityFrameworkContextOrmOptions(DbContext dbContext) {
        dbContext = _dbContext; 
    }
    public bool AutoDetectChanges {
        { get { return _dbContext.Configuration.AutoDetectChangesEnabled; } }
        { set { _dbContext.Configuration.AutoDetectChangesEnabled = value; } }
    }
}

不幸的是,这种方法有点破坏你系统的 ORM 不可知性,也许你有办法避免这种代码?

如果您想模拟 .Entry() 方法,这也会让您遇到问题,因为它为您提供了很多方法——但这无论如何都很难。