0

我正在使用LINQ-to-SQLASP.NET MVC 4,到目前为止,我有一个与真实数据库联系的存储库层。当我想进行单元测试时,这不是很好。

存储库层中也不应该有逻辑,所以这就是我想模拟的原因,这样我就可以创建一个与模拟或真实LINQ DataContext对话的服务层。DataContextDataContext

我看到我的 LINQ DataContext 类继承了DataContext,但是没有接口,所以我不能真正模拟它。我还看到 DataContext 使用Table<>类并且存在一个 interface 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();
    }
}
4

1 回答 1

1

尽管 .NET 4+ 仍支持 Linq-to-Sql,但它已被推迟以支持 Entity Framework。这可能就是为什么您会发现大部分较旧的文章。

无论如何,最好的方法是编写您自己的 DataAccess 层接口,通过您的应用程序使用。然后,您可以拥有该接口的实现,该接口使用您的 linq-to-sql 进行生产,并为您的单元测试使用模拟实现。

使用依赖注入来实例化实际的实现类。

要创建模拟实现,您可以手动进行(在您的测试项目中创建一个实现 IDataContext 接口但返回硬编码数据的类)或使用其中的一个模拟框架。

我没有使用它们中的每一个,但起量非常好。微软现在在 Visual Studio 2012 中也有他们的框架,称为Fakes,值得一看。

起订量使用示例

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;
     }
     ....
}
于 2013-06-05T09:20:14.533 回答