.net - 存储库本身通常不经过测试?

标签 .net unit-testing nhibernate entity-framework domain-driven-design

对不起,我是存储库模式、单元测试和 orm 工具的新手。

我一直在研究单元测试和存储库模式,并得出了一些结论,不知道我是否正确。

存储库模式有助于在使用它的 Controller 中替换单元测试,例如,对吗?因为创建上下文(在 EF 中)或 session (在 NH 中)的 stub /伪造更难,对吗?存储库本身没有经过测试?为什么?

将 EntityFramework 或 NHibernate 与存储库模式一起使用,如果我想测试我的存储库,我需要进行集成测试吗?因为如果我使用上下文/ session 的虚假实现,我就没有进行真正的测试?因为上下文/ session 本身就是存储库(我的意思是它们实现了添加、删除、编辑、GetById、GetAll 等真正的逻辑)?

带有 EF 或 NH 的存储库模式就像一个包装器? (不仅仅是一个包装器,我知道这是域的一个导入概念。)

最佳答案

在这种情况下,我会严格区分 EF 和 NH,并且我不会在同一问题中包含这两种技术。简单的 NH 更成熟,并且具有导致代码更容易测试的架构。同样在 NH 的情况下,您可以简单地将数据库切换到另一个(如 SQLite),它仍然可以正常工作,这在 EF 的情况下不一定是真的,其中切换数据库可能导致测试完全不同的应用程序 - 特别是如果您可以在 MS 和非 MS 数据库之间切换。

什么是存储库?让我们看看 Martin Fowler's definition :

A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Client objects construct query specifications declaratively and submit them to Repository for satisfaction. Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes. Conceptually, a Repository encapsulates the set of objects persisted in a data store and the operations performed over them, providing a more object-oriented view of the persistence layer. Repository also supports the objective of achieving a clean separation and one-way dependency between the domain and data mapping layers.



不错的定义。现在想想DbSet的目的:
  • 它是否在内存收集中起作用?是的,您可以使用它从数据库中获取实体或使用 Local属性以获取已加载的实体。
  • 客户端可以声明性地查询规范吗?是的,它被称为 linq-to-entities。
  • 可以从集合中添加或删除对象吗?是的,它可以。
  • 映射是否封装?是的。
  • 有干净的分离吗?在逻辑上是的。在 API 方面没有因为暴露 IDbSet域模型将使域模型依赖于技术 - EF。有问题吗?理论上是的,对于纯粹主义者来说是的,但在 99% 的情况下,这真的不是问题,因为您需要更改 API 的情况很少见,即使您正确分离了 API,它也总是涉及大的更​​改。
  • DbSet是一个存储库。使用 DbSet 的唯一区别直接并将其包装到某个通用存储库中是一种分离。这导致我以前对类似问题的回答 - Generic Repository With EF 4.1 what is the point

    现在您的应用程序中存储库的目的是什么?我看到你之前的问题包括this one您在哪里拥有您的 BaseRepository建立在 Entity Framework 之上。如果您认真地将其作为基础存储库,它将成为您的专门存储库的父存储库,这些存储库处理域模型的聚合根并公开仅与特定公开实体类型相关的专门方法,那么是的 - 您正在使用存储库模式并且您需要它。但是如果你只是包装上下文和单个集合并调用这个存储库,你很可能只创建了具有可疑附加值的冗余层,因为那只是 DbSet 之上的包装器。 .

    在这种情况下,您的存储库( DbSet 包装器)只有一种情况才有意义:
  • 包装器永远不会暴露 IQueryable (链接到实体)
  • 包装器永远不会接受 Expression<>并将其内部传递给 IQueryalbe (链接到实体)

  • 这是唯一可以为您提供完全可模拟的存储库的方案 => 您的 上层可以很容易地进行单元测试。您不会对存储库进行单元测试,也不会模拟存储库中使用的上下文。存储库包装了数据访问和映射逻辑——在存储库的情况下唯一合理的测试是集成测试。这个场景有什么问题?您将失去 LINQ 的全部功能,您将不得不包装/重新实现一些在 EF 中实现的方法和类型。这种存储库与使用存储过程包装数据访问时使用的存储库相同。

    如果你不遵循那个场景,你的生活会容易得多。您将拥有由 LINQ 定义的查询,但您将无法对代码进行单元测试,因为没有模拟/伪造仍会将查询评估为 linq-to-entities。一旦你 mock DbSetIQueryable您将使用 linq-to-object,它是 linq-to-entities 的超集。您可以轻松编写一个查询,该查询将通过模拟 DbSet 的测试。但在运行时失败,真正的 DbSet . Here更多关于这个问题和here是将通过测试但在运行时失败的查询示例。在这种情况下,您必须对使用存储库顶部的 linq-to-entities 查询的所有方法使用集成测试(使用真实数据库)。

    关于.net - 存储库本身通常不经过测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7110981/

    相关文章:

    c# - 命名空间 'WindowsAzure' 中不存在类型或命名空间名称 'Microsoft'

    javascript - 如何在 JavaScript 中模拟 pg?

    javascript - 使用 Modernizr 的单元测试代码

    javascript - 创建一个 Fake DOM 以在 JavaScript 测试套件中进行测试

    mysql - NHibernate mysql 从相关表中获取数据

    c# - 关闭 C#/C++ DLLImport 或至少释放其堆内存?

    .NET "Send error report to [me]"

    c# - ASP.Net 身份注销所有 session

    c# - 如何以引用为标准进行 NHibernate 查询?

    c# - NHibernate SessionFactory 线程安全问题