C# NHibernate存储库的单元测试策略

C# NHibernate存储库的单元测试策略,c#,wcf,nhibernate,repository-pattern,C#,Wcf,Nhibernate,Repository Pattern,我正在一个相当大的项目中使用NHibernate和Repository模式,试图建立我的服务层单元测试策略,但我脑子里有一些问题。有可能我没有正确地进行单元测试,也有可能我没有正确地进行存储库模式,但我不确定是哪个 我的场景的简化子集如下所示: public class UserRepository : RepositoryBase, IRepository { public UserRepository() {} public UserRepository( ISession

我正在一个相当大的项目中使用NHibernate和Repository模式,试图建立我的服务层单元测试策略,但我脑子里有一些问题。有可能我没有正确地进行单元测试,也有可能我没有正确地进行存储库模式,但我不确定是哪个

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

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;
   }

}
公共类用户存储库:RepositoryBase,IRepository { 公共用户存储库(){} 公共用户存储库(ISession sessionParam){ session=sessionParam;//存储库库的成员 } 公共字符串GetUsernameFromEmail(字符串emailAddress){ return session.QueryOver().List()。其中(u=>u.EmailAddress.ToLowerInvariant()==EmailAddress.ToLowerInvariant()).FirstOrDefault().Username; } } 我的单元测试概念是,我将伪造NHibernate的ISession,并传入一个返回符合我试图测试的场景的用户列表的会话(例如,电子邮件地址不区分大小写)(我也无法将其用于Fakeitesy,但这是另一个问题,我是否应该继续此路径)。请记住,我们不应该伪造我们不拥有的对象,我可以看到不想伪造ISession的逻辑,我已经阅读了很多关于不应该测试存储库的内容——这对于单元测试来说太低了

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

依赖于存储库,Asp.NETMVC4站点正在使用一个(WCF)服务层

在最好的情况下,我会在WCF层构建我的单元测试,并伪造IRepository进行测试,但我不知道如何将此逻辑移动到服务层,而不从存储库获取所有用户并将其返回到服务层,这似乎很可笑

所以我的问题是:在这里,我的头脑中有哪一部分是根本错误的

编辑


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

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

您的单元测试应该包含一个真实的数据库,可能在测试开始之前设置好,这样您就可以向存储库中注入一个临时会话,但该会话仍然指向一个真实的数据库


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

谢谢您的评论@Wiktor。我担心的是,一旦我介绍了一个实际的数据库,我们就不再谈论单元测试了——这些是集成测试,我绝对必须做的,但这不是我在这里要问的,没有必要。这正是需要考虑进一步抽象是否有意义的边缘案例之一。我的观点是(我相信大多数人都会这么认为),你不能可靠地伪造一个linq提供者,这是单元测试的必要条件。我的回答基本上是“从某种意义上说,不要对它进行单元测试”。从您的评论中,我认为您试图将太多的责任放在存储库层上。非平凡的处理、验证等应该在上层完成,从而使其易于测试。想一想-您会在同一存储库接口的两个或多个实现中复制相同的验证或处理逻辑吗?我愿意相信:-)最终结果:我将存储库模型更改为更通用的,并在将结果集返回到服务层并将逻辑移到服务层,根据需要模拟存储库。谢谢