真实业务环境中的TDD(C#,无ASP.NET,SQL Server)

真实业务环境中的TDD(C#,无ASP.NET,SQL Server),c#,sql-server,tsql,tdd,nunit,C#,Sql Server,Tsql,Tdd,Nunit,我想让自己尽可能简短: 第一:我读过相关的帖子,但没什么帮助 请参阅: 或: 或: 背景: 我不是一个完全的TDD初学者,我知道原则 我读过Rob C Martin和MC Feathers之类的书 TDD在保龄球和Tictatcoe游戏中对我很好 但当我想在我的工作场所做TDD时,我有点不知所措。这不是嘲笑,我知道如何嘲笑依赖 更重要的是: 我什么时候编码什么 我从哪里开始 以及:何时以及如何实现“数据库”或“文件系统”代码。模拟它很酷,但在集成测试阶段,我需要id作为真实代码 想象一下(示

我想让自己尽可能简短:

第一:我读过相关的帖子,但没什么帮助

请参阅:

或:

或:

背景:

  • 我不是一个完全的TDD初学者,我知道原则
  • 我读过Rob C Martin和MC Feathers之类的书
  • TDD在保龄球和Tictatcoe游戏中对我很好
  • 但当我想在我的工作场所做TDD时,我有点不知所措。这不是嘲笑,我知道如何嘲笑依赖

    更重要的是:

    • 我什么时候编码什么
    • 我从哪里开始
    • 以及:何时以及如何实现“数据库”或“文件系统”代码。模拟它很酷,但在集成测试阶段,我需要id作为真实代码
    想象一下(示例):

    • 编写一个程序,从数据库中读取所有客户的列表
    • 与客户ID相关,它必须从csv/Excel文件中搜索数据
    • 然后,业务逻辑对它产生了魔力
    • 最后将结果写入数据库(不同的表)
    我从来没有为这样的应用程序找到过TDD示例

    编辑: 作为一名程序员,您将如何以TDD风格实现这个示例




    PS:我不是说db单元测试或gui单元测试。

    想想您正在测试的行为,并用它来驱动单个更高级别的测试。然后,在实现此功能时,使用TDD在实现此功能所需的类中消除所需的行为

    在您的示例中,我将从一个简单的无操作情况开始。(我将用BDD语言编写,但您也可以用类似的代码实现)

    这种测试将允许您在不必在模拟中实现任何东西的情况下获得一些基本功能和接口(除了检查您是否没有调用代码来完成最终编写之外)

    然后我将继续讨论一个稍微宽泛的例子

    Given there are some customers in the database
    But none of these customers are in the CSV file
    When I read customers and process the related data from the csv file
    Then no data should be written to the database
    
    我会不断增加和调整实现这一点所需的类,最初可能使用mock,但最终会使用真正的数据库交互

    不过,我会小心为每门课写一个测试。这会使您的测试变得脆弱,并且每次您进行类似于更改的小重构时,它们都需要更改。关注行为,而不是实施

    您的流程应该是这样的:


    您可以在完全没有数据库的情况下启动。只需编写一个接口,使用最基本的方法检索客户

    public interface ICustomerHandler
    {
        List<Customer> GetCustomers(int customerId);
    }
    
    公共接口ICCustomerHandler
    {
    列出GetCustomers(int customerId);
    }
    
    然后,使用模拟框架,模拟该接口,同时为将使用并引用接口实现的方法编写测试。根据需要创建新类(例如,Customer),这会让您考虑需要哪些属性

    [TestMethod()]
    public void CreateCustomerRelationsTest()
    {  
        var manager = new CustomerManager(MockRepository.GenerateMock<ICustomerHandler>());
        var result = manager.CreateCustomerRelations();
        Assert.AreEqual(1, result.HappyCustomers);
        Assert.AreEqual(0, result.UnhappyCustomers);
    }  
    
    [TestMethod()]
    public void CreateCustomerRelationsTest()
    {  
    var manager=newcustomermanager(MockRepository.GenerateMock());
    var result=manager.CreateCustomerRelations();
    Assert.AreEqual(1,result.HappyCustomers);
    Assert.AreEqual(0,result.UnhappyCustomers);
    }  
    
    编写这个伪测试告诉您需要什么类,比如CustomerManager类,它有一个方法CreateCustomerRelations和两个属性。该方法应该引用接口中的GetCustomer方法,使用注入到类构造函数中的mock实例


    做足够的事情来构建项目,并让您第一次运行测试,这将失败,因为测试的方法中没有逻辑。然而,您已经有了一个很好的开始,让测试指示您的方法应该接受哪些输入,以及应该接收和断言哪些输出。首先定义测试条件有助于创建良好的设计。很快,您将编写足够的代码,以确保测试确认您的方法设计良好,并以您希望的方式运行。

    如果我错了,请有人纠正我,但这似乎会更好地被程序员接受?我得到了我一直在寻找的答案,因此我不明白为什么这个问题会“过于宽泛”还是不清楚?对不起,我是SO的新成员,但我多年来一直是SO的“读者”。最后我给出了一个例子,我想知道其他程序员是如何以TDD风格实现的->我将在问题中补充这一点,以澄清问题“测试引导的面向对象软件的成长”是一本值得考虑的好书。谢谢,看起来很有帮助。非常好的答案,谢谢!我用SpecFlow尝试了BDD,这似乎很有希望,但在我对TDD和单元测试有了更好的理解之前,我将其搁置。你的路肯定是一条路要走。谢谢你的回答!我理解这一点,在某些情况下,我已经走了这么远。当我想到这一点时,我可能有错误的意图“从头到尾”编程——这是我“我已经习惯了”的编码风格,但不是TDD方式。但有一个问题:在实现
    ICustomHandler
    时,我该怎么做?这里没有单元测试,因为它将在集成测试中测试?很可能是的。。。由于该接口的实现将依赖于您的数据库解决方案,这使得该依赖项与代码的隔离变得复杂。它可以只包含为“CustomerManager”类提供数据所需的基本内容,而不包含任何逻辑,这使得为它构建单元测试毫无意义。我想,集成测试会发现该方法的任何错误。好的,谢谢。我想我可以从这里继续下去。
    [TestMethod()]
    public void CreateCustomerRelationsTest()
    {  
        var manager = new CustomerManager(MockRepository.GenerateMock<ICustomerHandler>());
        var result = manager.CreateCustomerRelations();
        Assert.AreEqual(1, result.HappyCustomers);
        Assert.AreEqual(0, result.UnhappyCustomers);
    }