TDD简介

178 阅读15分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 15天,点击查看活动详情

大家好,我是阿萨。TDD作为敏捷开发实践,已经被说烂了。今天就给大家简单介绍一下TDD。

测试驱动开发(TDD)是一种迭代方法,它需要在构建应用程序之前将应用程序的每个组件转换为测试用例,然后重复测试和跟踪该组件。

TDD如何工作

先来看一下一般TDD过程:

  1.首先需求说明细化后,大家就明确知道了需求开发的目标。

2.编写一个测试需求的测试用例,它一定是失败的。因为需求还未开发。

  1. 开始编写代码,确保测试通过。

4.开始重构代码,保持代码的干净整洁。

  5.不停迭代,确保所有工作完成。

它是一个持续的过程,包括重构、单元测试和编程。在编写任何实际代码之前,测试驱动开发(TDD)强调单元测试用例的创建。它要求开发人员首先构建一个测试,然后只是足够的生产代码来满足它和随后的返工。这些规格是由开发人员使用的,然后他们创建测试来演示代码应该如何运行。

测试、编码和返工是快速连续完成的。测试驱动开发的第一步是为应用程序功能的每个次要方面计划和创建测试。测试驱动的开发框架告诉程序员,只有在自动测试失败的情况下才构建新代码。这可以防止代码复制。简单地说,首先为每个功能生成并测试测试用例,如果测试失败,则生成新代码以通过测试并提供简单的、无错误的代码。

Kent Beck在20世纪90年代末创造了它作为极限编程的一个组成部分。一种更全面的软件设计方法称为极限编程(XP),它是敏捷软件开发方法的一个组成部分,引入了测试驱动开发。为了在测试的代码中发现问题,我们对一小部分代码进行了测试。

在功能测试之前,编写测试以确保应用程序适合测试。为了在测试的代码中发现问题,我们对一小部分代码进行了测试。然后将该特性投入使用。然后将该特性投入使用。测试驱动开发利用重复的快速开发周期,它通常使用一个称为“红-绿-重构”的周期。

软件项目的质量确实随着时间的推移而提高,尽管这个过程一开始看起来很慢,而且经常是在短期内完成的。足够的测试覆盖率可以作为预防措施,以防止无意中更改功能。通过自己的测试套件在本地找到问题要比让客户在生产环境中找到问题要好得多。最后但并非最不重要的是,测试套件可以捕获软件项目的需求,以便参与者能够更好地理解它。它集成了构建和测试。

除了确保代码有效之外,这种方法还有助于间接地改进项目的设计和架构,通常是通过作为TDD过程一部分的单元、功能和验收测试。测试驱动开发鼓励应用程序代码的精确定义和验证性测试。测试驱动开发的输入是开发人员测试(单元测试)和验收测试(详细需求)。

测试驱动开发使编码更容易理解。它使开发人员能够保持更少的文档更新。结果,团队编写了非常不同类型的测试,并且因为评估的是行为而不是代码的个别行,所以它们倾向于更适应未来的变化。在实际开发应用程序之前,将创建自动化测试并作为测试驱动开发流程的一部分运行。因此,测试驱动开发也称为测试优先开发。

测试驱动开发过程

红色/绿色/重构循环是解释TDD过程的常用方法。让我们来看看手头的话题。

  1. 红色阶段

作为红色阶段的一部分,用户必须为即将实现的行为创建一个测试。由于开发人员需要在没有代码的情况下构建测试,因此这是最具挑战性的阶段。即使考虑在没有代码的情况下测试什么看起来很有挑战性,但所需要做的只是改变一个人的想法。必须创建一个使用一段代码的测试,就好像它已经实现了一样。

在这个阶段,开发人员应该专注于为未来创建一个用户友好的界面。从本质上讲,如果在编写第一个测试时没有编写声明类和函数的代码,则测试甚至无法编译。测试失败与此类似。下一步是运行测试,并在修复编译错误后使测试失败。

开发人员的单元测试框架将在此时抛出一个危险信号。试图运行测试用例。因为没有代码,所以会得到编译错误。测试用例在这一点上失败了,这就是为什么它被称为红色阶段。关于代码使用的决定必须在此阶段做出。这是基于一个人的需要,而不是一个人可能认为是必要的。

  1. 绿色阶段

不需要担心如何最好地实现它,我们的目标是找到一个解决方案。编写代码是下一个阶段,但只有代码需要通过第一个测试。因为开发人员在这个阶段编写代码,所以它通常是最简单的。编译代码,然后启动框架进行单元测试。TDD新手开发人员偶尔会遇到的另一个概念障碍是生成“刚好足够”的代码以通过测试的想法。

