什么是测试驱动开发 (TDD)?示例
什么是测试驱动开发 (TDD)?
测试驱动开发 (TDD) 是一种软件开发方法,其中开发测试用例以指定和验证代码的功能。简而言之,首先为每个功能创建和测试测试用例,如果测试失败,则编写新代码以通过测试,并使代码简单且无 bug。
测试驱动开发从为应用程序的每个小功能设计和开发测试开始。TDD 框架指示开发人员仅在自动化测试失败时才编写新代码。这避免了代码重复。TDD 的全称是 Test-driven development。
TDD 的简单概念是在编写新代码(开发之前)之前编写并更正失败的测试。这有助于避免代码重复,因为我们一次只编写少量代码以通过测试。(测试只不过是我们需要测试以满足它们的需求条件)。
测试驱动开发是在实际应用程序开发之前开发和运行自动化测试的过程。因此,TDD 有时也称为测试优先开发。
如何执行 TDD 测试
以下步骤定义了如何执行 TDD 测试,
- 添加测试。
- 运行所有测试,查看是否有任何新测试失败。
- 编写一些代码。
- 运行测试并重构代码。
- 重复。
TDD 循环定义
- 编写测试
- 使其运行。
- 修改代码使其正确,即重构。
- 重复过程。
关于 TDD 的一些澄清
- TDD 方法既不是关于“测试”,也不是关于“设计”。
- TDD 并不意味着“编写一些测试,然后构建一个通过测试的系统”。
- TDD 并不意味着“进行大量测试”。
TDD 与传统测试
以下是测试驱动开发与传统测试的主要区别
TDD 方法主要是一种规范技术。它确保您的源代码在确认级别得到彻底测试。
- 使用传统测试,成功的测试会发现一个或多个缺陷。这与 TDD 相同。当测试失败时,您已经取得了进展,因为您知道需要解决问题。
- TDD 确保您的系统实际满足为其定义的要求。它有助于建立您对系统的信心。
- 在 TDD 中,更关注生产代码,以验证测试是否正常工作。在传统测试中,更关注测试用例设计,即测试是否会显示应用程序的正确/不正确执行以满足要求。
- 在 TDD 中,您可以实现 100% 的覆盖率测试。与传统测试不同,每一行代码都经过测试。
- 传统测试和 TDD 的结合导致了测试系统的重要性,而不是系统的完美性。
- 在敏捷建模 (AM) 中,您应该“有目的地测试”。您应该知道为什么要测试以及需要测试到什么程度。
什么是验收 TDD 和开发人员 TDD
TDD 有两个级别
- 验收 TDD (ATDD):使用 ATDD,您编写一个验收测试。此测试满足规范要求或满足系统行为。之后,编写足够少的生产/功能代码以满足该验收测试。验收测试侧重于系统的整体行为。ATDD 也被称为行为驱动开发 (BDD)。
- 开发人员 TDD:使用开发人员 TDD,您编写一个开发人员测试,即单元测试,然后编写足够少的生产代码以满足该测试。单元测试侧重于系统的每个小功能。开发人员 TDD 简称为TDD。ATDD 和 TDD 的主要目标是即时 (JIT) 地指定解决方案的详细可执行要求。JIT 意味着只考虑系统中所需的要求。因此,提高了效率。
通过敏捷模型驱动开发 (AMDD) 扩展 TDD
TDD 在详细规范和验证方面表现出色。它在考虑整体设计、系统使用或 UI 等更大问题上表现不佳。AMDD 解决了 TDD 未解决的敏捷扩展问题。
因此,AMDD 用于解决更大的问题。
AMDD 的生命周期
在模型驱动开发 (MDD) 中,在编写源代码之前创建了大量的模型。这反过来又具有敏捷方法吗?
在上图中,每个框代表一个开发活动。
构想是 TDD 过程之一,用于预测/想象项目第一周将执行的测试。构想的主要目标是确定系统的范围和系统架构。为成功构想而进行高层需求和架构建模。
它是一个不进行软件/系统详细规范的过程,而是探索软件/系统需求的过程,这些需求定义了项目的整体策略。
迭代 0:构想
主要有两项子活动。
- 初始需求构想。可能需要几天时间来确定高层需求和系统范围。主要关注点是探索使用模型、初始领域模型和用户界面模型 (UI)。
- 初始架构构想。这也需要几天时间来确定系统架构。它允许为项目设定技术方向。主要关注点是探索技术图表、用户界面 (UI) 流程、领域模型和更改用例。
迭代建模
团队必须计划每个迭代将完成的工作。
- 每个迭代都使用敏捷流程,即在每个迭代期间,将添加具有优先级的新工作项。
- 首先将考虑优先级较高的工作。添加的工作项可以随时重新确定优先级或从项目堆栈中删除。
- 团队讨论他们将如何实现每个需求。建模用于此目的。
- 对该迭代将实现的每个需求进行建模分析和设计。
模型风暴
这也称为即时建模。
- 在这里,建模会议涉及一个由 2/3 名成员组成的团队,他们在纸上或白板上讨论问题。
- 一名团队成员会要求另一名成员与他们一起建模。此建模会议大约需要 5 到 10 分钟。团队成员聚集在一起共享白板/纸张。
- 他们探索问题,直到找到问题的主要原因。即时,如果一名团队成员识别出他/她想要解决的问题,那么他/她将寻求其他团队成员的快速帮助。
- 然后其他小组成员探索问题,然后每个人像以前一样继续。它也称为站立建模或客户质量保证会议。
测试驱动开发 (TDD)
- 它促进了应用程序代码的确认性测试和详细规范。
- 验收测试(详细需求)和开发人员测试(单元测试)都是 TDD 的输入。
- TDD 使代码更简单明了。它允许开发人员维护更少的文档。
评测
- 这是可选的。它包括代码检查和模型审查。
- 这可以针对每个迭代或整个项目完成。
- 这是为项目提供反馈的好选择。
测试驱动开发 (TDD) 与敏捷模型驱动开发 (AMDD)
TDD | AMDD |
---|---|
TDD 缩短了编程反馈循环 | AMDD 缩短了建模反馈循环。 |
TDD 是详细规范 | AMDD 适用于更大问题 |
TDD 促进高质量代码的开发 | AMDD 促进与利益相关者和开发人员的高质量沟通。 |
TDD 针对程序员 | AMDD 针对业务分析师、利益相关者和数据专业人员。 |
TDD 非视觉导向 | AMDD 视觉导向 |
TDD 在软件工作方面范围有限 | AMDD 范围广泛,包括利益相关者。它涉及努力达成共识 |
两者都支持演进开发 | ——————————————– |
TDD 框架
以下是最佳测试驱动开发 (TDD) 框架列表
现在,让我们通过示例学习测试驱动开发。
TDD 示例
在这个测试驱动开发示例中,我们将定义一个密码类。对于这个类,我们将尝试满足以下条件。
密码接受条件
- 密码应为 5 到 10 个字符。
首先,在这个 TDD 示例中,我们编写满足上述所有要求的代码。
场景 1:要运行测试,我们创建类 PasswordValidator ();
我们将运行上述类 TestPassword ();
输出为 PASSED,如下所示;
输出:
场景 2:在这里我们可以看到在方法 TestPasswordLength () 中不需要创建类 PasswordValidator 的实例。实例意味着创建类的对象来引用该类的成员(变量/方法)。
我们将从代码中删除类 PasswordValidator pv = new PasswordValidator ()。我们可以直接通过 PasswordValidator. IsValid (“Abc123”) 调用 isValid () 方法。(见下图)
所以我们重构(更改代码)如下
场景 3:重构后,输出显示失败状态(见下图),这是因为我们删除了实例。因此,没有对非静态方法 isValid () 的引用。
所以我们需要通过在布尔值之前添加“static”一词来更改此方法,例如 public static boolean isValid (String password)。重构类 PasswordValidator () 以消除上述错误以通过测试。
输出
对类 PassValidator () 进行更改后,如果运行测试,则输出将为 PASSED,如下所示。
TDD 的优点
以下是软件工程中测试驱动开发的主要优点
早期缺陷通知。
- 开发人员测试他们的代码,但在数据库领域,这通常包括手动测试或一次性脚本。使用 TDD,您可以随着时间的推移建立一套自动化测试,您和任何其他开发人员都可以随意重新运行。
设计更好、更简洁、更具可扩展性的代码。
- 它有助于理解代码将如何使用以及它如何与其他模块交互。
- 它会产生更好的设计决策和更易于维护的代码。
- TDD 允许编写具有单一职责的小型代码,而不是具有多重职责的庞大过程。这使得代码更易于理解。
- TDD 还强制只编写生产代码以通过基于用户需求的测试。
重构的信心
- 如果您重构代码,可能会导致代码中断。因此,通过一套自动化测试,您可以在发布之前修复这些中断。如果在使用自动化测试时发现中断,将发出适当的警告。
- 使用 TDD,应该会产生更快、更具可扩展性、错误更少、风险最小的代码。
有利于团队合作
- 在任何团队成员缺席的情况下,其他团队成员都可以轻松接手并处理代码。它还有助于知识共享,从而使团队整体更有效。
有利于开发人员
- 尽管开发人员必须花费更多时间编写 TDD 测试用例,但调试和开发新功能所需的时间要少得多。您将编写更简洁、更不复杂的代码。
摘要
- TDD 代表测试驱动开发。
- TDD 含义:它是修改代码以通过先前设计的测试的过程。
- 它更强调生产代码而不是测试用例设计。
- 测试驱动开发是修改代码以通过先前设计的测试的过程。
- 在软件工程中,它有时被称为“测试优先开发”。
- TDD 测试包括重构代码,即更改/向现有代码添加少量代码而不影响代码的行为。
- 使用 TDD 编程时,代码变得更清晰、更易于理解。