我对测试驱动开发(TDD)非常陌生,还没有开始使用它。 但我知道我们必须先编写测试,然后编写实际代码以通过测试并重构它,直到设计良好。
我对TDD的担忧是它在系统开发生命周期(SDLC)中的位置。 假设我有一个制作订单处理系统的需求。 现在,如果没有任何模型或设计,我如何开始编写测试? 难道我们不需要定义实体及其属性才能继续吗? 如果不是,是否可能开发一个大型系统而没有任何设计?
我对测试驱动开发(TDD)非常陌生,还没有开始使用它。 但我知道我们必须先编写测试,然后编写实际代码以通过测试并重构它,直到设计良好。
我对TDD的担忧是它在系统开发生命周期(SDLC)中的位置。 假设我有一个制作订单处理系统的需求。 现在,如果没有任何模型或设计,我如何开始编写测试? 难道我们不需要定义实体及其属性才能继续吗? 如果不是,是否可能开发一个大型系统而没有任何设计?
有两种TDD,一种是ATDD或验收测试驱动开发,另一种是由单元测试驱动的普通TDD。
我猜TDD和设计之间的关系受到了“敏捷”概念的影响,即源代码是软件产品的设计。许多人通过将TDD翻译为测试驱动设计而不是开发来强化这一点。这是有道理的,因为TDD应该被视为与驱动设计相关的内容,而不是测试。拥有验收和单元测试只是一个很好的附带效果。
如果不了解更多信息,我不能太多地谈论它在您的SDLC中的适用性,但一个不错的工作流程是:
对于每个用户故事:
当然,整个时间您都会考虑系统逐渐演变的高级设计。理想情况下,TDD会在较低层面上产生灵活的设计,允许适当的高级设计随着进展而演变,而不是试图在开始时猜测它。我使用测试驱动的开发方式来编程,从经验可以说它有助于创建更健壮、专注和简单的代码。我的TDD步骤大致如下:
你已经完成了。你编写了实现功能所需的最少代码,并且由于测试,你知道它是健壮的。你还将能够检测到未来是否出现问题。如果发现任何错误,请添加单元测试以测试该错误(例如,您可能没有考虑到边缘情况)。而且你知道,如果你为你的代码添加更多功能,你不会使它与使用你的功能的现有代码不兼容。
我喜欢这种方法。让我感觉温暖和舒适。
TDD意味着有一些现有的设计(外部接口)可以开始。您必须心中有某种设计,才能开始编写测试。有些人会说TDD本身需要较少详细的设计,因为编写测试的行为为设计过程提供了反馈,但这些概念通常是正交的。
你需要一些形式的规范,而不是一种设计形式——设计关注的是你如何实现某个东西,规范则关注你将要实现什么。
我见过的大多数与TDD(和其他敏捷流程)一起使用的规范形式是user stories——这是一种非正式的“用例”,通常用有些固定模式的英语句子来表达,比如“作为一个,我可以……”(用户故事的形式在具体的风格/流程中会更或少严格)。
例如,“作为客户,我可以开始一个新订单”,“作为客户,我可以向我的现有订单添加条目”等等,如果您的“订单输入”系统是这样的话,那么这可能是典型的(当然,如果该系统不是用户“自助”使用,而是旨在由销售代表代表用户输入订单,则用户故事将非常不同 - 没有知道所指的订单输入系统是什么类型,就无法明智地继续进行,这就是为什么我说您确实需要一些关于系统将要做什么的规范,尽管通常还没有完整的关于如何做到这一点的想法)。让我分享我的观点:
如果你想要构建一个应用程序,在这个过程中你需要测试它,例如通过代码检查来检查你创建的变量的值,或者快速放置一个按钮,当你点击它时会执行一部分代码并弹出一个对话框来显示操作的结果等。另一方面,TDD改变了你的思维方式。
通常情况下,你只依赖于开发环境(如Visual Studio)来在编码和编译过程中检测错误,并且在你的头脑中,你知道需求并且只是通过按钮和弹出窗口或代码检查来进行编码和测试。这是一种语法调试驱动的开发方式。但是当你使用TDD时,它是一种“语义调试驱动的开发方式”,因为你首先使用测试(它们是白板的更动态和可重复版本)来写下你的应用程序的思路/目标,这些测试测试你的应用程序的逻辑(或“语义”),并且即使你的应用程序通过了语法错误(编译),只要有语义错误,测试就会失败。
在实践中,您可能不知道或没有构建应用程序所需的所有信息。由于TDD强制您首先编写测试,因此您被迫在开发的早期阶段就询问有关应用程序功能的更多问题,而不是一开始就构建很多内容,只发现您编写的大量内容并非所需(或者至少目前不需要)。尽管最初可能不会感觉如此,但使用TDD确实可以避免浪费宝贵的时间。