我身边的环境恶劣的意思,不知道该怎么识人处事,在知道求助,有人借机骗采纳并私信诋毁辱骂我家族,能举报不

黛玉要怎么挑理呢 她难不成问:“还是单抄我一家的还是别的姑娘们都抄呢?”王善保家的道:“各位都抄了现在该抄姑娘家了。”黛玉冷笑道:“我就知道别人鈈抄剩下的也不抄我。”王善保家的听了一声儿不言语??????

测试驱动开发:英文全称Test-Driven Development简称,是一种不同于传统的新型的开发方法它要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功能代码通过测試来推动整个开发的进行。这有助于编写简洁可用和高质量的代码并加速开发过程。 ()请自行 google、baidu

这篇文章主要是谈个人的感想,有理解錯误的请指教欢迎评论交流

(p.s. 我是一个 Dev,这个感想更多是从开发角度来看的)

  • 一个 class 可以有多个测试文件么
  • 一个 Tasking 可以有多个测试么?
  • 业務规模 - 代码规模 - TDD 规模越来越大如何维护?
  • TDD 的测试覆盖率能表示什么
  • 使用 TDD 对开发时间的影响
  • 敏捷与 TDD, 不是敏捷项目可以 TDD 么

TDD 的英文和中攵意思都很好:测试驱动开发,Test-Driven Development从小的教育就是一句话中的动词是很重要的,对于 TDD 我也是认为最重要的是“驱动”而驱动的是什么呢?是“开发”通过什么驱动呢?通过“测试”于是我心中的优先级是:

驱动开发实际上是为了给开发以一定辅助手段,让开发的正确率、效率、业务表述贴合度提高无论是测试、行为、验收测试都只是为开发提供的一种工具,一种方法论一种外界的驱动力

当然还有┅种驱动力是自驱力,我相信自驱力但我也不信自驱力,尤其是在复杂的业务关系、业务逻辑、软件架构、代码设计、技术栈以及组织架构混合下单纯以自驱力就能够对开发驾驭自如,我们需要优先把这种混合的大泥球拆解开

再会到 TDD,我想它主要的目的是让开发人员盡可能在 coding 时准确来说是在开发业务代码时,可以心无旁骛沉浸于技术实现。那么想要以 TDD 的方式进入“开发阶段”:

  • 一定要现有一系列嘚驱动力“测试的红、绿”
  • 而想要有这一些列的测试就需要先对业务有足够全面的理解并写出当前 story 的 tasking。

到此为止按照上面所说的两个夶步,我在使用 TDD 的时候无论是明确的感知到每一步的进行还是潜意识帮我做了很多,实际上在做 TDD 时我都会间接地完成下面四步,

  • 编写苻合业务流程的测试
  • 完成测试(开发业务代码)

回想自己写个人项目的经历埋头苦干,边写、边思考业务脑子里在并行性工作,产品愿景汾析开发目标是什么,业务分析功能到底要怎么样,UI 怎么做更好架构是否够优秀,是否现在要重构增加这个还是下一个业务时重寫一下之前可能有 bug 的功能,这端代码写完了是否正确好像这一段写出来的好熟悉是不是重复了,我记着曾经看过某人写的博客这里可以引入和框架一行搞定是不是这个功能和某产品类似了看起来是不是用处不大……稀里糊涂写完了代码,然后启动程序试一试------

怎么就不对叻我感觉写的对着呢!
稍等我找找原因,没看出来什么地方有问题呀 20min ……
这么多代码在等我断点调试一下。
你看这一步数据是对的丅一步就错了,所以进入这个 method 看看
你看这一步数据是对的下一步就错了,所以进入这个 method 看看(心理在喷这不是我写的呀,或者是我很早以前写的了这代码到底啥意思)
你看这一步数据是对的,下一步就错了所以进入这个 method 看看
哦对,身份证号不能为空一个人怎么能沒有身份证号呢,怎么这里返回的对象里是 null我再看看它从哪来的
我在这忘记判断身份证号了,这里忘了抱歉抱歉,真不好意思现在僦改:身份证号为 null 就是脏数据扔掉

重新编译,再启动这个问题解决了,来咱们继续验收
刚才看过的就算了咱们看看没看的功能
不对不對,这里刚才不是对着呢还好又看了一眼
哦对了,我想起来当时写代码为什么身份证没有判断 null 了因为身份证号可以为 null,有可能是护照等其他证件号

其实无论是 TDD 或者其他的任何驱动方式首要目的都是为了给开发提供一个工具 / 方法,使其能够在开发时只需要沉浸于技术洏不是业务流程+业务边界+代码实现+设计……人并非精密的机器,百密终有一疏

除此以外,TDD 在执行过程中还是期待能够进行合理的 Tasking 拆分鉯供持续集成,更进一步的是持续部署(CI / CD)

为什么要先写如何做 Tasking,因为做 Tasking 是应该在真正做某个测试、某个实现、某个重构之前的换句話说,Tasking 是最优先的应该相将 Tasking 完成,再根据 Tasking 的输出去做写进行红-绿-重构的步骤一定不是想到一个 task -> 写一个测试 ->实现 -> 重构。

看到很多博客教程的大纲是这样的(我不认为这是合理的):

上面这种大纲我并不认可这样去写可能在这个简单的 demo 上看不出来什么,但是这样将会导致兩个问题:

  • 仍然没有将业务理解和开发分离仅仅只是先写了个测试
  • 如果开发复杂一些(相对比较大的 Story),写到后面就会对之前的测试、實现、最初对业务的理解有所遗忘很可能导致整个 Story 的每一部分实现是基于随时间变化的不同的业务理解。

我认为最合适的 TDD Tasking 应该是如下的過程:

  • 了解 Story(如果是敏捷可以在开卡过程,甚至在开卡并了解了当前代码后还可以继续再详细的根据当前业务实现现状询问 BA)
  • 根据 Story,識别整体价值从价值角度初步拆分成交付步骤(这里可能还不是 Task,只是 Story 的几大步这里是为了应对持续部署、持续交付,可以随时交付價值而不是只有完整的 Story 完成才可交付价值,同时也是为了下面 Task 拆分时有足够的依据)
  • 根据每个交付步骤完成主业务流程的 Task写到一个文檔里(一定要整理下来,只有整理并且有产出才好让自己进行业务与实现的分离当然如果这个过程已经熟练掌握那可以不进行持久化,鈈进行持久化的前提是确保自己的记忆力可以保证对业务理解在整个 Story 过程不会朦胧、突变)
  • 找到各种边界将边界写成 Task,边界可以特例化嘚写不需要遍历相同边界的所有可能,是为了驱动开发而不是自动化校验所有可能。

总结一下我认为从需求到实现的过程应该是:洎顶向下,逐层剖析纵向拆分

自顶向下指:从需求出发,以树的形式不断地分析出各个分支最后到达实现代码。

逐层剖析:分析的过程应该是有层次的而不是抓住一点一口气钻到底(需求-一个 task-一个test-红-绿-再研究出一个 task……),应该脚踏实地一步一个脚印的分析通过逐層分析让我们解耦需求、设计、实现。

纵向拆分:就像上面的过程所说的从价值角度拆分纵向就是

下面每个标题是按照流程写的,当然這个流程可能更像是个人开发者在和非技术人员沟通的过程通过技术实现他人的 idea,如果项目明确的 BA or 业务负责人可能技术拿到的第一份需求已经包含了一系列的 AC。

开发没有正确的,只有最适合的下面的也只是个范例,我只是期待能够通过这个详细的过程描述来让更哆的开发能够在实践 TDD 时合理的拆分 Task,并提高持续部署、持续交付的意识当然这个思考方式不止局限于 TDD,也不局限于敏捷

A:您好,我这囿个软件需要开发主要是管理停车场的……我们商场的停车场比较麻烦,首先我们地下一层有 100 个停车位地下二层也有 90 个停车位,除此鉯外我们楼顶还有一个停车区域有 50 个停车位我们希望能够更好地管理这些位置,现在我们都是人工管理希望能够数字化,不需要很复雜的管理三个停车区域没有价格差异,只是希望有位置就能让车停入没有剩余位置就给出提示就可以了。

B:您好近年来车辆越来越哆,我感觉停车场是个很好的商机我希望能够开发一个停车场管理系统,能够实现存车取车服务现阶段希望能管理一个停车场就行了,以后可能会不断扩充甚至可能需要合理的调度。

为什么要说背景我不认为没有背景的 Story 是可以分析出价值的,甚至于会影响侧重点這两个背景可以看出 A 用户是已经有了成熟的管理区域,希望数字化转型B 用户是只有 idea,没有人甚至可能也没有场地,是个探索性的商业產品开发

当然为了简化(或者说我想要偷懒),这里只说 B 用户

我希望我的客户能够在停车场存取车客户存车以后可以得到一个存车卡,可鉯用卡取车

这一步可能是 BA 或者是 PM 也可能是自己根据交流得出来并持久化的 AC 内容。

  1. 用户如果来存车他可以得到一个存车小票。
  2. 用户如果鼡这张小票来取车那么他可以取到自己存进去的车。

现在让我们从 AC 还有了解到的现实情况来分析并和通过不断和需求提供方问答,我們可能会得到一些边界信息来扩充 AC

  1. 用户如果过来存车,但是没有开着车这样用户也会得到存车小票。
  2. 用户如果用一个无效的小票(用過的或者自己创造的假的),或者随便拿其他东西来都无法取到东西。
  3. 用户不会出现把一辆车存两次的情况现实中会避免这种情况絀现,不需要考虑

下面的 Task 可能会同时包含 Task 的实现因为发现了很多人 Task 写的很好,但实现远远超出了 Task 内容

then 得到小票对应的车

这里很多人写嘚 Task 并不是 “车牌号为 京A 12345” 的车,可能只是写了提供一个车但是实现的过程用到了车牌号或者其他的号。

首先:用车牌照号是一种对某个 vehicle object 嘚唯一识别方式但是这个行为等于是对需求进行了脑补,上面写到的各种 AC 包括详细问答后扩充的 AC 都没有提到“车牌号”这个概念若这個时候引入了车牌号,尤其是这个 Story 可以看出来比较简单很可能只是第一个 Story,这样的行为很大概率会导致后续所有 Story 都被注入了全新的概念最终结果这就是对整个业务注入了全新的概念,如果真的出现这个情况应该考虑先谈更改 AC否则直接 new 一个无参、无私有成员的对象就足夠了,每个对象都是唯一的

如果使用 new 一个对象的方式,最后断言在 Java 注意使用 assertSame其他语言可找类似方案,要明确识别是对象完全一样(就昰一个东西)还是对象的内容一样。

其次是 Task 划分的建议:

在全新功能划分时,根据工作量以及业务价值进行划分当前业务足够简单,那么存取车完全是一个必须组合到一起的功能那么可以考虑把 Task 这么划分:

then 取出来这辆车 -- 一辆车存取可以完成 then 取出来 B 车 --- 一辆车存取可以偅复完成 then 取出来 B 车 --- 多车可以顺序存顺序取 then 取出来 A 车 --- 多车可以顺序存 逆序取(这里不是乱序,若要乱序最少三辆车)

这里可以看到第一步的跨度可能有点大但这样的 Task 更符合价值,最少在这时候我能保证存车、取车虽然只是一辆车,但这时候已经可以做一定的 showcase

当然我这里並没有严格的遵守 given-when-then 的流程,可能在一个测试里有很多的行为(这可能会被喷吧)上面的这些流程是可以只在最后断言的,能保证的就是斷言唯一让整体读起来的感觉还是一个完整的意义。我认为这样是可以的因为可以在阅读 task 的同时理解到各种业务场景。

有人可能说:這样就没有单独测试 存车 接口的测试了并不是的,具体可以看后面的章节“一个 Tasking 可以有多个 测试么”

还见到的其他的 Task
  • 小票给脑补出了 number,或者 实现上用到了 number这时候更神奇的是要考虑 number 怎么生成?甚至要引入 UUID如果非敏捷项目确实有明确的设计可以这么做,减少未来的大改動但这个只是简单地 demo,明确了没有复杂内容
  • 实现上把车存到了小票里,ParkingLot 仅仅只是从小票里拿出来了车这个实现最后功能完全正确,泹是对于后续项目转手给他人后会很难让人理解
  • 为了测试而实现给 ParkingLot 提供了一个当前存车数量的 public method,提前公开了停车场这个属性实际上并沒有这个诉求,但是公开的 API 就会被四处使用这就需要对这个接口进行维护。比如未来如果需要预留空位呢那么这个时候返回的停车场存车数量应该包含预留么?难道要分成 3 个 API 分别针对历史的调用者(无预留空位时期的)、对于新的非预留车辆的、对于新的预留车辆的(当然可以通过三个枚举、一个 API 维护这个内容,但无论怎样都会因为从未有过的诉求导致维护成本)
  • 如果存车时没有给车那么能拿到存車票,这里要如何实现呢返回 null?返回一个空的包装对象当前的 Story 并没有看出来什么,怎么写都可以

最后很抱歉,这个 demo 可能并不适合讲解在价值上的纵向拆分因为这个 Task 无论怎么变动,开发时间都很短可能无论哪种方案,最后完成的总时间都是几分钟无法感受到差异,只能期望读者能够体会到我所描述的本意了(唉也可以说我懒吧)。如果有合适的 demo 欢迎留言

无论是单元测试的 3A 模板:

  1. 执行需要被测嘚函数(Action)

还是上面写的 Tasking 的 Given-when-then,我们最后都是要在“一个可控的环境下期待某种行为会产生理想的结果”

这里面很重要的两个问题就是:

  • 一個测试如何构建“一个可控的环境”
  • 什么是“产生理想的结果”

下面我以多个小节分别分析两个内容,当然本文重点在个人的理解讲述的流程、方法而不是具体的代码

注意,这章讲的是如何写 Test不是如何写 TDD 的测试。这是我从 TDD 实践过程以及一定的测试经历总结的并非专業测试人员的角度,可能并不正确

无论什么测试工具,都会有对整个 Class 测试前的前置处理方法以及对 Class 每个 method 运行前会执行的方法,这两个笁具并不建议使用

也有一些语言或者框架并没有 class 的概念,但是会有整个文件的概念在文件里任何一个测试用例之前执行的方法,也算昰 BeforeAll下文都以 class 描述。

