我正在抽象我的DbContext,试图解决关注点分离问题,并使我的代码单元可测试。为了做到这一点,我想出了以下界面。
下面的此接口托管在名为AllInterfaces的程序集中。由于以下声明中的IDbSet,此项目引用了EF dll。
public interface ISalesContext : IDisposable
{
IDbSet<Customer> Customers { get; }
IDbSet<Order> Orders { get; }
IDbSet<Product> Products { get; }
}
我还创建了一个伪数据库集,如下所示。
public class FakeDataSet<T> : IDbSet<T> where T: class, new()
{
.......
}
因此,对于我的Customer对象,这个伪数据集如下所示。
public class FakeCustomerDbSet : FakeDbSet<Customer>
{
..............
}
然后我创建了我的假上下文如下。
public class FakeSalesContext : ISalesContext
{
public FakeSalesContext ()
{
Customers = new FakeCustomerDbSet ();
}
public IDbSet<Customer> Customers { get; set; }
public IDbSet<Order> Orders{ get; private set; }
public IDbSet<Product> Products { get; private set; }
public void Dispose()
{
}
}
以上所有与伪对象相关的类(FakeDataSet、FakeCustomerDbSet和FakeSalesContext)都位于程序集中AllFakes。我不得不添加对EF dll的引用,因为IDbSet接口也在这些伪类中被引用。
然后我有了我的单元测试项目,我使用假对象来执行单元测试。
ISalesContext Context = new FakeSalesContext ();
Context.Customers.Add(new Customer() { Id = 1, LastName = "Karen" } );
问题是,这个单元测试要求我添加对实体框架dll的引用。如果我删除EF引用,我会得到以下编译错误。
类型"System.Data.Entity.IDbSet"1"是在程序集中定义的未被引用。必须添加对程序集的引用'EntityFramework,版本=4.4.0.0,区域性=中性,PublicKeyToken=b77a5c561934e089'。
如果我从AllFakes程序集中删除EF dll引用,我会得到以下错误。
找不到类型或命名空间名称"IDbSet"(您是缺少using指令或程序集引用?)
向所有这些程序集添加对EF dll的引用有意义吗?对我来说,既然我已经抽象了数据库上下文,这里就不需要它了。关于如何做到这一点,有什么建议吗?
我认为您需要对EF dll的引用。您确实对上下文进行了抽象,但您的抽象仍在使用EntityFramework.dll中定义的IDbSet接口。FakeSalesContext公开IDbSet类型的公共属性,如果您不添加对EntityFrameworkdll的引用(其中定义了IDbSet),则不会编译,因为编译器将不知道IDbSet是什么。
在这种情况下,我认为它没有问题。只要您只测试DbContext
实现,引用本身只用于上下文对象的依赖关系解析。