【敏捷开发】测试驱动开发(TDD)

测试驱动开发(Test-Driven Development,简称TDD)是敏捷开发模式中的一项核心实践和技术,也是一种设计方法论。TDD有别于以往的“先编码,后测试”的开发模式,要求在设计与编码之前,先编写测试脚本或设计测试用例。

一、TDD概念

敏捷开发大师Kent Beck在1996年提出了极限编程(Extreme Programming,简称XP)。TDD是其四个核心实践之一。【注:参见【架构基础】简单设计原则】

TDD在敏捷开发模式中被称之为“测试优先的编程(test-first programming)”,而在IBM Ration统一过程(Rational Unified Process,RUP)中被称为“测试优先的设计(test-first design)”。所有这些,都在强调“测试先行”,使得开发人员对所做的设计或所写的代码有足够的信心,同时也有保障地进行设计或代码的快速重构,有利于快速迭代、持续交付。重构的前提就是测试就绪(testing is ready),在这样的前提下,重构的风险就很低,否则就会存在比较高的风险。

TDD具体实施过程,可以嵌入到两个层次,如下图所示:

  1. 狭义TDD:在代码层次,在编码之前写测试脚本,可以称为单元测试驱动开发(Unit Test Driven Development,简称UTDD)。
  2. 广义TDD:在业务层次,在需求分析时,就确定需求的验收标准,即验收测试驱动开发(Acceptance Test Driven Development,简称ATDD)。

 

二、UTDD

先来谈谈UTDD,基本流程如下图所示。

  1. 红(RED):在做某个新需求时,先不着急编写功能代码,而是把需求涉及的场景、约束等考虑清楚,先写好测试用例。然后执行单元测试代码,结果自然是不通过(失败)。
  2. 绿(GREEN):利用单元测试的失败反馈,查明功能代码未通过测试用例的原因,针对性地添加或修改代码,直到测试用例通过。
  3. 重构(REFACTOR):在所有单元测试用例执行成功的基本前提下,识别代码或设计上的坏味道,进行重构。通过现有的单元测试用例,来保证重构的正确性。

 

UTDD的三条规则

  1. 规则1 除非是为了使得一条失败的unit test通过,否则不允许编写任何功能代码。

违反第1条,先编写了功能代码,那这段代码是为了实现什么需求呢?怎么确保它真的实现了呢?

  1. 规则2 在一个单元测试中,只允许编写恰好能够导致失败的测试代码。

违反第2条,写了多个失败的测试用例,如果长时间不能通过测试,会增加开发者的压力。另外,测试可能会被重构,这时会增加测试的修改成本。

  1. 规则3 只允许编写恰好能够使一条失败的unit test通过的功能代码。

违反第3条,功能代码实现了超出当前测试的功能,那么这部分代码就缺少测试的防护,不确定是否正确,需要额外增加手工测试。可能这是不存在的需求,那就凭空增加了代码的复杂性。如果是现实存在的需求,那后面的测试用例写出来就会直接通过,破坏了UTDD的节奏感。

UTDD从根本上改变了开发人员(Developer,简称DEV)的思维方式,DEV不能再像过去那样随意地写代码,要求所写的每行代码都是有效的代码,写完所有的代码就意味着真正完成了开发任务。而在此之前,所谓的代码写完了,实际上只是完成了一半的工作,因为单元测试还未执行,可能会存在许多缺陷。

UTDD有力地促进DEV去思考需求的应用场景、异常处理或约束,写出更加完善的功能代码。其次,UTDD确保了测试的独立性。如果先写功能代码,再进行测试,容易受到实现思维的影响。多数情况下,DEV自测时存在两大障碍:思维障碍和心理障碍,前者会导致DEV无法保证测试的客观性和全面性;后者会导致DEV对自己的代码不愿深究,即使发现了一些疑问,也很可能会适可而止。

最后,UTDD确保了所有功能代码的可测试性,彻底地保证了代码的微观质量,最终实现了可测试的系统。

