【问题标题】:Unit testing, dependency injection and AutoMapper annotations单元测试、依赖注入和 AutoMapper 注释
【发布时间】:2017-11-03 04:28:57
【问题描述】:

我最近第一次使用 MVC 在 SQL Server 数据库上构建 CRUD 应用程序。实体框架和提供的脚手架实用程序使这非常容易。我特别喜欢如何在模型中使用数据注释来集中数据字段的标签名称、验证等。我发现 MVC 直观、有条理,而且我能够使用 Entity Framework 添加自定义功能,例如更改跟踪,而无需大量额外代码或挫败感。

然后我决定将其提升到一个新的水平并结合单元测试。事情很快变得复杂了很多。

我读到使用实际数据库进行单元测试存在问题且速度缓慢,通常不推荐使用。最好交换模拟数据库调用或使用内存数据库替代品。说得通。所以,我做的第一件事是编写一个单独的存储库层来隔离数据库调用。我很快发现,这本身是不够的。为了在测试时轻松地将一个存储库交换为另一个而不重写代码,有必要使用带有依赖注入的控制模式反转通过构造函数将正确的存储库实现注入到控制器中。由于依赖注入依赖于接口,我必须为所有存储库类添加接口定义,安装 Ninject 来管理注入并连接事物以注入正确的接口实现。我还实现了一个 Unit of Work 接口来封装更新可能多个存储库并一次提交所有更改的过程。

然后我发现,在我的 CRUD 应用程序中编辑现有记录时,内置字段映射器无法回发使用依赖注入构造的已编辑对象。这让我想到了为每个视图单独、简化的视图模型的理念,它只定义视图所需的精确字段信息,并使用 AutoMapper 将数据模型映射到每个视图模型,并在发布后再次返回。所以,经过更多的学习、安装和接线,我得到了这个工作。不幸的是,我随后发现 AutoMapper 映射项目之间的字段值时,它不会映射数据注释。这意味着我必须为每个类复制数据模型和 4 或 5 个视图模型之间的所有数据注释,以便标签、字段验证等工作。我在 SO 上找到了一些解决此问题的建议,但它们似乎并不简单或健壮。我知道这不应该是一个大问题,但这是我遇到的第一个严重障碍,我找不到合理的解决方案,这让我很烦恼。

我的问题:

  1. 有没有人有一种经过验证的方法可以让 AutoMapper 也映射数据注释?是否有另一个类似的映射器可以解决这个问题?

  2. 上述所有工作都源于一个简单的愿望,即使用替代数据库进行一些单元测试。我的项目的代码大小和复杂性从原始 MVC 项目和使用脚手架自动创建的类显着增长。我知道大家的共识是,这是组织项目进行测试以及未来开发和重构的“正确”方式,但这真的值得吗?如果我的测试只使用真实数据库的副本,我可以有一个更简单的项目。我很想听听其他人的经历和观点。

【问题讨论】:

  • 您正在以正确的方式制作一个可维护、可测试的项目(您可以通过仅仅模拟 DbContext 来跳过几个步骤),但我真正不清楚的是您所说的“映射数据注释”。
  • 如果我的数据模型中的电子邮件字段上有 [Display] 数据注释以将特定字符串显示为字段的标签,并且 [DataType] 注释以将字段值显示为可点击的电子邮件链接,如果我将该字段映射到视图模型,我希望在视图模型中应用这些相同的注释。我不想在视图模型中重新定义映射字段上的注释。
  • 一个措辞优美的问题,准确地详细说明了事情!

标签: asp.net-mvc entity-framework unit-testing automapper ninject.web.mvc


【解决方案1】:

AFAIK,您所指的数据注释(例如[Display])用于表示层。将它们放入数据库模型是没有意义的。如果将它们放入正确的层,则不必复制它们。

还有其他不属于表示层的专门用于数据层的属性(例如字段长度和表连接)。基本上,您只需要根据功能将它们分开即可。

【讨论】:

  • 我同意这些是演示项目,因此更适合与视图模型相关联。但是,如果我有多个视图模型与给定类的重叠字段,我怎样才能避免多次重新定义相同的注释?在一个完美的世界中,我想在数据模型上定义所有注释属性并让映射器使用这些属性,除非我在视图模型中使用显式注释覆盖它们。
  • 简单的答案是您编写一个具有特定功能集的视图模型。如果你有一个类似的视图但有一些不同的功能,你可以使用继承,但大多数时候它只是让事情变得复杂。创建一个新的 VM 类型并重新实现注释。大多数情况下,增加片段的数量确实会使项目看起来更复杂,但实际上你只是让它更易于维护和结构化。
【解决方案2】:

我最终只实现了一个存储库来将实际的数据库调用与控制器分开。这让我可以独立测试存储库功能,并确保我得到了预期的数据。

我认为在这种情况下,依赖注入、字段映射和重复字段注释的所有额外复杂性和开销都超过了测试的好处。特别是对于 98% 的功能是数据库访问或数据显示的 CRUD 应用程序。没有要测试的业务逻辑。

【讨论】: