01|TDD演示(1):任务分解法与整体工作流程

2022-03-16 徐昊
《徐昊·TDD 项目实战 70 讲》
课程介绍


讲述:徐昊

时长:大小5.82M


你好,我是徐昊。今天我们来聊聊测试驱动开发(Test-Driven Development,TDD)。
测试驱动开发,顾名思义,就是将软件需求转化为一组自动化测试,然后再根据测试描绘的场景,逐步实现软件功能的开发方法。
在正式开始学习 TDD 之前,我想通过四节课的时间,来演示如何通过 TDD 的方式完成一段完整的功能,让你对 TDD 的做法有个感性的认识。毕竟,我想很多人对 TDD 心存质疑,最主要还是因为不光没吃过猪肉,其实也没见过猪跑吧。

TDD 的基本原则

为了让我的演示更有针对性,有些基本原则你需要先了解一下。TDD 的创始人 Kent Beck,在他的传世大作 Test-Driven Development by Example 的开篇中给出了 TDD 的基本原则:
当且仅当存在失败的自动化测试时,才开始编写生产代码;
消除重复。
不过在今时今日,我认为第二条应该改为“消除坏味道(Bad Smell)”。毕竟重复仅仅是一种坏味道,还有很多...

展开全文
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。

精选留言

  • Alexdown
    置顶
    2022-03-19
    Go语言实现: https://github.com/longyue0521/TDD-In-Go/tree/args 提交历史记录: https://github.com/longyue0521/TDD-In-Go/commits/args (用vscode对比提交记录看更方便) 1. TDD其实是三项已有技术的重组 —— 先大概设计,再落地测试,再重构出最终代码 1) 设计能力:软件设计原则/思想/模式 2) 测试能力:测试技术/方法/工具 3) 重构能力:代码坏味道,重构方法/工具 2. 需求拆分一般有两种方式 1) 任务列表 —— 从无到有实现各个功能点,从内到外,比如实现Option和ListOption等 2) 测试列表 —— 通过所有测试即表示实现功能,Outside-in,从外部API一点一点向内推 希望老师多提供案例,带领大家多多练习以提升需求拆分这项能力——解决测试从哪来的问题 3. 为什么一定要先看到红灯? 1) 测试的正确性如何保证?你不可能再为测试写测试,你需要看到测试以你预期的方式失败! 2) 如果你没看到红灯,要么测试有问题,要么代码已提前实现(推荐把代码改错,强制看到红灯) 3) 红灯表示“缺少功能/实现错误”,“以终为始”失败测试就是那个“终”帮助确定产品代码缺少当前失败测试所捕获的“功能”. 4) 此阶段的目标:确定“终”后需努力不落空! 4. 为什么一定要快速看到绿灯? 1) 关注点分离,“终”已经由失败的测试确定,代码只要通过“终”即可. 2) 代码硬编码,僵化,设计不好等问题,要么是“终”不够多,要么是重构阶段的锅 3) 此阶段的目标:用尽可能简洁的代码使当前所有测试通过! 5. 为什么一定要重构? 1) 好的代码使重构出来的,这里指的是代码的实现,API一般是提前构思好的,偶有部分返工. 2) 识别代码坏味道,熟练运用重构方法/技巧/工具及软件设计思想/原则/模式等驱动出最终产品代码和测试代码 3) 强调:测试代码也需要重构! 4) 每次重构都要运行所有测试,确保绿灯!一旦红灯,回退到绿灯再重构! 5) 此阶段的目标:弥补为了快速看到绿灯所犯的过错! 实践TDD就像玩游戏,进入下一个关卡(红灯/绿灯/重构)前先保存进度(git),挂了就重来!
    展开

    作者回复: good job

    
    6
  • 🐑
    置顶
    2022-03-22
    大家好~我是TDD这门课的编辑辰洋~ 🎐我来友情提示一下下~ 01-04是视频演示,好对TDD有个感性的认识。 05-10是对演示的复盘,同时也会讲解TDD的相关知识点。比如测试的基本结构,TDD中的测试是啥~ 所以,如果你在01-04的操作卡壳了,可以从05开始学,看看5-10,这才是重点哇!看完再回头去看01-04~
    展开
    
    
  • Jxin
    置顶
    2022-03-18
    总结 1.分离关注点,实现的时候只关注一个原子功能点的实现,不关心重构。(不纠结坏味道) 2.重构的时只看红绿过不过,不关心功能实现。(不需要顾虑是否改坏了) 疑问: 1.当前例子可以拆分成一个个原子功能,彼此没依赖。但有些时候功能与功能间是会嵌套的,该把他们拆开还是合并成一个去看?拆分原子功能(测试列表)的粒度是个难点。 2.实际工作中,我们伴随的可能是大量需要mock的接口,又该如何平衡?
    展开

    作者回复: 项目二 更复杂的例子

    
    
  • 邓志国
    2022-03-16
    以前我也是不做设计,依赖重构。以后可以尝试下做一下。另外用注释拆解任务这个不错
    
    4
  • 阿崔cxr
    2022-03-16
    红 / 绿循环这一集里 我看是先写了一个伪实现,然后通过取反的测试来驱动出真正的实现 我自己的做法是按照 TPP 的步骤,一开始也是伪实现,不过因为我知道他是错误的,所以直接在这一个测试的基础上就直接把代码实现成正确的了, 没有做取反的测试。
    展开

    作者回复: 任务划分巧妙的话 可以避免triangel,不然重组测试的时候还麻烦

    共 2 条评论
    1
  • 文经
    2022-03-23
    徐老师,我对Java不了解,通过注解编写测试用例隐藏了太多实现的细节,也多细节没看懂。能不能加个餐,介绍一下Java 通过注解编写的原理。
    
    
  • webmin
    2022-03-21
    自顶向下分解,拆解为小问题后,逐个解决掉,合起来就把大问题给解决掉了,递归不单是一种算法,也是一种解决计算问题的思维方式。 正确路径 主干问题,边界条件 细节问题,就像一颗树的树干、树枝和树叶的关系。 看了老师的演示才知道在工程实践中怎么正确的使用TDD来落地预构、实现、验证这个闭环。
    
    
  • aoe
    2022-03-20
    第一课笔记与源码都在这里 https://www.wyyl1.com/post/19/01/ 附相关学习笔记: 《代码整洁之道》学习笔记 https://www.wyyl1.com/post/18/01/ 《Java 测试驱动开发》学习笔记 https://www.wyyl1.com/post/18/02/ 《测试驱动开发的艺术》学习笔记 https://www.wyyl1.com/post/18/03/
    展开
    
    
  • aoe
    2022-03-20
    两天前看完视频,感觉很容易,当自信满满的开始练习时,完全不像视频中行云流水,而是一步一个砍。最后跟着视频写代码,写到解析多参数时感觉像在 LeetCode 上做算法题。以下是解题思路(最终还是跟着老师的视频敲代码。实现第一个布尔类型的时候用 Stream 求解,结果到第二个求整数的时候发现还是 List 好用,又换了回去) TDD 模板 1. API 构思与组件划分 首先我们需要考虑,**别人将以何种方式使用这段代码**,也就是这段代码的整体对外接口部分。 我们可以通过写测试的方式,来感受 API 的友好程度 2. 在确定了 API 的形式之后,我们需要大致构思如何实现这个功能 3. 功能分解与任务列表 ⭐️⭐️⭐️⭐️⭐️(TDD 核心之一) 在 API 与实现方式有了方向之后,我们就可以根据需求的描述对功能进行分解了。 这里可以先不求全面,有个大致的范围即可 4. 红 / 绿循环 那么先让我们选择最简单的任务,并通过红绿循环实现它 功能分析:解析空格分割的字符串 示例:-l -p 8080 -d /usr/logs -g this is a list -d 1 2 -3 5 功能 - 减号后的字符代表一个功能符号 - l - 功能:日志,没有相关的值 - 类型:布尔 - 描述:存在=true;不存在=false - p - 功能:端口 - 类型:整数 - 描述:有一个整数值 - d - 功能:目录 - 类型:字符串 - 描述有一个字符串 - g - 功能:一个字符串列表 - 类型:字符串 - d - 功能:表示一个整数列表 - 类型:整数组成的字符串 - 如果参数中没有指定某个标志,那么解析器应该指定一个默认值 - 布尔:false - 整数:0 - 列表:[] - 如果给出的参数与模式不匹配,给出友好提示 - 简要错误信息 - 告知错误原因 三种实现方式 1. -l -p 8080 -d /usr/logs 一次解析整个字符串解析(难度大) 2. [-l], [-p, 8080], [-d, /usr/logs] 按功能划分,处理特定数组(简单)💡 课程中选取了最简单的方案实现 3. {-l:[], -p:[8080], -d:[/usr/logs]} 按功能划分,从Map中取出相应的值(比数组复杂) 方式 2 具体实现 单个功能 布尔类型:-l 单整数类型:-p 8080 单个连续字符串类型:-d /usr/logs 组合功能 -l -p 8080 -d /usr/logs 异常情况 布尔类型:输入 -l a; -l 3 单整数类型:输入 -p a; -p 3.14 单个连续字符串类型:输入 -d a b c; -d /usr/logs /usr/logs/a.log 感悟:站在使用者的角度看待自己的代码
    展开

    作者回复: 纸上得来终觉浅,绝知此事要躬行。

    共 2 条评论
    
  • Geek_fa4b49
    2022-03-20
    1. 非常认同TDD前需要做简单的设计,我们不能极端:需要做简单的设计,为了构思系统的大概结构和想要的样子(输入输出)。也不能完全的把系统的所有细节都设计完成才开始写代码。 2. 看到老师的实现,感觉个人的经验的编码能力也非常重要,特别是使用record和option这些比较好的实践,需要平时不断的实践、总结和尝试,否则想都想不到这种实现方法。
    展开
    
    
  • 飞翔
    2022-03-19
    老师 能问问权限认证放在接口层还是应用层呀 为什么?

    作者回复: 看场景 放哪都有可能 放哪都有道理

    
    
  • Leo
    2022-03-19
    感觉第0步(拆解任务) 和 第3步(重构) 挺难的. 对于前端开发UI样式该如何TDD? 还是TDD有它的适用范围? (逻辑处理?)
    展开
    
    
  • Flynn
    2022-03-18
    1.红绿重构之前还有前置的80%的工作要做 2.一个ide可以搞定所有的工作,不太需要额外的工具
    展开
    
    
  • aoe
    2022-03-18
    原来需要一个 TDOD list ,不是想到什么写什么

    作者回复: 对 tdd的核心之一

    
    
  • 飞翔
    2022-03-18
    老师 DDD只能用于业务建模嘛 框架比如Spring zookeeper 能用ddd嘛

    作者回复: 可以 但没必要

    
    
  • Yuchen
    2022-03-17
    跟项目管理里面的任务管理中的任务分解到,无法分解差不多

    作者回复: 也不需要分那么细

    
    
  • 枫中的刀剑
    2022-03-17
    本以为很熟悉args了,看完老师的视频发现还是又学到了不少,比如用注解来拆分,比如在测试里直接用注释列出TODO,自己的习惯都是另起一个文本来列表。 不同试实现策略,在happy path上的处理感觉都是差不多的,但是在sad path 上还是挺大差异的。 选择简单的策略,处理起来感觉要轻松一些。
    展开
    
    
  • 明星
    2022-03-17
    “根据需求的功能描述拆分功能点,功能点要考虑正确路径(Happy Path)和边界条件(Side Path);”
    
    