如何使用语句单元测试使DbContext?

时间:2018-06-01 18:13:09

标签: entity-framework unit-testing entity-framework-6 dbcontext using

我的情况是:

  1. 我正在开发一个没有实现存储库模式的ASP.NET MVC项目
  2. 所有DbContext次呼叫均来自控制器层
  3. DbContext包含在using语句中并根据内存管理目的进行实例化而不是连接池目的
  4. 我们需要对这些控制器进行单元测试,这意味着将DbContext注入控制器。
  5. 我们没有使用IoC容器。我必须在无参数构造函数中创建一个新实例,并将其用于调用控制器操作的生命周期。
  6. 我无法改变大多数这些条件。
  7. 我可以改变的条件:

    1. 如果可靠的选项取而代之,请删除using语句。
    2. 承认这段代码不能直接测试,并继续在其他地方消耗能源。
    3. 所以,我的问题是:我如何将DbContext传递给构造函数,以便我可以模拟返回的响应,但保持using语句的可靠性,因为它们往往相互矛盾。

      如果我需要停止使用using语句,我可以,只要有办法确保每次执行请求的操作时都会处理上下文。

      对此有什么想法吗?

2 个答案:

答案 0 :(得分:0)

这些限制很困难但并非不可能。你没有提到Core会让这件事变得轻而易举。

最有可能的是,创建一个接受DbContext对象的构造函数。在你的单元测试中,创建你的"模拟" DbContext并将其传递给控制器​​。如果收到DbContext,Controller不会创建DbContext。

另外,在任何测试之前,请考虑创建内存中的EF DbContext用于测试目的,并在测试完成时将其销毁。

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

答案 1 :(得分:0)

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

  • 实现内存数据提供程序,将EF指向单元测试。
  • 设置可在测试运行之间恢复的已知状态数据库。 (更多的集成测试,不太适合TDD,您希望测试可以非常快速地运行。)
  • 由于缺少DI / IoC
  • ,将其置于“不是为单元测试而设计”的存储桶中

模拟DbContext很麻烦,但可行。一旦你有一个模拟器,我会建议在项目中添加一个像Autofac这样的IoC容器。我不知道会阻止你引入IoC容器的情况,但是如果团队担心它是一个全有或全无的因素而且工作量太大,那么我会向他们保证它是可以添加对项目的最小更改,并且不会破坏现有代码。除了DbContext之外,如果代码没有使用DI / IoC Container,您打算如何处理其他具体依赖?您不必一次性切换所有依赖项/控制器,而是逐步改进它们。

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

关于使用IoC容器制作单元测试友好的控制器/代码,我最近发布了一篇关于使用Lazy依赖项/ w Autofac的文章,以便为具有多个依赖项的类编写测试。您可以在https://medium.com/@StevePy/writing-easily-testable-code-with-autofac-lazy-properties-f9c63457c8ce

阅读