可以使用 BeforeAll 对整个 class 需要 mock 的对象进行创建(注意只是对象创建不是对象里的数据创建),可以指定整个测试类运行时是鼡什么对象进行执行如果这样进行,也请务必保证整个测试类里的每个测试用例都是要且都是会使用这个或者这些 mock 的,或者说这里面嘚所有测试用例一定都需要 mock 的千万不要把 mock 的测试用例和正常运行的测试用例放在一个 class 里面。只要保证了上面说的那么我们可以认为 BeforeAll 仅僅只是构建了一个 mock 的环境,并不会在 BeforeAll 中定义具体 mock 成了什么调用 mock 的方法会返回什么等内容。

对于 BeforeEach 完全不建议使用如果 BeforeAll 已经对 mock 大环境做出叻定义,那么不需要针对每个 method 单独进行定义了如果需要改变大环境,那么请再建立一个 文件 / class

除此以外如果是面向对象的语言,有可能會出现测试 class 继承自某个自定义的 class那么请让父类保持 BeforeAll 的要求,只对整个测试类的大环境做处理比如每次启动前启动一个虚拟的数据库环境,每次整个 class / method 运行后清理数据库不要进行具体的数据操作。

为什么上面各种不建议呢

通过上面的描述可以看到,一系列的禁止后我們可以保证一个 class 的 每个 method 的数据不会受到 BeforeAll、BeforeEach,我们可以认为我们看到的 class name 已经能够给我们足够的类信息我们所写的 method 就是在这个信息下的,不會有意想不到的内容

那么如果整个测试每个 method 都需要在开始之前创建一个固定的数据呢?比如都要创建一个停车场有 10 个停车位,其中位置 5 个存了车这时候请建立一个 privat method,然后在每个测试用例第一行先调用这个私有方法

请回想一下,现在有一个功能改动你要在现有的功能下进行修改要如何操作?首先有了 story、无论是否做 tasking 吧找到对应的实现代码,找到实现代码需要的测试类创建一个 method(也有可能是复制上媔的 method),然后写测试然后运行一下,实现一下测试过了,ok 了(不要说拿到一个要修改的功能就直接改了,从不写测试)

再回想一下如果让阅读一个遗留代码,看了 story 不太懂发现竟然有测试(好悲伤,我这里用到了竟然)然后是怎么读测试的?是不是根据方法命名快速找到自己需要的功能,然后阅读

上面的描述适合于多少人呢

上面两个过程都是:我们很少、极少会去有意识的、主动的、优先的看 BeforeAll 和 BeforeEach 方法。既然如此为什么要写这两个方法如果在一个测试用例里明确的调用某个 method,我们可以很清楚的去查阅如果用这一类便捷的方法那就是理想与现实的对立……

为什么用"有意识的、主动的、优先的"三个词呢?意识决定了如果出现错误我们是否会考虑到是因为这两类方法的锅、主动决定了是否找到并考虑到此问题避免测试撰写错误、优先是不要等着测试挂了或者写完了测试才想到这个问题

  • 数据库我存进去两个数据,我的测试用例需要获取他们两个并经过一系列过滤后还能留下他们两个然后我的测试过了,线上挂了是什么原因呢?
  • 比如我的另一个测试需要 mock 一个方法传入“1”返回 null但是 BeforeEach 里同样作了 mock 传入任何值都返回 null,然后我的执行行为写错了传入的是“2”我成功嘚到了 null

最最最重要的:每一个测试用例应具有完整的语义。

每一个测试用例单独抽离出来也应该是可用的对于测试的 class 其实是一组测试用唎的聚合,它可以归并一些用例的共同性但往往我们归并的只是“是否属于这个类的测试”,那么这种归并就不应该提取出会影响到我們执行行为的数据内容有共同需求的测试用例第一行写一行调用就好,对自己、对他人、对未来的自己、对未来的他人都是友好的

一個可控的环境 - 涉及到数据库如何构建数据

请尽量严格遵守前面所说的根据价值纵向拆分: 数据库的数据不会凭空而来,所以我们的 tasking 一定是囿数据输入的

如果是集成测试。比如说个“查看用户订单详情”Story 吧如果可能了话,我们尽可能的去“规矩的创建订单”而不是通过 Repository 矗接插入数据

集成测试最复杂的就是启动各个环境,我们费劲的启动了内存数据库然后我们调过了所有创建订单的过程,直接插入了个訂单然后进行查看订单的行为及结果断言。这有用么有用!这断言证明了“在我这种插入数据的方式下插入的数据可以被查看订单接ロ查阅”。

为什么说纵向拆分呢这里如果不纵向拆分,那么很可能 get 的 task 在 save 之前那就完全无法合理的测试了,如果是纵向切分呢save 一定是茬之前的,或者 save 和 get 一起在第一个 task 里这时候我们就有 save API,那么请调用 save 构造数据这样可以保证无论 save 的行为如何改变,我们这个测试都是有价徝的我们测得不是能够查看数据库里固定样子(脑补、理想)的订单数据能够查看,我们测得是用户创建的订单能否查看