一旦第一个测试通过,开发人员就开始创建下一个失败的测试,并不断添加代码使其通过。在这个阶段,一个人必须承担编码器的角色,完成一个简单的任务:编写一个简单的解决方案,使测试成功。编写良好、高效的代码是不必要的。它只需要通过。在此阶段,允许忽略行业标准,甚至使用重复的代码。

重构阶段将包括消除代码重复。开发人员的工作被分成两部分,以帮助理解,新编写的代码的测试也被分成两部分,以确保没有旧的测试用例失败。简单地说,这就是连续回归。在此阶段之后,开发的测试用例将被视为“处于绿色状态”。如果出现问题,可以在运行描述性测试时开始考虑改进代码库。

3.重构阶段

允许开发人员在重构步骤中改进代码,同时保持所有测试通过。在此之前,编写代码的目标是使单元测试通过。现在可以在以前的解决方案之上进行改进,因为现在对问题有了更好的理解。为了确保在重构时没有破坏任何东西,还需要进行测试。

以前,开发人员没有考虑其他因素,如设计模式、代码可维护性、可读性和质量。因为已经通过单元测试解决了业务需求,所以这个阶段的重点就是这些。开发人员正在向在重构步骤中阅读实现的程序员展示他们的能力。当重复这个过程时,测试套件会不断更新,以反映项目的进展,以及在任何给定的时间内产品代码的内容。

人们不需要担心在重构时功能丢失,因为每次代码修改并重新编译时,测试用例都会自动运行以验证功能。如果一个人看到任何东西似乎坏了,但不确定如何修复,这是可以接受的。在重复循环几次之后,有必要再看一看它,花时间完成这个阶段,并运行测试以确保它们在每次小型重构之后仍然通过。

测试驱动开发的重要性

测试驱动开发(TDD)至关重要,原因有八个。

  1. 提高代码质量

在为这段代码编写测试之前,程序员必须首先决定他们希望用这段代码完成什么。然后,它将提供的体验以及它将如何与完整代码的其他部分相匹配,由开发人员进行评估。使用测试驱动开发编写的代码质量更高,错误更少。

TDD促进了简单和可扩展代码的创建。TDD严格的指导原则将鼓励开发人员形成惯例,从而自动生成更好的代码。此外,开发人员可以通过专注于更短、更容易阅读的代码部分来减少他们的工作,这使得遵循测试需求变得更简单。

  1. 完善系统设计

在产品代码之前构建测试的另一个好处是,开发人员可以将更多的时间用于必须处理的边界用例。TDD一次只关注一个次要方面。首先编写测试时,代码更容易检查,并且具有更直接的接口。

因此,开发人员可以通过使用测试驱动的开发方法来实现应用程序的模块化、易于理解、维护、扩展、测试和重构结构。此外,在开发周期的末尾,更广泛的测试会导致更少的错误和缺陷。

3.提高开发人员的工作效率

TDD提高了开发人员调试的时间,从而提高了速度。因此,在开始阶段创建测试和生产代码可能需要更长的时间。然而,随着项目的发展,添加和测试新功能的速度会更快,返工也会更少。四个开发团队参与了微软和IBM的联合研究,该研究发现采用TDD可以减少40-90%的缺陷密度。完成项目所需的时间也增加了15%至35%,尽管由于质量的提高,较低的维护费用抵消了这一损失。

  1. 随着时间的推移降低项目成本

随着TDD的使用,项目开发的价格将大幅下降。测试驱动的开发可以显著降低项目的成本,消除潜在的缺陷,并使代码维护更易于管理。最终,以上所有的好处都会降低成本,提高团队绩效。

TDD有助于降低开发成本;问题越少,开发人员花费的时间就越少,这直接影响到项目费用。请记住,这些成本节约发生在产品的整个生命周期内。在短期内,TDD几乎总是更昂贵,因为项目需要更多的测试。

  1. 获取错误预防的帮助

TDD是一种独特的方法,当仔细地坚持时,它可以保证完整的测试覆盖。由于运行测试是TDD的主要优先级,开发人员可以确保应用程序按预期的方式运行,并且只需要进行一些小的修复。需要注意的是,在TDD环境中,开发人员更重视编写测试以在缺陷发生之前捕获缺陷,而不是在代码开发完成后修复它们。

