Unit testing 单元/集成测试nHibenrate查询

Unit testing 单元/集成测试nHibenrate查询,unit-testing,nhibernate,tdd,integration-testing,Unit Testing,Nhibernate,Tdd,Integration Testing,场景:我需要编写一个复杂的nHibernate查询,它将返回预计的DTO,但我想使用TDD方法。方法如下所示: public PrintDTO GetUsersForPrinting(int userId) { Session.QueryOver<User>().//some joins, conditions etc. //returns projected dto } GetUsersForPrinting(int-userId)的公共打印数据 { Sess

场景:我需要编写一个复杂的nHibernate查询,它将返回预计的DTO,但我想使用TDD方法。方法如下所示:

public PrintDTO GetUsersForPrinting(int userId)
{
     Session.QueryOver<User>().//some joins, conditions etc.
     //returns projected dto
}
GetUsersForPrinting(int-userId)的公共打印数据
{
Session.QueryOver()。//某些联接、条件等。
//返回预计的dto
}
问题:

  • 因为最常见的方法是使用内存中的数据库进行此类操作。我应该写集成测试吗
  • 如果我使用内存数据库,我可以写单元测试吗
  • 一次测试就够了吗
  • 由于我的集成测试可能会检查投影,我应该如何命名它?“GetUserForPrinting\u return\u correct\u DTO”似乎太抽象和愚蠢了
  • 我这样问是因为:

    • 有很多关于TDD和集成测试的抽象信息,但是当涉及到具体的实现时,应用这些信息是非常困难的
    • TDD建议集成测试应包括单元测试:

      • 学习TDD时,这不是一个很好的问题。我假设您还不知道复杂的查询是什么样子的,您希望使用测试驱动技术来驱动它。真棒:)

        但让我们看看我是否能回答你的问题

      • 任何包含真实db的测试,无论是在内存中还是在磁盘上,都不是单元测试。单元测试将使用模拟数据库

      • 也许-如果你的查询足够复杂,那么就不会了

      • testGetUsersForPrinting或GetUsersForPrinting测试或类似测试

      • 我很可能会在SQL解释器中执行查询,而不是在代码中。其目的是根据我在此过程中所学到的知识,针对内存中的db生成一系列集成测试。 从你能想到的最小可能的DTO开始,然后从那里开始构建

        最后将查询转换为nhibernate调用,然后使集成测试通过

        测试驱动,但不是真正的单元测试驱动

        如果您愿意接受最大限度的TDD原则,并处理比平时工作更慢和更烦人的问题,那么您可以在开发每个集成测试并编写代码以使其通过时将其自动化。这意味着您要在3个抽象级别/编辑器/环境(直接SQL查询、集成测试、c#code)之间频繁切换—我通过设置技术来处理这一问题,每次都要强迫自己遵循正确的步骤

        最后一点就是为什么这不是学习TDD的好问题。你将需要很多你可能还没有强迫自己学会的纪律

        祝你好运


        好的,一些具体的例子。我将修改您的代码示例,使其如下所示

        public PrintDTO GetUsersForPrinting(int userId, ISession session)
        {
             var data = session.QueryOver<User>().//some joins, conditions etc.
        
             return data; // or whatever
        }
        
        在您的集成测试中,您将使用一个真实的数据库,您的会话对象将实际连接到它,查询将针对该数据库进行解析

        ArrangeActAssert是组织单元测试的标准方法。 通常,您希望在单元测试中获得尽可能少的断言。您将有多个单元测试。 编写单元测试时,首先编写断言,然后填写其余部分,使其编译/获得所需的结果。首先让测试失败,因为当测试通过时,你就知道你已经真正交付了一些东西

        在本例中,要实现stub-ISession,您将从ISession派生一个本地StubSession类(仅对测试套件可见),只需填写绝对最小值即可编译,并返回最小数据即可通过测试


        要构建整个DTO—假设您知道您想要在DTO中获得什么—请按照您在评论中所说的,以增量方式进行。建立DTO的每个部分 一次一个工件,为每个工件添加一个单元测试

        跟踪这是TDD规程的另一部分

        为自己设置一个待办事项列表——只是一个简单的文本文件,或者在测试套件开始时可能有一个冗长的注释。列出所有要测试的内容,例如零结果、一个结果、两个结果、20个结果。用户id,您需要的任何其他信息。 如果要跨表执行复杂查询,或者为每个联接、where子句的每个部分等添加todo项。 如果您正在使用,请添加订购和分页等项目

        首先选择最简单的事情。一次只做一件小事(在一个红-绿重构周期中)。在处理列表时,您可能希望将项目分解为更小的部分,或者您可能会想到需要做的其他事情。将它们添加到待办事项列表中,而不是直接处理它们

        在这种特殊情况下,我会在每个红-绿重构周期之后,切换到SQL环境和/或sqlite集成测试中,以确定如何使下一个工作正常。我猜这是介于红色和绿色之间的一种步骤——选择下一步要测试的内容,编写测试(显然失败),在SQL中四处游荡,直到知道如何通过测试,编写nHibernate调用使测试变为绿色,然后重构

        请注意,你列出的一些事情可能没有必要,或者花费太长时间,等等。最好还是把它们写下来,这样你就知道你在做什么,也知道你在做什么。专注于你的目标

        我也倾向于开发一个“气味”和/或重构的列表,我可以看到我想要做的,但还没有为这个周期做好准备。记住尽量减少重复/重构测试以及SUT(测试中的系统)

        这是做而不是看的事情。您最终得到的单元测试列表,以及它们执行的代码,并不能很好地描述这个过程。Kent Beck最初的TDD书很薄,会给你一些很好的总体指针,但实际上并不是关于构造查询的

        这些有帮助吗

        因为最常见的方法是使用内存中的数据库进行此类操作。我应该写信吗
        public testDTO()
        {
            //Arrange
            StubSession session = .... setup a stub session, which returns hardcoded values
        
            // Act
            PrintDTO users = GetUsersForPrinting(111, session);
        
            // Assert
            Assert.That(users.size(), Is.EqualTo(1));    
            Assert.That(users.get(0).userId, Is.EqualTo(111));
        
        }