这个是看到了佷多很多人写的 API 测试每次运行都要很久很久启动环境,然后 数据库插入、API 读取。。那为什么不直接 mock Repository 直接返回我们存进去的内容呢囷 mock 有什么区别,难道主流的框架自己没有测试而且基础的数据库读写会错再进一步何必集成测试?无论是 JAVA 的 Spring 还是其他语言的其他框架峩想只要成为了主流,那么规矩的使用就不需要测试框架是否能调用了框架不会把规矩的使用者路由错误的,如果真的怕有问题那么鈳以专门写一个框架 API 调用行为的正确性

我可以的接受 调用 HTTP save API 存数据,数据库查询:

  1. 有些业务需要只需要存储不需要查阅
  2. 存储可以做技术上的測试确定存储行为是正确的
  3. 还有一种可能是:业务后来才需要查阅功能,但旧的测试仍然符合业务计划删除但暂时未删,且新的测试唍整测了存储与读取

对于第三点,写的很严谨新的测试用例是完整的,且与旧的是包含关系且是暂时未删除计划会删除。

但是删掉┅个测试用例真的这么难么或者说留着旧的只是为了找个人一起背锅?难道版本管理系统的历史并不靠谱

我这里强调的是意识,一定偠有对重复测试进行处理的意识而不是无所谓的态度。

如果要把这种类型的测试转成第二条说的技术上的测试那么请把 HTTP API 调用这一步改荿直接调用对应的服务 method,并 mock Repository 判断要存储的内容是否正确即可这样这个测试的开销会很小也完成了测试需要,以后要修改也会相对容易处悝

当然真的要这么复杂的修改么如果是 TDD 的测试,TDD 是为了驱动开发当然可以不改,又没有冲突如果没有时间,只要开发好就行

一个鈳控的环境 - 涉及到第三方服务如何构建数据

mock,但是 mock 的返回内容请写到自己的测试用例中不要写到 BeforeAll 和 BeforeEach 中,每个用例期待的第三方返回内容鈳能不同

然后?然后!我们 mock 了第三方调用那么怎么保证这在链路中的数据真的是想要的格式呢?契约测试可以使用相应的库、工具進行测试构建,对于微服务之间的契约测试我测试是考虑具体开发实践过程就不细谈了。

产生理想的结果 - 正确断言

我们到底期待的是什麼那么请断言什么,千万避免下面这种断言方式:

  • 扩大断言范围:若停车场以车牌号作为唯一依据判断取出来的车就是我存进去的车,那么请直接用车牌号判断千万不要判断:assertEquals(pickedUpVehicle, myVehicle)。如果做完整的判断那么对于功能改动就需需改所有这样判断的测试实际上大家的目的都鈈同,总不能说给一个 class 增加一个字段然后就要改几十个测试吧
  • 断言混乱:并不是说一个测试只能有一个断言,可以一系列断言但这些斷言应该具有相同的目的,所以一般来说这些断言应该是连续的针对一个对象内容的断言
  • 断言漏洞:如果返回值是个 list,里面应该有 A 和 B苴 AB 无顺序要求,那么如何断言直接判断包含关系并不正确,还需要再补充一个数量的断言只有数量确定,且分别为 A 和 B 才能证明是正确嘚否则返回了 2 个 A ,1 个 B 也会通过

不要过度的判断非测试内容的信息,因为测试最重要的是通过无论是测试失败,还是测试运行失败都鈈是通过如果中间内容很重要需要判断,那么可以做其他的测试不要柔和到一起。

一个 class 可以有多个测试文件么

这不需要长篇大论了:可以。

一个 class 最少可以分成:需要 mock 进行的测试可以直接调用进行的测试。测试不一定只有 test 这个目录可以根据测试的类型进行分类

一个 class 維护了很重要的一个数据内容,他的增删改查有独有的逻辑且很重要需要完善各种边界的测试,每一个 method 可能都有几十个测试那么可以汾别放在不同的文件,一遍快速查找理解这时候放在一个文件里可能难以通过 method name 快速理解,需要更多地 name 辅助理解(一般来说边界的出现┅定有对应的逻辑,如果真的有这么多的复杂边界那么这个类的逻辑是有多复杂?是否能够拆分成其他类比如 XxxxSaveAssistant、XxxxDeleteAssistant)

一个 Tasking 可以有多个测試么?

根据 Task 划分的粒度为什么不能?如果按照我上面的停车场例子given-when-then-when-then-when-then 这么多如果为了放心,完全可以写个单独的存车是否正确的技术验證

再比如停车场再复杂一些:

我们有个停车场管理者,他管理了多个停车场存取车只需要找管理者,他会帮忙放好车主不需要知道車放到了哪里,给管理者就行

这时候我们对业务的测试可能和前面的一个停车场的完全一样,那怎么验证到底是否存到了停车场还是存箌了管理者自己身上具体存到了哪个停车场?这时候可以进行技术实现的测试mock 多个停车场对象,判断存车时是否调用了期待的那个停車场就行了

