【问题标题】:Unit testing strategies for NHibernate RepositoryNHibernate 存储库的单元测试策略
【发布时间】:2013-08-01 08:05:44
【问题描述】:

我在一个相当大的项目中使用 NHibernate 和存储库模式,并且正在尝试建立我的服务层单元测试策略,但我遇到了一些问题。可能是我错误地处理了单元测试,也可能是我错误地处理了存储库模式,但我不确定是哪个。

我的场景的简化子集如下所示:

public class UserRepository : RepositoryBase, IRepository 
{

   public UserRepository() {}
   public UserRepository( ISession sessionParam ) {
      session = sessionParam;   // member of repository base
   }

   public string GetUsernameFromEmail( string emailAddress ) {
      return session.QueryOver<Members>().List().Where( u => u.EmailAddress.ToLowerInvariant() == emailAdrress.ToLowerInvariant() ).FirstOrDefault().Username;
   }

}

我的单元测试概念是我会伪造 NHibernate 的 ISession 并传入一个返回的用户列表,该列表适合我正在尝试测试的场景(例如,电子邮件地址不区分大小写)(我也不能让它与 FakeItEasy 一起工作,但那是另一个问题,我是否应该沿着这条路继续)。请记住,我们不应该伪造我们不拥有的对象,我可以看到不想伪造 ISession 的逻辑,并且我已经阅读了很多关于不应该如何测试存储库的内容 - 那也是单元测试远远不够。

但即使在这个非常基本的情况下,我也想对存储库中的逻辑进行单元测试。其他存储库方法可能具有更多的逻辑(例如,数据验证等)。我知道我可以使用 SqlLite 或类似的东西来为存储库构建相对快速的集成测试,但在我看来,这个逻辑仍然应该进行单元测试。

依赖于存储库,有一个 (WCF) 服务层被 Asp.Net MVC4 站点使用。

在最好的情况下,我会在 WCF 层中构建我的单元测试并伪造 IRepository 进行测试,但我不知道如何在不让所有用户从存储库并将它们返回到服务层,这看起来很荒谬。

所以我的问题是:这里的整体架构的哪一部分在我的脑海中有根本性的错误?

编辑

为了回应@Wiktor-zychla 的回答,这是我关于为什么要伪造 ISession 的逻辑。在考虑这个特定的测试时,我想让我的存储库使用 ISession 的实现,它总是返回具有混合大小写的电子邮件地址和特定用户名的单个用户,传入一个全小写的电子邮件地址,并返回值是我指示我的假使用的用户名。这样我就可以根据已知值测试我的逻辑 - NHibernate 在现实世界中是否会这样运行不是我关心的问题 - 测试存储库方法中的逻辑是。再说一次,我知道这是一个简单而幼稚的例子,可以通过许多其他方式解决 - 它只是代表我希望以后能够测试的更复杂的功能。

【问题讨论】:

    标签: c# wcf nhibernate repository-pattern


    【解决方案1】:

    我认为您不应该尝试伪造 ISession。这没有多大意义 - NHibernate 存储库是一个抽象概念的具体实现,您要测试的是这个具体实现是否可以,而不是进一步抽象它并测试什么?一个不同的假 linq 实现,然后假装 NH 遵循它?

    然后,您的单元测试应该涉及一个真实的数据库,可能在测试开始之前设置,以便您将一个临时 ISession 注入存储库,但 ISession 仍然指向一个真实的数据库。

    另一方面,当您测试使用存储库的服务时,将另一个存储库实现注入您的服务层是完全有效的。

    【讨论】:

    • 感谢您的评论@Wiktor。我担心的是,一旦我介绍了一个实际的数据库,我们就不再谈论单元测试——那些是集成测试,我绝对必须这样做,但这不是我在这里要问的。
    • 没有必要。这正是您需要考虑进一步抽象是否有意义的边缘情况之一。我对此的看法(我相信我会同意我的多数)是你不能可靠地伪造一个 linq 提供程序,这是对它进行单元测试所必需的。我的回答基本上是“不要在你似乎被吸引的意义上对此进行单元测试”。
    • 从您的评论中,我相信您正试图将过多的责任置于存储库层。重要的处理、验证等应该在上层完成,从而使其易于测试。想一想 - 你会在同一个存储库接口的两个或多个实现中复制相同的验证或处理逻辑吗?
    • 我愿意相信 :-)
    • 最终结果:我将存储库模型更改为更加通用,并在将结果集返回到服务层之前延迟过滤结果集,并将逻辑移动到服务层,将存储库模拟为需要。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多