【问题标题】:Implement a fake NHibernate repository实现一个假的 NHibernate 存储库
【发布时间】:2011-09-03 23:24:46
【问题描述】:

我正在使用 StoryQ 执行一些基本的集成测试,并且我们使用 NHibernate 作为我们的 ORM。 当我开始时,我不知道 NHibernate 实现了存储库模式,所以我创建了自己的 IRepository 来运行我的集成测试。

但是,考虑到 NHibernate 已经实现了 Repository 模式,我假设它是针对某种接口这样做的。所以,如果我的假设是正确的,我想反对 NHibernate 的存储库接口。

我试图搜索它,但我遇到了需要针对 ISession 接口进行操作的信息。由于我不太了解 NHibernate,有人可以解释为什么我需要针对 ISession 接口实现我的假存储库吗? NHibernate 中的 IRepository 等价物是什么?有没有更深入的教程?

【问题讨论】:

    标签: unit-testing nhibernate repository-pattern


    【解决方案1】:

    我不确定 NHibernate 核心的哪里有一个 IRepository 接口(AFAIK 没有),所以您可能指的是其他一些 NHibernate 副项目。

    这也不是模拟 ISession 的最佳方法。在我看来,最好的办法是使用 NHibernate 完全支持的真正的内存数据库。您可能需要检查如何配置 NHibernate 以在 sqlite 内存数据库上运行,这基本上只是在您的测试中配置 NHibernate。

    这种方法的好处是,测试以非常快的速度运行,就好像不涉及数据库一样,并且您不需要为了运行而抽象出所有 ORM 功能(以及松散的功能)/推动你的测试。

    【讨论】:

    • 确实,我不知道核心 NHibernate 中是否有 IRepository 接口,这正是我要问的。我会试着把它说得更清楚。我也不想去嘲笑ISession。但是,我确实希望能够针对某种允许我编写测试的接口进行编码。使用 SqlLite 绝对是一种选择。你知道有哪些教程可以帮助我入门吗?
    • @DavidS 是的...Ayende 有一个用于此目的的基类,请在此处查看ayende.com/blog/3983/nhibernate-unit-testing 谷歌搜索可能会提供更多链接
    • 谢谢你。这似乎是我正在寻找的。​​span>
    【解决方案2】:

    NHibernate 没有实现存储库模式。它取代了它。

    如果你有一个简单的数据库实现,SQLite 内存数据库会很好,但我发现事情很快就会变得很麻烦,几乎到了使用 SQLite 的痛苦程度,如果不是更多的话它是存根/模拟 ISession/ICriteria/等。

    一个完美的例子:在我最近的一个项目中,我使用 PostgreSQL 作为我的生产数据库和 SQLite 作为我的测试数据库,我需要扩展 NHibernate 以添加对最近的聚合函数的支持添加到 PostgreSQL。弄清楚如何添加它本身就是一个故事,但我解决了。然后我不得不在 SQLite 中找到一个等效的功能。我需要一个聚合函数,它的工作方式与它的 Postgres 对应物完全相同。没有。我四处询问,并被告知有一些方法可以扩展 NHibernate 以在 SQLite 中“伪造”这个函数。我还可以选择扩展 SQLite 以添加此功能。

    我想做的只是围绕我试图实现的场景编写两个甚至三个测试。我最终花了太多时间试图确保两个系统之间的功能等效。为一个功能付出所有这些努力是不值得的。如果以后我需要添加另一个功能会怎样?

    我认为 SQLite 很有用。这是一个很棒的轻量级数据库系统,我喜欢你可以方便地将它用作简单场景的内存数据库。但是,我不确定它是否值得使用。我想从现在开始,我将在所有环境中使用相同的数据库,即使这意味着对所有数据持久性逻辑进行更慢的集成测试。

    【讨论】:

    • @cs - 原则上,我不介意针对真实数据库进行测试,即使这意味着我的集成测试运行缓慢。所以我的问题是你如何在测试环境中实际切换到测试 dB,以及如何在生产环境中切换到生产 dB。我知道这可能是一个基本问题,但我不太了解 NHibernate,甚至不确定从哪里开始。
    • 就我而言,我从 web/app config 中读取了配置。生产站点从 web.config 读取,测试从 app.config 读取。您在这些配置文件中为环境提供适当的配置。有意义吗?
    • @cs - 是的。谢谢你。
    • 这确实回答了我的问题,但 Will Green 和 Hadi 的回答为实施细节提供了更多线索。
    【解决方案3】:

    我采用的方法是实现 IRepository 和 GenericRepository,以包装 ISession Save 和 Delete 方法。此外,GenericRepository 还使用 NHibernate 的 LINQ 提供程序实现 IQueryable。我的实现大量借鉴了 Javier Lozano 的 MVC Trubine 项目。他的实现在这里:https://github.com/jglozano/mvcturbine/blob/master/src/Blades/NHibernate/MvcTurbine.NHibernate/GenericRepository.cs

    这适用于我需要的大约 80% 的查询。剩下的,我创建一个查询对象来包装查询。这样,我可以使用 ICriteria、IQuery、IQueryOver 或 LINQ,无论查询的需要是什么。 Fabio Maulo 在这里解释得很好:http://fabiomaulo.blogspot.com/2010/07/enhanced-query-object.html

    这两种方法都可以轻松地模拟掉依赖关系。

    【讨论】:

    • 谢谢威尔。由于我对 NHibernate 还很陌生(另一位开发人员介绍了它),因此似乎我在这里有点不够深入,但乍一看,它确实让测试驱动开发变得更加困难。
    • IME,当我用 TDD 碰壁时,通常是因为我缺少抽象。从持久性机制(NHibernate、Linq to SQL、EF、DataReader 等)中获取实体是与 Controller、ViewModel 或 Presenter 不同的关注点。我所做的是使存储库或查询实现一个接口,以便我可以伪造它,并将该依赖项注入我的 Controller/ViewModel/Presenter。
    • 我也喜欢扩展查询对象模式。我在一个基于类型返回查询对象的查询提供程序后面进行了抽象。在测试中很容易存根/模拟。
    猜你喜欢
    • 1970-01-01
    • 2011-03-29
    • 1970-01-01
    • 2010-12-20
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 2013-01-20
    相关资源
    最近更新 更多