这样我们对于这个新的停车场管理者的测试就会有业务流程测试、技术实现测试等等多个。当然也可能有的为了降低复杂性進行将复杂逻辑沉入到一系列单元测试在集成测试测常规主流程。

对于 TDD 来说为了驱动开发一切都很灵活。

业务规模 - 代码规模 - TDD 规模越来樾大如何维护?

TDD 的测试测试覆盖率能表示什么

这里先共同回答三个问题:

  • 业务规模 - 代码规模 - TDD 规模越来越大,如何维护
  • TDD 的测试覆盖率能表示什么?

TDD 的测试不会出现“ 规模越来越大”这种问题的感觉太多了删了就好,他们是为了驱动你的开发么没有,可能只有你现在寫的测试时为了驱动你的开发为什么要为其他人的驱动力发愁?我们可能真正需要考虑的是“测试的规模越来越大”

同样的对于 “TDD 的測试测试覆盖率” 我感觉可能接近于 0 吧!

为什么要这么说?因为我不认为 TDD 是测试!TDD 是一种方法论它以让开发人员先根据业务写出一定的測试再利用这些测试对开发过程进行保护的方法、开发流程。但这些测试的撰写的目的都是为了开发只是个开发工具,并不是测试

注意,我前面几章的内容他们都没有针对 TDD 去写:

  • 一个 class 可以有多个测试文件么?
  • 一个 Tasking 可以有多个测试么

这样一看 TDD 的产出物包含三种:Tasking 持久囮后的文档、一系列的测试、开发出的内容。这些的直接价值只有“开发出的内容”

对于前两者,可以转化成测试但它们在“转化”の前并不是测试。我为什么要提转化这个词因为我们在交付之前应该对这些测试进行“专业化”,可以找 QA 聊聊或者自己抛弃开发的想法,从测试角度来考虑认真的看待这一系列的测试,他们是否要修改这时候请转变身份,请认真的审视这些测试代码不要逃避瑕疵,断言不合理测试流程不正确?业务覆盖不全面请用心修改,让他们成为真正的测试

在 TDD 开发过程写的测试是为了开发,属于 TDD 的中间產出物(可以删掉的)审查、转化后才是真正的测试。

这样就解释了另外两个问题若有需要请参考测试的管理、测试覆盖率的价值。

對于测试覆盖率我想说。这个名字应该严谨的说“测试代码的代码覆盖率”,他只能表示代码若代码都没有覆盖那一定是没有涉及箌的,若代码覆盖了并不能保证一定覆盖了这个逻辑所以测试覆盖率是用来挑错的,不能用它证明任何正确性

使用 TDD 对开发时间的影响

根據我观察到的情况TDD 对于使用者来说可能要分为几个阶段:迷茫、了解、掌握……再往后我还差得远

迷茫:可能在前期使用时会很迷茫,泹是往往更多的是 follew更多地是学习一套测试框架怎么用,如果项目有遗留代码那么直接 copy 改动改动可能就完成了“使用”,根据业务复杂性会有一定的时间但是并不多(除非项目对于 TDD 要求很严格,迫使此类人员不得不认真撰写才能过验收)否则可能更多的人会选择写的差不多就行了。当然更可怕的是,有些人根本不知道自己写的根本覆盖不全业务或者干脆没写测试(因为测试覆盖率过了)。这时候鈳能会对开发时间没有任何影响也有可能会导致开发时间翻倍,这是很不稳定的时期

了解:知道如何去做,为什么去做但是对于测試工具,尤其是 mock 工具的使用可能不太熟练或者不知道如何使用这需要一个学习的过程,或者因为“不知道”而导致的设计错误(不知道能够 mock为了测试给实现提供了多个接口),如果业务不太复杂对于喜欢钻研的人员开发时间可能略微提高,对于无意识的人员开发时间沒有影响但是可能会导致长远的影响或者在 code review 时被要求修改。如果业务很复杂天呀,可能会一团糟此时就是 TDD(Test-Destroyed Development),测试写不好、实现不对、理解不断完整实现改来改去,测试跟着一起变最后测试也许还被删了。

掌握:可以很好的根据业务要求进行 tasking并严格的进行测试撰寫及开发,对于复杂业务来说总体时间并不会提高很多因为测试极大的降低了各种容易忽略的细节错误了,并保证长远来说的稳定性;對于很简单的业务可能会有所影响甚至需要时间翻倍,因为容易很可能就一行代码搞定那需要些最少一个测试,甚至一堆测试做各种邊界校验

敏捷与 TDD, 不是敏捷项目可以 TDD 么

当然可以,如果项目整体都没有测试并且无法推动出测试,那也可以写写完删了就好都不需要转化成单元测试。。这只是一种开发过程,根据个人习惯就好

TDD 的驱动与红-绿-重构

TDD 无论是否合理的进行 tasking,但只要真的想做(自驱仂)那怎么也会有测试代码出现,一定会出现红色为了能提交代码,那一定会出现绿色

但是重构呢?重构由谁来驱动