TDD允许开发人员构建完整的测试套件,这对项目是有利的。由于有了测试套件,只要对代码库进行了彻底的测试,缺陷就不太可能未被发现。

  1. 得到永久的文档

对于开发人员来说,测试可以充当文档。人们想要利用类的方式很可能是典型开发TDD测试的场景之一。它是使用公共语言建立测试场景的特性的当前描述。基于测试中陈述的声明,用户可以看到方法所需的预期输入和预期结果。

这可以促进开发人员对系统的许多方面的理解,从而支持公共代码所有权。现在,任何开发人员都可以更改代码,而不仅仅是熟悉代码的开发人员。

  1. 创建一个可维护的代码库

TDD过程包括重做或重组工作代码,以增加可读性和优化实现。TDD过程中需要的下一步是重构,它代表现有代码的优化,并且只有一个目标,即使其更易于引入。如果通过了初始测试,开发人员可以重构一个微小的功能或改进代码以满足标准。这种测试驱动的方法和旧的代码一样有效,因为它使用相同的步骤:添加一个新的测试,运行它来检查它是否失败,创建代码,测试它,重做它,然后重复。

  1. 从可靠的过程中获益

使用TDD,开发人员和发起人都可以对创建的解决方案的可靠性充满信心。在重构或引入新特性之后,测试有助于确定是否一切都按预期工作。如果没有TDD,开发人员将无法跟踪当前的开发,并且不确定最近开发的软件将如何与之前完美的代码交互。

此外,任何新的修改都可能破坏解决方案。从本质上讲,这是TDD如何实现敏捷开发的另一个例子,同时允许开发人员更少地担心未来更改的后果。

测试驱动开发的局限性

在实现TDD时,还应该意识到它的局限性。具体如下:

  1. TDD可能会减慢开发过程

它最初会减慢开发速度,因为必须先编写测试,这在快速迭代启动的环境中可能会花费一些时间。如果你赶时间,需要马上推出产品或服务,TDD方法可能不是最好的选择。因为团队将首先专注于构建测试,所以可能无法按时完成实现代码。

一个常见的误解是TDD需要更多的时间,因此成本更高,尽管这只适用于快速完成的项目。然而,从长远来看,它加速了发展。

  1. TDD很难维护和支持

TDD最重要的缺点之一就是这一点。开发人员必须修改测试以适应产品需求的变化。您需要调整代码以适应新的测试。在任何开发方法中,基本需求修改都是昂贵的,但是对于TDD,这些范围调整可以显著地影响进度。

此外,一些团队发现,随着项目变得越来越大,维护大量单元测试变得越来越有挑战性。实际上,许多传统的单元测试,无论是否使用TDD创建,都与特定的代码实现密切相关。

3.学习TDD方法是很难的

如果扩展的团队以前从未使用过TDD方法,那么他们可能很难理解和适应TDD方法的概念。任何试图自己学习它的人都可能会发现它具有挑战性。开发人员必须高度投入,并始终渴望改进。

当架构更加直接,并且人们可能需要利用它来获得动力和快速迭代时,在项目的早期阶段采用TDD会更简单。否则,TDD会干扰为更高级的项目分配时间和资源。

因为编写代码不同于正确地编写代码,所以掌握TDD代码可能具有挑战性。TDD的功能也没有涉及;因此,许多团队只是简单地关注代码覆盖率,这几乎没有告诉人们关于代码覆盖率的任何信息。创建实际的单元测试是一种艺术形式。许多经理倾向于关注像代码覆盖率这样的度量,这些度量与单元测试的水平几乎没有关系,并且很少提出TDD的这一元素。

  1. TDD方法往往是坚定而死板的

起初,这种策略似乎有点令人生畏,因为不是每个开发人员都习惯于一次只专注于一件事情,在查看代码之前编写测试。开发商将不得不跟上这些家务。精炼这些测试以使它们运行得更快或删除重复的测试是至关重要的,因为预订越来越多的测试会导致构建变得越来越长。TDD方法可以影响代码规划;因此,为了使其有效,每个开发团队成员都必须了解并遵循其指导原则。

测试驱动开发是建立在“左移”哲学之上的,即越早开始测试和缺陷识别,就能越快地交付高质量的产品。最近,像微软这样的公司已经改进了TDD来创建测试驱动的用户意图形式化(TDUIF)。

TDUIF由微软、宾夕法尼亚大学和加利福尼亚大学开发,它结合了基于用户意图的测试,可实现90.40%的编码精度。这样的进步使得理解TDD在DevOps和软件开发过程中的作用变得至关重要。