三、ATDD

通常,在一个大型项目中,推行UTDD比较困难,而在业务层面推行ATDD,即在设计与开发之前,明确需求特性的验收标准,则相对比较容易推广实施。

在敏捷开发模式中,由需求拆分出来的用户故事(User Story,简称US),一般描述简单,不具备可测试性。

举个例子

开发一个在线旅游APP,提供交通、酒店、景点门票等预订服务,有一个最基本的US:作为一名旅游用户,想通过一次操作,快速删除事先预订的订单包(含机票、酒店和门票)。

对于这种US,如果不附加验收标准,DEV实现起来很容易:在数据库的某个表中删除一条记录,在其他关联表上修改相应的标志位即可。但实际业务不会如此简单,订单说取消就取消?不需要有一个取消的时间提前量?取消一定成功吗?是否要收取手续费?是否需要线下处理时间?是否需要通知用户?采用何种方式通知用户取消成功或失败?

回答上述问题,就需要增加“验收标准”,如:

  1. 订单取消之前,需要提醒用户再次确认
  2. 提示用户需要提前24个小时取消
  3. 订单取消需要4个小时处理时间,才能确定取消成功与否
  4. 订单取消需要收取总金额10%的手续费
  5. 不管取消成功与否,采用邮件和短信双重通知
  6. 用户事后可以查询订单取消的记录
  7. 需要保留客户和APP双向操作记录日志

如此,US就具备了可测试性,DEV也更明白如何去实现,实现的结果和产品经理的期望更容易达成一致。

从ATDD演化出一种可具体落地的开发模式就是行为驱动开发(Behavior Driven Development,简称BDD)。BDD最初是由Dan North在2003年命名,它包括验收测试、客户测试驱动等XP实践。作为对TDD的回应,主要是从用户的需求出发,强调系统行为。BDD将验收标准进一步明确化,可看作是ATDD的实例化,即列出US涉及的应用场景并表达为Given-When-Then范式:

  1. Given:给定什么上下文/条件 AND/OR 其他条件
  2. When:当什么事件被触发
  3. Then:产生什么结果 AND/OR 其他结果

BDD再往前推进一步,就是需求实例化(Requirements By Example,简称RBE),更加明确需求的具体表现。需求描述越明确,需求干系人(用户、产品经理、DEV与TSE等)之间的理解就越趋近一致,不容易产生偏差或误解,有利于开发和测试的工作。基于RBE,DEV编写需求的功能代码,TSE可以独立编写测试代码,产品经理的工作也会变得轻松,不需要太多的解释,不需要回答开发与测试的各种问题。

  1. 从需求角度看,BDD和需求实例化比较彻底地明确需求,统一用户、产品经理、DEV与TSE等人员的认知,让大家在同一个层面上沟通,使得研发工作更高效。
  2. 从测试角度看,需求即测试,产品的需求就是测试的需求,需求可以被执行,即一步到位,将需求变为自动化测试脚本,开发出来的功能特性随时可以被验证。

TDD一改以往的破坏性测试的思维方式,提倡“测试先行”,更符合“缺陷预防”的思想。这样一来,开发的思维方式发生了很大的变化,编写出高质量的功能代码去通过这些测试,在进行每一项设计、编写每一行代码时,都要想想用户的真实需求、应用场景和一些例外情况等,确保实现的功能特性符合预期,并具有健壮性。测试也从以前的破坏性的方法,转移到一种建设性的方法中来。在这种积极心态的影响下,DEV的工作效率和产品代码的质量都会显著地提高,真正实现“质量是内建的(Quality is built in)”的目标。

四、TDD的价值

TDD从业务层次(需求分析、软件设计),促进做正确的事,即设计出符合用户需求包括功能需求与非功能需求的软件特性。

TDD从代码层次(软件开发、软件测试),促进正确地做事,即开发出与设计完全一致的软件功能。