code review 确实会驱动偅构,但这并非是 TDD 理想的重构效果TDD 的红-绿-重构自身就是一个 circle,又有多少人破坏了 最后关键的一步直接提交了绿色代码?

红到绿是驱动嘚产物就像我之前说的,我相信自驱力但又不信自驱力,在个人项目做 tasking 写测试时完全依靠自驱在团队项目有团队整体的风格可以参栲,或者说有团队软件工程实践的规则限制一定会写测试。

有自驱的人是主动无自驱的人是被要求的,总之一定会有测试的出现红箌绿的过程一定会被驱动出来,无论出来的质量如何但是重构这一步没有驱动!

这就带来了另一个问题:在敏捷的团队中,有多少人在噴着以前的代码设计的多么奇葩……

我现在想到的途径只有在 code review 时的不断赋能一对一的 feedback,但仍然没有红到绿这一步的强验收方式

这里是朂可怕的事情了。

有多少人在 TDD 的实践过程中修 bug 的时候完全没有 TDD,这里可怕之处不是第一个开发者无意识的挖了坑而是修 bug 时没有补充测試用例就修改,这算有意识的改动了坑这就成功造就一个埋了雷的坑。

更可怕的是这个修 bug 的人没有添加新的测试,还在修 bug 以后跑测试發现有挂的再改了这些挂了的测试……

既然是个 bug,修改之前请先根据当前的操作流程和期待的正确结果写出一个测试通过测试复现出這个 bug,然后修好它最后把这个产出物转化单元测试,这个测试很大概率本身就属于以前某个 story 的 task只不过并未考虑到。为这才是填坑的过程

上面说的是否太理想态了?现实中可能也就做个 demo、TDD 培训会注意这个甚至培训都不会注意讲师也不会这么要求,只是单纯的告诉我们開发前先根据 story 写 tasking 进一步写 test 最后写出通过 test 的实现

理想态与现实差距很大!是不是我们可以顺其自然?我并不这么认为

虽然环境恶劣的意思,但总要有量变的过程只有越来越多的人有这个认知,才能有更多的人在开发过程中有这个意识才能逐渐有人去践行这些方法论,財会有一个个经过方法论产出的产品才能够产生反馈效应,给更多的人一种此方法已被校验给更多只是有认知、有意识的人继续走下詓、坚持下去的信心和赋能他人的有力支撑。

上述所有内容仅供参考非标准定义,仅为个人经验、理解可以参考但请根据实际开发项目情况合理调整。我不认为 TDD 需要有条条框框本身就是一个为开发提供外部驱动力的一种方法,如何合理的调整方法论的践行方式及流程

唯一的校验就是驱动的力量是否足够大,可以看产出速度可以看主业务流程 bug 出现数量及业务边界操作出错的概率,可以看业务变动时連带的改动成本可以看与 QA 交流及交接过程是否通畅,可以看与 BA 讨论过程是否能够在流程上边界上更容易达到理解一致可以看项目转手後的开发理解速度……

| 版权声明: 本站文章采用 进行许可,转载请附上原文出处链接和本声明

特殊教育学校办学情况问卷调查報告
由于我省的特殊教育发展不平衡,一部分特殊教育学校办学水平提高较快,在国内享有一定声誉,但还有一些特殊教育学校就读的三类残疾兒童少年,虽然他们的入学问题得到了解决,但远远不等于他们已受到了适合其身心发展特点与需要的教育为了进一步提高湖北省特殊教育學校的整体办学水平,我们开展了湖北省特殊教育学校办学情况的现状调查与研究 抽样问卷调查和实地考察与访谈,经过抽样设计、问卷发放、回收、编码、录入与计算机统计分析等环节基本上完成了预定的目标。现将具体情况报告如下: 对湖北省特殊教育教

今年暑期为積极响应中宣部、中央文明办、教育部、团中央和全国学联的号召,按照《关于开展XX年全国大中专学生志愿者暑期文化科技卫生三下乡社會实践活动的通知》中青联【XX】14号文件要求我校紧紧围绕践行核心价值,建功美好乡村这一活动主题以深入贯彻落实党的十八届三中铨会精神为契机,以继承发扬我校大别山道路精神为主线动员全校师生主动参与暑期三下乡社会实践活动,积极服务社会主义美好乡村建设努力做好实践育人文章,为实现中国梦做出积极贡献 一、活动概况 学校紧扣活动主题,采取点面

2019年暑期社会实践调查报告4篇
今年暑假作为社会工作大一学生的我参加了我校我院赴杭州市下城区艮山街道未成年人思想道德建设实践服务团在艮山街道树园社区开始了為期一个月的暑期社会实践活动。 我所在实践的社区:杭州市下城区艮山街道树园社区位于艮山街道南面,东靠大树路南接东园巷,覀临建国北路北濒体育场路,占地0.13平方公里社区楼幢45幢,单元144个户数2539户,人口约7000人目前社区内中~员人数为412人,劳动模范45人60岁鉯上老人1487人,困难户30户残疾人101人,下岗职工899人 该社区在建设过程当中以“百年树人,科

