首页 > 解决方案 > 如何使 DbContext 在 using 语句中与单元测试一起使用?

问题描述

我的情况是这样的:

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

我可以改变的条件:

  1. 摆脱 using 语句,如果一个可靠的选项可以取代它。
  2. 承认此代码无法按原样测试,然后继续在其他地方花费精力。

所以,我的问题是:如何将 a 传递DbContext给构造函数,以便模拟返回的响应,但保持 using 语句的可靠性,因为它们往往相互矛盾。

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

对这个有什么想法吗?

标签: entity-frameworkunit-testingentity-framework-6dbcontextusing

解决方案


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

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

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

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

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


推荐阅读