Entity framework 如何使DbContext在使用语句时与单元测试一起工作?

Entity framework 如何使DbContext在使用语句时与单元测试一起工作?,entity-framework,unit-testing,entity-framework-6,dbcontext,using,Entity Framework,Unit Testing,Entity Framework 6,Dbcontext,Using,我的情况是: 我正在从事一个ASP.NET MVC项目,该项目没有实现存储库模式 所有DbContext调用都是从控制器层进行的 DbContext被包装在一个using语句中,并根据内存管理而非连接池的需要进行实例化 我们需要对这些控制器进行单元测试,这意味着将DbContext注入控制器 我们没有使用IoC容器。我必须在一个无参数构造函数中创建一个新实例,并在调用控制器操作的生命周期中使用它 我不能改变这些条件中的大多数 我可以改变的条件: 如果一个可靠的选项可以取代using语句,那么就不

我的情况是:

  • 我正在从事一个ASP.NET MVC项目,该项目没有实现存储库模式
  • 所有
    DbContext
    调用都是从控制器层进行的
  • DbContext
    被包装在一个using语句中,并根据内存管理而非连接池的需要进行实例化
  • 我们需要对这些控制器进行单元测试,这意味着将
    DbContext
    注入控制器
  • 我们没有使用IoC容器。我必须在一个无参数构造函数中创建一个新实例,并在调用控制器操作的生命周期中使用它
  • 我不能改变这些条件中的大多数 我可以改变的条件:

  • 如果一个可靠的选项可以取代using语句,那么就不要使用using语句
  • 承认这段代码是不可测试的,继续在其他地方花费精力
  • 因此,我的问题是:如何将
    DbContext
    传递给构造函数,以便模拟返回的响应,但保持using语句的可靠性,因为它们往往相互矛盾

    如果我需要停止使用
    using
    语句,只要有办法确保每次执行请求的操作时上下文都被释放,我就可以了


    对此有什么想法吗?

    有这些限制很难,但并非不可能。你没有提到核心,这将使它成为一件轻而易举的事

    很可能,创建一个接受DbContext对象的构造函数。在单元测试中,创建“模拟”DbContext并将其传递给控制器。如果控制器接收到DbContext,则不会创建DbContext

    另外,在进行任何测试之前,考虑创建内存中的EF DbContext以进行测试,并在测试完成时销毁它


    在没有IOC的情况下,DI在开发TDD时是惊人的。它是为.Net Core内置的,因此这些约束是一条死胡同。

    在要测试的方法中构造DbContext与在代码中实例化依赖项的任何其他具体实例没有什么不同,这意味着您无法使用模拟依赖项进行测试。因此,我想到的直接选项是(无需更改代码/结构):

    • 为单元测试实现一个指向EF的内存中数据提供程序
    • 设置可在测试运行之间恢复的已知状态数据库。(更多的是集成测试,不太适合TDD,因为您希望测试能够非常快速、非常频繁地运行。)
    • 由于缺少DI/IoC,将其放入“不是为单元测试设计的”存储桶中
    模拟DbContext是混乱的,但确实可行。一旦您有了一个mock-able,我建议您在项目中添加一个类似Autofac的IoC容器。我不知道什么情况会阻止你引入一个IoC容器,但是如果团队担心它是一个全有或全无的重新因素,并且工作太大,那么我可以向他们保证,它可以通过对项目进行最小的更改来添加,并且不会破坏现有的代码。除了DbContext之外,如果代码没有使用DI/IoC容器,您打算如何处理其他具体的依赖关系?您不必一次性关闭所有依赖项/控制器,而是逐步改进它们

    设置容器以解析MVC控制器后,具有默认构造函数的现有控制器将不会受到影响。然后,您可以向容器注册DbContext,并调整测试中的控制器以接受构造函数中的上下文。例如,IoC容器将DbContext生存期范围设置为每个请求的实例,因此您不需要使用{}块执行
    。从那里,您的测试可以提供模拟的DbContext,而容器管理上下文的生命周期


    关于使用IoC容器生成单元测试友好的控制器/代码,我最近发布了一篇文章,介绍了如何使用Lazy dependencies/w Autofac为具有多个依赖项的类编写测试。您好,我真的不明白您的问题;您正在模拟一个
    DbContext
    ,但要处理它吗。。。你能展示一些代码吗?你用什么样的模拟框架?老福克斯,我用的是Moq.John,问题是使用存在于MVC动作中的语句。在适当的位置使用语句后,它们将忽略上下文中传递的任何内容。摆脱使用语句是OP可以控制的事情之一。相反,出于TDD目的,使用第二个构造函数,该构造函数在适合测试的DbContext中传递。最初的构造函数当然会创建一个新的DbContext并正确地处理它。(例如IDisposable)当然,使用Ninject或类似的东西进行全面的DI…:)为了嘲弄DbContext,我想向您指出。