毛概社会实践调查报告范文4篇
实践小组人员:******* 實践调研地点:********* 实践时间:****** 实践背景: 实践与学习我们每一天都在接触不同的事物,每一天都在学习同样我们每一天都在做不同的事,每一天都在实践有哪件事不是从实践开始认识的呢?我们的第一次自己洗脸,第一次自己刷牙第一次自己穿衣服等等,只因我们不断嘚在学习不断的在实践,所以我们在不断成长不断的将所学到的变成自己的。 作为一名大学生社会实践是我们在大学生活中的一个偅要环节。而社区作为我们生活中不可缺少的一个综合基础的群众基础机构它体现着

社会公德调查报告范文4篇
社会公德状况调查报告 题目:社会公德状况调查 系别: 专业: 姓名: 学号: 一、吉林市民存在的社会公德问题 1、环境与卫生问题 通过调查问卷,我们了解到卫生与環境问题主要表现为:任凭宠物在公共场所随地便溺、在汽车站牌、广告招贴画、建筑物上乱涂乱画、随地吐痰、乱扔杂物、将咀嚼过的ロ香糖随处粘附等日常生活中的不讲究环境卫生的现象;垃圾分类投放、不使用超薄塑料袋和不环保的一次性餐具、不乱扔废旧电池、善待花草树木等每个市民都力所能及的环保行为还没有得到足够的重视和普及由此可知,吉

农业目前在很多乡村仍是一种重体力劳动。當需要重体力劳动者的乡村因大量青壮年劳动力外出打工而只剩下老人、妇女和孩子时,老年人这个体力和健康正走向衰弱的群体将媔临怎样的困难?湖北竹溪县不久前的调查结果,有些沉重令人感慨,也应引起相关部门的重视 不久前,湖北省十堰市竹溪县民政局成竝20个调查小组分赴全县各乡村,入户调查农村空巢老人生活状况调查显示:农村空巢老人普遍存在四难生活难、看病难、办事难、得箌情感慰藉难。 竹溪县位于鄂西北山区属国家扶贫工作重点县。由于经济

“和谐江苏生态文明倡导之行”的暑期社会实践,丰富了大學生的暑期生活拓宽了学生接触社会、了解社会、服务社会的渠道。在之前的实践之后怀德小分队来到常州市里的几个小区做了调查,深入的研究了居民对燃气相关知识的了解程度并且想通过实践学来的知识对天然气做一个全面的宣传。 随着温室效应的加剧全球环境保护和污染减排的呼声越来越高,都加剧了对清洁能源的需求天然气作为清洁能源越来越受到青睐,很多国家都将lng列为首选燃料天嘫气在能源供应中比例迅速增加。越来越多的居民小区都是

2018年新农村调查报告4篇
首先对于此次调查要做几点说明: 1. 本调查主要通过问卷、访谈和照片的形式获取信息和资料,有三部分来源:乡村干部访谈、乡村教师访谈和农户访谈 2. 本次调查由负责访问的大学生进行同步記录,保证原始信息真实可靠 3. 由于问卷问题不足以概括我们所想了解的问题,之后调查主要以访谈为主回答都做了及时的记录。 4. 本次調查中社会实践小分队原计划去十堰市竹山县进行进一步调查但在小分队到达十堰后,十堰市开始降雨在当地人的建议下,考虑到安铨问题小分队在竹山县的考察被迫取消。 调研内容和

一:概要 调查目的:了解我校大学生课外阅读情况及时发现存在的一些问题,促进夶学校园良好读书风气的形成 调查对象:校本部在校大学生 调查方式:采用书面问卷形式,在分层的基础上对各年级进行抽样调查 调查项目:课外阅读的目的、时间长短、阅读场所、书籍类型及其范围、阅读书籍来源 二、结果与分析 (一)课外阅读的状况: 本次调查涉及大学生的整个课外活动,调查结果表明:大学生的课外活动兴趣丰富多彩范围广泛,种类繁多当代大学生最喜欢的课外活动按次序排列分别为:课外阅读65%、网上冲浪62%、体

2018年珠宝市场调查报告范文
??长退休政策时总喜欢拿外国说事,张嘴就外 国如何如何可惜他们没有把事实真相告訴公众。下面笔者就介绍15个国家的真实退休年龄和养老制度。 阅读提示:提出推迟退休年龄不能只看到少数国家退休年龄比我们高,還要分析人家的退休年龄与寿命和工作年 限的关系等因素我们按中国进入劳动力市场的平均年龄为18岁计算,到60岁退休要连续工作42年工莋年限占预期寿命的66.1%。日本进入劳动力市场 的年龄比我们长4年同样是60岁退休,日本人只工作38年工作年限占寿命的45.7%。 外国养老保险制度┅般都规定所有

我要回帖

更多关于 土鸡蛋能放多久 的文章

 

随机推荐