使用来自LINQ DataContext的模拟数据创建服务层
本文关键字:数据 模拟 创建 服务 DataContext LINQ | 更新日期: 2023-09-27 18:16:54
我使用的是LINQ-to-SQL
和ASP。NET MVC 4,到目前为止,我有一个与真实数据库联系的存储库层。当我想进行单元测试时,这不是很好。
在存储库层中也不应该有逻辑,所以这就是为什么我想模拟LINQ DataContext
,这样我就可以创建一个服务层,它可以与模拟DataContext
或真正的DataContext
对话。
我看到我的LINQ DataContext类继承了DataContext
,但是没有接口,所以我不能真正模拟它。我还看到DataContext使用Table<>
类,并且存在一个接口ITable
,所以我可能可以模拟它。我的LINQ DataContext
也是一个部分类,所以也许我可以以某种方式操纵?
当我谷歌这个的时候,所有的文章都是2008年的,已经过时了。谁能给我指路吗?
这是我想做的一个例子。我将为每个控制器设置单独的服务类。
public class MyServiceClass
{
IDataContext _context;
// Constructors with dependency injection
public MyServiceClass()
{
_context = new MyRealDataContext();
}
public MyServiceClass(IDataContext ctx)
{
_context = ctx;
}
// Service functions
public IEnumerable<ModelClass> GetAll()
{
return _context.ModelClass;
}
public ModelClass GetOne(int id)
{
return _context.Where(s => s.ID == id).SingleOrDefault();
}
}
虽然。net 4+中仍然支持Linq-to-Sql,但是为了支持实体框架,它已经被推迟了。这可能就是为什么你发现的大多是旧文章。
无论如何,最好的方法是编写自己的DataAccess层接口,通过应用程序使用。然后,您可以拥有该接口的实现,该接口使用您的linq-to-sql进行生产,并为您的单元测试使用模拟实现。使用依赖注入实例化实际的实现类。
对于创建模拟实现,您可以手动完成(在您的测试项目中创建一个实现IDataContext接口但返回硬编码数据的类)或使用其中一个模拟框架。
我没有使用每一个,但moq是相当不错的。微软现在也在Visual Studio 2012中推出了名为Fakes的框架,值得一看。
使用moq的例子
var expectedResultList = new List<ModelClass>(){ ... };
var mockDataContext = new Mock<IDataContext>();
mock.Setup(c => c.GetAll()).Returns(expectedResultList);
MyServiceClass service = new MyServiceClass(mockDataContext.Object);
var list = service.GetAll();
Assert.AreEqual(expectedResultList, list);
在这段代码中,您设置了模拟对象,以便在调用GetAll方法时它将返回您期望的列表。通过这种方式,您可以根据数据访问的不同返回值轻松测试业务逻辑。
IDataContext示例
public interface IDataContext<T>
{
IEnumerable<T> GetAll();
T GetById(int id);
int Save(T model);
}
public class LinqToSqlDataContext<T> : IDataContext<T>
{
private DataContext context = new DataContext();
public IEnumerable<T> GetAll()
{
// query datacontext and return enumerable
}
public T GetById(int id)
{
// query datacontext and return object
}
public int Save(T model)
{
// save object in datacontext
}
}
public class MyFirstServiceClass
{
private IDataContext<MyClass> context;
public MyFirstServiceClass(IDataContext<MyClass> ctx)
{
this.context = ctx;
}
....
}
public class MySecondServiceClass
{
private IDataContext<MySecondClass> context;
public MyFirstServiceClass(IDataContext<MySecondClass> ctx)
{
this.context = ctx;
}
....
}