TDD充分体现了“测试先行,小步迭代,快速反馈”的敏捷思想,从微观代码到宏观系统,均践行着“要想跑得快,先要跑得稳”的目标。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/24665.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

1310. 数三角形

题目链接:https://www.acwing.com/problem/content/1312/ 首先不考虑三点共线的情况一共有 种,现在来计算三点共线的情况 1.三点在一条直线上 2.三点在一条竖线上 3.三点在一条斜线上,正反斜线对称,仅需考虑一边的情况 如果…

docker安装mysql

安装mysql docker pull mysql:8.0.31 单机启动: docker run -itd --name mysql1 -p 3305:3306 -e MYSQL_ROOT_PASSWORD123456 mysql:8.0.31 --lower_case_table_names1 单机指定配置文件启动: docker run \ --name mysql-8 \ -d \ -p 3306:3306 …

14-5_Qt 5.9 C++开发指南_基于HTTP 协议的网络应用程序

文章目录 1. 实现高层网络操作的类2. 基于HTTP协议的网络文件下载3.源码3.1 可是化UI设计3.2 mainwindow.h3.3 mainwindow.cpp 1. 实现高层网络操作的类 Qt 网络模块提供一些类实现 OSI 7 层网络模型中高层的网络协议,如 HTTP、FTP、SNMP等,这些类主要是…

Netty使用和常用组件辨析

Netty 使用和常用组件 简述 <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId <version>4.1.42.Final </version> <scope>compile</scope> </dependency> Netty 的优势 1 、 AP…

【小吉带你学Git】idea操作(2)_版本和分支的相关操作

&#x1f38a;专栏【Git】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【Counting Stars 】 欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f354;版本⭐首先创建一个项目⭐添加暂存区⭐提交本地库&#x1f33…

压力测试与测试工具jmeter的介绍

目录 一、性能指标 二、jmeter &#xff08;一&#xff09;JMeter 安装 &#xff08;二&#xff09;JMeter 压测示例 1、添加线程组 2、添加 HTTP 请求 3、添加监听器 4、启动压测&查看分析结果 &#xff08;三&#xff09;JMeter Address Already in use 错误解决 压力测…

yum出现Could not retrieve mirrorlist解决方法

Loaded plugins: fastestmirror, security Loading mirror speeds from cached hostfile Could not retrieve mirrorlist http://mirrorlist.centos.org/?release6&archi386&repoos error was 14: PYCURL ERROR 6 - “Couldn’t resolve host ‘mirrorlist.centos.org…

monaco,monaco-editor,monaco-editor-webpack-plugin,

Monaco "Monaco"是包含了Monaco Editor和Monaco Language Server两个项目的总称&#xff0c;而"Monaco Editor"是Monaco项目中的一个部分&#xff0c;它是一款基于Web技术的高性能代码编辑器。 Monaco Language Server是一个支持多种语言的语言服务器&am…

【web逆向】全报文加密及其登录流程的分析案例

aHR0cHM6Ly9oZWFsdGguZWxkZXIuY2NiLmNvbS9zaWduX2luLw 涉及加密库jsencrypt 定位加密点 先看加密的请求和响应&#xff1a; 全局搜索加密字段jsondata&#xff0c;这种非特定参数的一般一搜一个准&#xff0c;搜到就是断点。起初下的断点没停住&#xff0c;转而从调用栈单步…

HJ52 计算字符串的编辑距离

题目&#xff1a;HJ52 计算字符串的编辑距离 题解&#xff1a; 定义dp方程&#xff0c;dp[i][j] 表示字符串s1(1-i)&#xff0c;到字符串s2(1-j)的编辑距离&#xff1b; 如果s1[i] s2[j] 证明当前位置的字符相等&#xff0c;无需操作&#xff0c;即dp[i][j] dp[i-1][j-1]; …

K8S系列文章之 kubeasz部署K8S环境

