使用来自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();
    }
}

使用来自LINQ DataContext的模拟数据创建服务层

虽然。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;
     }
     ....
}