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()
方法,这也会让您遇到问题,因为它为您提供了很多方法——但这无论如何都很难。
出于测试目的,我想创建一个自动生成的 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()
方法,这也会让您遇到问题,因为它为您提供了很多方法——但这无论如何都很难。