自动化安装方式&#xff08;kubeasz&#xff09;* 生产环境推荐&#xff08;首次安装下载相关配置和安装包&#xff09;是基于Ansible实现的部署工具 简单介绍 每一具体k8s集群的详细配置参数文件 Ansible 任务配置文件 镜像安装包 安装部署步骤 前提 &#xff1a; 保证Ansib…

Python web实战之 Django 的模板语言详解

关键词&#xff1a; Python、web开发、Django、模板语言 概要 作为 Python Web 开发的框架之一&#xff0c;Django 提供了一套完整的 MVC 模式&#xff0c;其中的模板语言为开发者提供了强大的渲染和控制前端的能力。本文介绍 Django 的模板语言。 1. Django 模板语言入门 Dj…

npm发布包

1.npm 登录 在控制台输入命令 npm login 按提示输入用户名&#xff0c;密码&#xff0c;邮箱后登录 如果出现如下提示 需要将淘宝镜像源切换为npm源&#xff0c;删除或注释以下内容就行 2.发布 进入准备发布的代码的根目录下&#xff0c;输入命令 npm publish 3.删除已发…

PostgreSql pg_ctl 命令

一、概述 控制 PostgreSQL 服务的工具。 二、语法 --初始化数据库实例 pg_ctl init[db] [-D datadir] [-s] [-o initdb-options]--启动数据库实例 pg_ctl start [-D datadir] [-l filename] [-W] [-t seconds] [-s] [-o options] [-p path] [-c]--停止数据库实例 pg_ctl sto…

区块链和WEB3.0有哪些基础知识呢

区块链基础知识 常用区块链基础知识包括&#xff1a; &#xff08;1&#xff09;区块链概念&#xff1a;区块链是一种去中心化的分布式账本技术&#xff0c;它通过加密算法和共识机制保证了数据的安全性和不可篡改性。区块链中的每一个区块都包含了前一个区块的哈希值&#x…

怎么学习CSS相关技术知识? - 易智编译EaseEditing

学习CSS技术是前端开发中的重要一环&#xff0c;它用于控制网页的样式和布局&#xff0c;使网页更加美观和易于使用。以下是学习CSS技术的几个方面&#xff1a; 基本语法和选择器&#xff1a; 了解CSS的基本语法&#xff0c;学习如何使用选择器来选择HTML元素并应用样式。 样…

一条sql语句在mysql中如何执行(查询+更新)

文章目录 一 MySQL 基础架构1.1 MySQL 基本架构1.2 Server 层基本组件介绍1) 连接器2) 查询缓存(MySQL 8.0 版本后移除)3) 分析器4) 优化器5) 执行器 二 语句分析2.1 查询语句2.2 更新语句为什么要用两个日志模块&#xff0c;用一个日志模块不行吗?为什么必须有“两阶段提交”…

MySQL的索引使用的数据结构,事务知识

一、索引的数据结构&#x1f338; 索引的数据结构&#xff08;非常重要&#xff09; mysql的索引的数据结构&#xff0c;并非定式&#xff01;&#xff01;&#xff01;取决于MySQL使用哪个存储引擎 数据库这块组织数据使用的数据结构是在硬盘上的。我们平时写的代码是存在内存…

根据今天全量的数据以及昨天全量的数据,获取今天增量的数据

编写了一个根据今天的全量的数据以及昨天全量的数据&#xff0c;自动获取今天增量数据的脚本。 #!/bin/bashhive_db"" hive_result_tb"" hive_source_tb"" hive_source_last_tb"" hive_pk""initParam(){# 库名hive_db${1}# …

Qt中JSON的使用

一.前言&#xff1a; JSON是一种轻量级数据交换格式&#xff0c;常用于客户端和服务端的数据交互&#xff0c;不依赖于编程语言&#xff0c;在很多编程语言中都可以使用JSON&#xff0c;比如C&#xff0c;C&#xff0c;Java&#xff0c;Android&#xff0c;Qt。除了JSON&#x…