最近,一个人问一个基本的问题,关于如何在Python中计算列表中元素的所有排列。对于大多数学生提出的问题,我没有在答案中提供实际的源代码,而是解释了如何解决该问题,该问题最终以测试驱动开发的基本介绍结尾。

关于问题本身,我想起了自己在大学学习编程时必须解决的所有类似问题。我们从未被教导过测试驱动开发或任何类似的方法,但始终有人要求他们编写算法,以从列表中对元素进行排序,或者解决塔塔河内难题,等等。SoftwareEngineering.SE上的所有学生似乎也不知道TDD(测试驱动开发)如何帮助他们解决所遇到的问题:如果是的话,他们会以不同的方式提出问题。

事实是,没有TDD,所有这些问题确实非常具有挑战性。我认为自己是一名专业的开发人员,但是如果被问到,我仍然会花一些时间编写没有TDD的列表排序算法,并且如果我被要求计算列表中元素的所有排列,而仍然没有,我将一无所知。使用TDD。另一方面,使用TDD时,我在写答案给学生时仅用了几分钟就解决了排列问题。

TDD根本不被教或至少很晚才被教的原因是什么?在大学里?换句话说,在要求学生编写列表排序算法和类似内容之前解释TDD方法是否有问题?


以下两个问题的评论:


在您的问题中,您似乎将TDD表示为“问题解决装置”。过去,TDD被表示为“解决方案发现机制”,但即使鲍勃·马丁(TDD的主要倡导者)也承认:您必须为该技术带来大量先验知识。


特别是:


我很好奇为什么您认为TDD使规范明确的棘手算法问题变得更加容易。


我认为有必要多解释一些什么,在解决问题时,TDD如此神奇。

在高中和大学里,我没有解决问题的任何特定技术,这既适用于编程又适用于数学。回顾过去,我认为这样的技术之一是复习当前/最后的课程/讲座并寻求与练习的联系。如果课程是关于积分的,则老师要求解决的问题很可能需要使用积分。如果讲座是关于递归的,则有可能使用递归解决给学生的难题。我也肯定有解决数学问题的形式化方法,这些方法也可以应用于编程。但是,我从没学过任何东西。

这意味着在实践中,我的方法仅仅是解决问题,试图猜测应如何解决。那时,如果我面临着从列表中生成元素排列的挑战,那么我就不会以空列表作为输入,而是以[4, 9, 2]这样的示例为例,试图弄清楚为什么会有六个可能的排列,以及如何通过代码生成它们。从那里开始,我需要进行很多思考,以找到解决问题的可能方法。从本质上讲,这就是原始问题中作者所做的,最终使用random。同样,当我还是一名学生时,我这个年龄段的其他学生都不会以[]开头:所有人都会立即着手处理包含两个或三个元素的情况,然后停留半个小时,有时结果是代码不正确

对我来说,TDD方法似乎是违反直觉的。我的意思是,它工作得很好,但是在阅读一些有关TDD的文章之前,我永远不会弄清楚自己(1)我应该以最简单的情况开始,(2)在编写代码之前编写测试,以及(3 ),请不要着急,尝试在代码中实现多个场景。看看初学者程序员的想法,我有一个印象,我并不是唯一发现它违反直觉的人。我认为,对于对功能语言有很好理解的程序员来说,它可能更直观。我猜想,例如在Haskell中,自然会通过首先考虑一个空列表的情况,然后考虑一个包含一个元素的列表的情况,然后考虑一个包含多个元素的列表的情况来处理置换问题。在可以使用递归算法但不像Haskell那样自然的语言中,这种方法自然就不那么自然了,除非当然要实践TDD。

评论

我相信,这个问题在两个网站上都是热门话题,并且鉴于不同的受众可能会在两个网站上产生有趣的答案。已经有一些相关的问题:cseducators.stackexchange.com/q/961/945,cseducators.stackexchange.com/q/908/945,cseducators.stackexchange.com/q/872/945。

我可能完全误解了TDD的含义,或者您的示例存在问题,因为它们是...好吧,我想unit一词就是这个词。您要么了解问题,然后就可以编写有效的代码,否则您不会。确实没有可以测试的中间步骤或子模块。

您对这个问题是否很有信心,您的意思是“ TDD”而不是“列出预期的输入和输出列表”?

如果我必须列出“不是CS学生但应该教的重要概念”的列表,版本控制将排在第一位,而TDD将会非常遥远。

有问题的假设是,TDD很好,没有负面影响。它也不是唯一的解决方案发现机制。还有许多其他机制(我更喜欢自顶向下编程),因为我认为单元测试在许多程序中会适得其反,尤其是在前端应用程序中。

#1 楼

我是当地社区大学的兼职编程老师。

这所学院开设的第一门课程是Java编程和算法。这是一门课程,从基本的循环和条件开始,以继承,多态性和集合简介结束。在一个学期中,对于以前从未编写过任何代码的学生而言,这项活动对他们中的大多数人来说都是完全异乎寻常的。董事会发现学院的CS课程存在许多问题:


教授的编程语言太多。
没有关于软件开发生命周期的课程。
没有数据库课程。
很难获得学分以转移到州立大学和地方大学,部分原因是这些学校无法就“计算机科学”,“信息技术”和“软件工程”这两个术语达成统一的定义。 br />
我对他们的建议?在课程中添加一个为期两个学期的顶点课程,学生可以编写一个全栈应用程序,该课程涵盖从收集需求到部署的整个软件开发生命周期。这样一来,他们就可以在本地雇主那里(在学徒级别)聘用。

那么,TDD在所有这些方面都适合什么?我真的不知道。

在您的问题中,您似乎将TDD表示为“问题解决装置”;我主要将TDD视为改善代码设计和可测试性的一种方式。过去,TDD曾被视为一种“解决方案发现机制”,但即使鲍勃·马丁(TDD的主要倡导者)也承认,您必须为该技术带来大量先验知识。

换句话说,您仍然必须首先知道如何解决代码中的问题。 TDD只是在与软件设计细节相关的正确总体方向上推动您。这使它成为一门高层次的课程,而不是一门低层次的课程。

评论


考虑到学生需要作为CS和SE学位的一部分学习的所有其他学科,要适应它非常困难。TDD的深度足以保证至少2-3个学分的工作价值。尤其是当您尝试涵盖模拟,存根,理论,参数化测试,甚至更基本地讲应该测试和不应该测试的内容时。

–贝琳·洛里奇(Berin Loritsch)
19年12月31日在19:46

同意TDD是高级课程。但是,TDD不仅会“在正确的总体方向上推动您”。首先编写测试就像在安装砖墙之前先设置线条和尺子。通过将事后重复的对准检查转换为连续的对准夹具,可以帮助您在更短的时间内完成更好的工作。这比对每个砖块进行布局后检查对齐方式要好,这又比对越来越大的砖块进行布局后检查对齐关系要好。我不记得我的CS学位坚持要我自动化我的测试,而只是坚持要我进行测试。

– Laurent LA RIZZA
20年1月2日,13:47

魔鬼的拥护者:我见过TDD的许多用法实际上破坏了体系结构,仅出于可测试性的目的而创建了大量不必要的抽象层。测试本身实际上是为了进行测试而复制的测试代码。可测试性很好,但是通常某些代码根本无法有效测试,通常是在大量使用某些外部框架(例如UI代码)并对其进行测试时,您必须模拟整个框架。这样,其他形式的测试(例如e2e测试)比单元测试要好。

–苏丹
20年1月2日,22:51

首先编写测试更像是先将人们搬进来,然后在他们周围盖房子...

–备忘录
20年1月3日,17:19

@memo:更像是编写智能蓝图,该蓝图可以在施工过程中自动检查房屋的正确性。

–罗伯特·哈维(Robert Harvey)
20年1月3日,21:17

#2 楼

首先,我们必须从根本上区分计算机科学和软件工程。 (也许在较小的程度上介于软件工程和编程或“编码”之间。)

正如我的一位CS教授所说的:如果您需要键盘,那么您就不需要CS。

TDD非常是一种软件工程实践。它实际上与计算机科学关系不大。因此,如果您要问为什么CS学生不学习TDD,那是因为TDD与CS并没有多大关系。

现在,软件工程,这完全是一堆鱼。我非常同意应该在那儿教TDD。我参加了一门软件工程课程(一个学期每周90分钟),在这一课中,我们学习了瀑布,V模型,RUP,CMM,CASE,RAD,螺旋,迭代以及其他一些我忘记的东西。当然,在TDD中肯定会有空间,特别是如果将其与其余课程集成在一起,并将TDD应用于需要编程的所有课程中的所有家庭作业和课堂作业中。

但是,就我而言,尚未编写《敏捷宣言》,而TDD是一种晦涩的利基技术。 ,您会发现他们很早就教过功能应该随用法示例一起使用,而只是稍后,本书介绍了自动化的单元测试,并建议应以测试形式编写这些用法示例。他们还教导用法示例及其所谓的“目的陈述”(您可以将其视为JavaDoc注释的摘要行)应该写在代码之前。

他们没有明确教导TDD(他们有自己的方法),但这至少有点接近。 HtDP是为高中生设计的,不到一年的教学时间,所以我认为在大学的一个学期中教授它是不可行的。

但是,老实说,这已经是一个巨大的胜利,因为简单地教导学生可以实际运行使用不同输入编写的代码。 (换句话说,这是一种粗略的手动测试形式。)我为学生经常无法采取这种思维步骤感到惊讶。

例如,我在Stack Overflow上看到了多个问题,这些问题本质上是等于“我需要实现哪种方法才能使此代码正常工作”。请注意,这与方法的代码无关(询问者知道如何实现该方法),而仅与名称有关。但是,没有一个提问者想到了简单地运行代码并查看NoMethodError异常中将始终出现的异常方法的名称的想法。

评论


我同意首先,我们必须从根本上区分计算机科学和软件工程。但是(至少在美国),许多学校仍然无法区分两者(或其他计算机科学学科),并且计算机科学专业的毕业生通常最终在行业中工作,而对行业的了解或经验很少。需要有效地在复杂软件系统上进行团队合作。

–托马斯·欧文斯♦
19/12/31在23:53

@ tgm1024-Monicawasmisulated CS课程通常包括有关可计算性理论的课程。尽管它可能对软件工程很有用,但它绝对不同于SE。只需看看CS(theory).SE vsse.SE。

–丹尼尔·M。
20年1月1日在22:53

抱歉,@ tgm,但丹尼尔是正确的。不管您声称没有多少次,这两件事之间绝对是有区别的。

–轨道轻赛
20年1月2日,下午2:16

我认为有害的是不认识并解释CS和SE之间的区别,并假装不存在。对那些被告知获得CS学位将使他们成为软件工程师的学生的伤害最大。它最肯定不会。

–埃里克·金(Eric King)
20年1月2日,15:16



@ tgm1024--Monicawasmisulated说CS和SE在根本上是相同的,就像对物理和机械工程来说。一种涉及理论和科学,另一种涉及实践和应用。学习一种对另一种有帮助,但是它们绝不是完全相同的学科。

– Abion47
20年1月2日,21:19

#3 楼

TDD在“现实世界”编程中是一个很好的过程,因为问题通常会在我们未指定的桌子上出现。 “添加可以执行X的功能”,“如果执行Y可以解决错误的地方”等。TDD迫使我们在开始编程之前先创建一个规范。

在CS /编程类,这些问题通常在我们面前特别明确。 “编写一个函数,该函数接受一个整数数组,并返回一个以非降序排列的具有相同整数的数组”。规格已提交给我们。

我很好奇为什么您认为TDD使具有明确定义的规格的棘手算法问题变得更加容易。具体来说,我想请您解释一下:

如果我被要求计算列表中元素的所有排列,而仍然不使用TDD,我将一无所知。另一方面,使用TDD时,我在写给学生答案时仅用了几分钟就解决了排列问题。


我怀疑您会说是因为您编写了测试用例,断言了P([]) -> [[]]P([1]) -> [[1]]P([1, 2]) -> [[1, 2], [2, 1]]等,这使您看到了递归应该如何工作。但这不是TDD,这只是...考虑问题。您可以考虑问题而无需编写会失败的实际单元测试的过程。

评论


您在上一段中描述的是TDD。它与“仅考虑问题”相同,这是TDD的全部要点-它迫使您在实际写出问题之前仔细考虑问题。它还使您能够仅通过编写实际需要的代码来使用YAGNI,而不必编写其他代码来使它们不必要地花哨或“可扩展”。另外,非TDD方法将是编写打印或等式语句以验证输出,因此TDD方法(以仅略微增加的冗长程度为交换)会自动以组织方式包括这些检查。

– Abion47
20年1月2日,21:25

TDD只是在编写代码之前编写单元测试的特定过程。 TDD在思考方面没有垄断。

– MattPutnam
20年1月3日,14:33

@MattPutnam,恰恰是我的一个“但是”。正如我所见,TDD被吹捧为IRL是一种荒谬的过大杀伤力。例如,当Java增量测试工具大致局限于在各处散布的公共静态void main()时,我主张使用许多这样的方法。但是现在,它变成了一个信念系统,即每件事都要首先进行单元测试,这简直是在忘记他们现在可能已经超出了以后修复错误的代价。天哪,每个人都应该看到某些人经历的程度。

–tgm1024--莫妮卡遭到虐待
20年1月3日,14:39



@MattPutnam这就是TDD背后的“内容”,而忽略了“为什么”。 TDD不仅仅是为了编写测试而编写测试。这种心态是在代码之前编写测试可以使该代码更安全,更安全,但最重要的是,它可以使代码更加专心。编写单元测试的行为迫使开发人员编写有目的的代码,而不是仅仅抛出代码来查看最终的结果,因此,它大大减少了迭代开发的需求。最终获得具有完整测试覆盖范围的代码并不是最终目标,而仅仅是锦上添花。

– Abion47
20年1月3日,18:35

在大多数情况下,该应用程序就是测试。人为的测试与应用程序具有完全相同的作用。否则建议是荒谬的。如果我有一个使用8个参数来计算价格的价格计算器,并且应用程序生成了正确的价格,则测试通过。您将不会生成涵盖应用程序范围之外的场景的测试,否则您根本就不会开发应用程序规范。您只是为了编码而进行编码。第一个火星漫游者坠毁并燃烧,因为有人使用英制单位而不是公制单位。 TDD不是万能药。

– Newclique
20年1月9日,17:27

#4 楼

我怀疑这主要是因为编写自动化测试比编写被测试的代码更困难。当您仍在努力应对基本机制时,很难添加另一层。另外,正如其他答案所指出的那样,TDD被视为一种软件工程过程,即使它的从业者更多地将其视为教学手段。另外,知道首先要编写哪些测试本身就是一项技能。

如果我要学习入门课程,我会按TDD顺序提供一些测试,并指导学生让他们通过时间顺序。将编程与经验丰富的导师配对非常相似。就个人而言,我认为这将使算法之类的课程更易于教授,由于逐步进行,这将抵消在该技术上花费的时间。这将使学生思考以下问题:“我有一些行之有效的代码,可以找到包含两个元素的列表的所有排列。我如何重用尽可能多的代码以使其适用于3个以上的元素?”

评论


作为“教学设备”,单元测试的进入门槛很高。很难做到这一点,而且它假定了很多先验知识。我喜欢您为学生提供预先编写的单元测试的想法。

–罗伯特·哈维(Robert Harvey)
19/12/31在23:04



但是学生需要知道仅仅测试每个特定要求是不够的。用户将要执行规范编写者未曾想到的事情。曾经有人声称我的错误报告一定是一个错误,因为在这个已经很长的项目中没有人报告过它。我的反驳是:“那么我猜没有人对这种类型的车辆做出过正确的选择。”我是通过随机偏离测试脚本而发现故障的众多案例之一。我还清理了一名编码员,他通过编写代码来实现X的要求,以确保它不会做其他任何事情!

– WGroleau
20年1月1日,17:50

@WGroleau然后介绍EnterpriseDeveloperFromHell的教学设备,该设备提供通过所有测试但尽可能无用的程序。

– Caleth
20年1月2日,12:14



编写自动化测试比编写被测试的代码难吗? IMO并不难,这是另一种互补的技能。编写自动化测试会迫使您对实际想要的结果做出决定,对我而言,这是最难的部分。

– Laurent LA RIZZA
20年1月2日,12:27

“自动化测试”是模棱两可的。运行测试可以自动化,或者创建测试可以自动化。我不止一次地审查了被宣传为自动创建测试驱动程序的工具。他们每个人都分析了源代码并创建了仅在存在编译器错误的情况下才会失败的测试用例。

– WGroleau
20年1月2日,16:45

#5 楼

基本问题是,在TDD流程中发明测试与计算机科学或软件工程无关。它需要应用程序领域的知识。

当然,这是TDD在实际应用程序中的优势:您无法逃避思考所要构建的系统将实际用于什么系统。但是在典型的CS和SE活动中,给学生的任务具有最小的上下文,并且仅存在于测试或说明一些学习目标的情况。

例如,如果学习目标是为了证明对学习目标的理解, TDD与编程语言无关,它是无关紧要的:您可以编写通过所有TDD测试的软件,而无需使用“ case”。如果该示例是人为的,则实际上,不使用“案例”可能是解决实际问题的更好解决方案,但是就预期的学习目标而言却不是。

鼓励学生发明自己的测试用例并运行它们,但是要尝试使用正式的TDD流程是没有意义的。

第二个问题可能与CE和SE的教学方式有关,但这仍然是一种实用的方法:使用TDD时如何对学生的测验成绩进行评分?没有明显的方法可以自动化该过程。

即使您生成的模型解决方案说“您应该已经针对以下15种或20种情况进行了测试”,您仍然必须手动识别每个部分的学生测试(全部或部分)您的模型答案。而且,除了琐碎的情况外,学生可能会制作出一套很好的测试,这些测试在逻辑上以与模型答案不同的方式进行结构化。

评论


也许我误会了您的第二点。在我看来,评估一组测试的严谨性非常容易实现自动化-通过针对每个带有特定已知错误的罐装实现对它们进行运行,并确定是否存在测试失败(如预期的那样) 。就像可能会对学生的实施方案进行一套固定测试以评估该实施方案的准确性一样。

– starchild
20年1月2日在8:56

@starchild出于同样的原因,实际上很难做到这一点。您仍然只测试一些极端情况。那么,如果学生发现了7个有效的极端案例而您却发现了10个但只有5个您与学生之间的极端案例匹配,该怎么办。因此,您的自动评分现在给学生5/10,而应该给7/10。还是应该降低7/12和所有其他分数?

– joojaa
20年1月2日,10:13



基本问题是,在TDD流程中发明测试与计算机科学或软件工程无关。它需要应用程序领域的知识。我相信您会混淆功能需求和设计需求。 TDD与特定设计的实现有关。当TDD支持者(我不是一个)提到功能时,他们是在实现阶段而不是应用程序级别的功能。 “这种排序例程是否起作用?---首先对其进行测试,使其失败,然后再实现。”,(等等)

–tgm1024--莫妮卡遭到虐待
20年1月3日在16:59



#6 楼

普通的学生对他们应该知道的知识和做的事情的了解确实很差。要教TDD,他们需要了解:


如何解决技术问题。一开始,他们认为代码是一次性编写的。只有在他们意识到基本的调试策略之后,才转向更多的增量编写。即使您事先告诉他们,他们仍然会这样做,因为他们认为事情就是这样做的(这也是为什么人们不知道如何绘画,弹钢琴,做数学等的原因)。 )
如何反省自己的行为,以便可以在自己的行为中找到可重复的模式。一旦可以执行此操作,就可以自动化您自己的工作。但这对大多数人来说是完全陌生的,直到他们达到一定水平。
如何编写需求。
了解问题空间的极端情况。
了解风险管理的工程原理。 (哈,但您甚至都不知道自己是工程师)。
了解代码的重构和维护。
了解编程在实际公司中的工作方式。

实际上我有太早被介绍给TDD的同事,他们并没有真正从中受益。但是,仍然可以朝着这个目标迈出一步。只是人们需要大量的经验支持才能受益。

所以您可以教它,但不能从中学到任何东西。尤其是因为有些代码不太容易将其引入TDD。

评论


这是很多要教想要成为软件开发人员的学生的事情。如果课程有一个真实的软件模块,该模块具有以前的学生的经验,那就太好了。

– Paul McCarthy
20年1月14日在22:39

#7 楼

TDD在大学中并不流行,因为(通常来说)大学在确保向学生提供的知识可以转化为现实环境方面做得很差。

可以说,首先,这不是大学的角色,而更多的是讲授CS的基础知识和核心概念。如果学生对追求学术生涯感兴趣,那是有启发性的,重要的和必不可少的,但是当学生完成学位并进入该行业,并跟随团队发展而发展时,这是不够的最佳实践,CI / CD等。

很明显,存在很多交叉点,并且两者都可以互惠互利,但是,最终,大学还没有完全掌握毕业所需要做的工作更有能力,相关且最新的软件工程师。

评论


很好的答案,布鲁诺。 E Feliz Ano Novo,homem。

–行李箱
20年1月3日,15:25

这就是为什么代码训练营可以为编程职业提供更好的准备的原因。而且许多人可以根据他们开发和发布的实际应用程序自学并找到工作。学位并不总是答案。

– AlanKley
20年1月8日在17:46

#8 楼

我从来没有考虑过将TDD作为解决问题的有效方法,而在阅读了您的问题之后,我还是没有帮助。

TDD只是迫使您从一个方面(即客户的角度)着眼于问题。这可以帮助您避免提出与客户的问题不符的解决方案。通常这是一件好事,尽管它也可能会限制您,但它使您无法从更大的角度看待问题,对于您的客户未考虑的问题,可能会有更好,更通用的解决方案。

另一种看待它的方法是,这是最终的自上而下的方法。 TDD可以代表自顶向下开发。您从最高级别的课程开始开发,然后逐步放大。

,无论哪种方式,它都是一个抽象的概念。您可以告诉学生,提供定义,但是仅此而已。您在考试中不能问那么多问题。因此,在任何SE或CS类中,尽管在SE上下文中很有用,但它永远不过是旁注。

#9 楼

要直接回答这个问题:

正如有人建议的那样,整个学期都有足够的学习机会。一个单独的课程?也许。我可以看到TDD与软件设计主题结合在一起。 IMO TDD的最大价值是锁定现有行为,因此我们以后可以添加新行为,并更改设计以使其适合这些新行为。那么是软件设计课程吗?

很高兴看到TDD背后的思考过程(名字不好,我曾经问过Kent Beck是否会重新考虑;他说:“那列火车已经离开了车站”),尽早引入。自1976年以来,我就一直在编写代码,我知道TDD最初感觉很不自然。但是现在感觉很自然。编写测试代码并不能挽回我的时间,后来我只需每年修复一次严重的缺陷就可以重新获得回报(UofM Transplant Center的OTIS2软件完全由测试驱动编写,在2004年发生了最后一次“软件紧急情况” )。

我鼓励应届毕业生尝试一个月。但是,如果他们更早地接触TDD,对他们来说会容易得多。当我学习一种新语言时,我发现使用单元测试框架很有用(真实的故事:“现在如何通过Ruby通过此测试?也许这可以工作... HEY IT WORKED!”),或进行探索一个新的库(“文档对返回的顺序含糊不清...我将编写测试...”)。

我发现实现算法时TDD很有用(不发明一个...我会讲到这一点),或者像从头开始建立任何稍微复杂的业务规则。永久通过的每个测试都“锁定”。如果测试足够离散,则无需进行更改(但是要花好一个月才能花费很多时间)。

因此将TDD合并到早期的编程类中会很有趣。改进三点:


我们可以将精力放在调试和中断修复上,而大多数开发人员认为这只是他们工作的本质。不是。不必那么痛苦或费时。
单元测试框架可以简单地替换#ifdef DEBUG / printf(“ ...”)/ #endif-因此,我们一直在做类似的事情(但更具风险)。
当我们听到“您必须首先编写测试”时,我们被误导了。我想写下我对要编写的代码的期望。我希望在继续关注下一个行为或清理设计时保持运行状态。

另一有用的东西是教科书,或者至少是精简的,无意义的课程,其实验室旨在传达TDD实践的各个方面。我对此有一个建议(请参阅经验/免责声明)。

回答批评家:

我是新来的,但我注意到有些“答案”没有没有回答这个问题,但是对TDD提出了合理的批评。所以我想可以解决其中的一些问题吗?


是的,确实如此,将TDD与之后的单元测试(UTA)进行比较的研究表明,TDD是最初比较慢。但是,UTA组的测试覆盖率低得多,缺陷更多。我认为这是一项研究:在工业中使用测试驱动的开发实践的纵向研究


如果开发人员在产品上工作了几个月以上,而实际上却将大部分时间花在了编写新功能上,那么这将是负面的。但是我作为开发人员工作的六个TDD团队确实以这种方式度过了他们的时间,而我在TDD之前花了10年时间来执行代码吊装工作的十年大部分时间都花在了调试器上,或者是谨慎地复制/粘贴/修改,所以我不会老/其他人的代码。 TDD的优势并非一instant而就,但通过降低开发人员的加班时间(和压力)和增加收入来衡量,它们具有显着的可靠性和惊人的价值。底线:我一直很期待与这些TDD团队合作。 (一旦我喝了些茶。)



TDD也无法发明新的算法,这也是事实。我认为是Ron Jeffries尝试使用TDD创建Sudoku求解器,并试图不让自己的Sudoku技能干扰实现。他失败了。我不惊讶。 TDD有助于分解,简化和实施业务规则;帮助确认我们正确使用了算法(例如,可能无法归约的复杂加密算法);帮助我们稍后重塑代码,以便我们可以安全地添加新功能;并通过限制我们已经在产品性能方面进行的投资来做到这一点。

当您编写“测试”(即规范,又称为方案)时,您必须知道答案!另外,您还想编写一个测试解决方案,该测试对解决方案的影响很小,您已经对如何实现它有了一些概念(先验知识)。

通常令人惊讶的是,如果我们关注代码的气味,并且只要与该代码相关的所有测试通过,我们就会根据需要进行重构,那么设计就会变得如此清晰和简单。

没有人建议我们抛弃对设计模式,语言习语或SOLID原理,如何玩Sudoku或如何编写堆排序的精通知识。

TDD旨在创建一个安全网,使我们有信心快速添加新功能并更改设计以适应这些新功能,而又不会破坏其他任何功能。他们的死亡之洞。 (有趣的旁注:OTIS2项目是一个至关重要的系统,因此,对我们而言,患者死亡的风险并不是开玩笑的。在10分钟内运行了20,000多项测试,现在这是一个安全网!)

经验/免责声明:

从1998年到2004年,我几乎全职参加了TDD,并与大约6个不同的团队合作。所有这些都至少需要6个月的开发时间。在那之前,我花了13年的时间以其他方式编写软件,并开始讨厌使用printf()进行调试和手动测试。

我从2001年开始教授软件开发实践,现在包括TDD,BDD,和SA-CSD课程。当然,这是一种美好的生活,但我也知道TDD是使以团队为中心的软件开发理智又令人愉快的一种直接方法。所以...

我正在写我希望能成为一本大学或高中教科书的课程(当然还有在线回购,实验室,视频等):基本的测试驱动开发

#10 楼

在1970年代TDD(首字母缩写词TDD)的发明被发明之前,我就曾在计算机科学领域任教,当然,我们从来没有明确地教过该技术。但是对于我们给出的一个编程练习,我们提供了一组测试用例,并被告知我们的解决方案必须通过测试。因此,我在没有明确地学习它的情况下就了解了该方法的价值,并且从此以后一直使用它。

#11 楼

尽管编写测试是软件开发必不可少的技能,但科学证据并未表明TDD最终会生产出比迭代测试-最后(ITL)开发更好的软件(OTOH,这也不算差)。

有关证据,请参阅Davide Fucci等。 “使用多站点盲分析方法对测试驱动开发的效果进行外部复制”(链接)和Turhan等人在制作软件中进行的元分析(链接)。

因此,除非我们开始看到相反的证据表明,TDD确实提供了可衡量的收益,相对于在开发过程中的某个时刻简单地灌输测试写作的好习惯,教授TDD作为一种特定的实践并不重要。

评论


好吧,有人会说,理论上和实践之间没有区别……。观察几个(没有经验的)学生在永远不会被维护的项目上的理论表现,并查看实际CI / CD项目中的实际结果,而所研究的团队的数量是参与该项目的学生数量的两倍,这是完全不同的想法。那实验。要理解的是,这两种方法之间的主要区别将在维护和演进中发现,而不是在第一版中发现。

–克里斯托弗(Christophe)
20年1月9日在22:59

在Turhan的荟萃分析中,有许多针对研究生和专业工作者的研究,而TDD有效性的证据仍无定论。如果TDD从业人员希望提出自己的论据,他们将需要提高证据水平以显示出真正的效果。轶事的复数形式不是数据。

–́Anzel
20 Jan 10'在15:03

#12 楼


,但如果有人问,我仍然会花一些时间编写不带TDD的列表排序算法,而且如果不要求我仍不使用TDD来计算列表中元素的所有排列,我将一无所知。另一方面,借助TDD,我可以在几分钟内解决置换问题。


这使我感到困惑。
对我来说,测试驱动开发意味着考虑测试早点花点时间实施测试并及时更新代码。
当然,考虑要测试什么是阐述问题要解决的好机会,并且在某些情况下可以很好地了解陷阱
但是不做TDD,首先不专注于测试并不能禁止考虑潜在的问题。无论您是否要进一步采取措施并立即实施测试,您都应该考虑自己的工作并弄清楚情况。


解释会不会有问题在要求学生编写列表排序算法和类似内容之前使用TDD方法?


这取决于您在多大程度上解释TDD。
了解某些信息会很有帮助。但是学生会听到很多无法解释的内容,因为其他基本知识仍然缺失。因此,您不应该深入了解这样一个概念,即没有基础知识就会对他们毫无用处并疏远未知术语。
除此之外,也许许多程序员都知道如果您正在寻找一种方法,那会是什么样子-要解决某些问题并找到确实显示解决方案的示例,但首先您必须整理出作者添加的所有其他不相关的内容。

因此,为了回答这个问题,如果我是一名学生,我想把事情分开。如果您宣布要解释我们如何对列表进行排序,那么请告诉我们如何进行此操作,但不要留下填写测试内容的路径。如果您想开始解释测试,则不要宣布实施排序,因为这种情况已经很长时间都没有发生。
再次,在开始编写排序或测试之前,需要进行一些思考。列表在排序前后会显示什么?举例说明,考虑陷阱,在列表为空时必须考虑哪些因素,以免失败等等。必须考虑所有这些因素,但尚未编写测试行。

通常,我想说的是,您混淆了两个应分开保存的内容。


思考您要解决的问题的性质。
思考代码的输入以及应该给出的输出。

思考问题与专注于编写测试有很大不同案例。

如何做坏事

一旦我遇到一个痴迷于TDD的人,就遇到了一个TDD的例子。不幸的是,它在我看来作者太喜欢他的教程了,所以他没有意识到它实际上是什么废话。

作者只专注于测试用例,而不是他们的代码应该处理的问题。由于您永远找不到所有输入排列,因此必须对实际操作有一个总体了解,您必须了解整个问题。您不能总是从空的输入开始,然后再添加一些输入,并总是添加代码以正确处理新的输入。
您必须大致了解实际要处理的内容。但是作者没有。

如果我尝试将其转换为对列表进行排序,那么我们将从一个空列表开始,然后可以按原样返回一个元素,一个包含两个元素的列表可能需要交换,并且可能以递归结束,因为三个元素就像两个(我们已经解决了),再加上一个步骤又增加了一个元素...
排序算法的可怕选择-但没人会意识到,因为我们只专注于测试用例。

结论

这些评论使我对自己的见解多了一些。

我认为“测试驱动的开发”一词是错误的。它应该是“受测试支持的开发”,这意味着我们不仅要编写代码并希望如此,而且我们也考虑进行测试,我们知道尽早发现问题出在哪里总是件好事。

如果开发是由测试驱动的名称,这可能意味着一切仅取决于测试,并且只要满足几个测试用例,我们便会完成。即使是非常不足的代码(从未尝试从整体上看问题,但却被来回破解),直到所有测试用例都变成绿色,然后才在实际操作中失败,这样的需求才能得到满足。

评论


是的,我一直对仅添加足够的代码来满足测试的想法感到怀疑。这对于边界值测试很好。但是,如果您要测试连续范围,那就没用了。不能只说一个中值,然后是另一个,等等。在我看来,TDD仅在单独的测试团队编写测试及其完成顺序时才有效码。

–行李箱
20年1月3日,15:31

@Trunk测试也可以为开发人员提供帮助,编写代码的人可以对自己的代码进行更详细的考虑,也许会发现应该通过测试的陷阱。此外,测试可以帮助避免代码更改带来另一个陷阱。我要强调的是,不要仅仅依靠测试。测试不是唯一的救赎。不要停止思考代码,绝对不要产生bulls..t代码,只要它们通过了一些测试用例,而忽略了其余所有代码,那么它们就足够好了。对我而言,测试应该是编码的补充,而不是允许将其他所有内容都排除在外的完整编码方法。

–冰球
20 Jan 3 '20在16:15



@Trunk的真正区别在于,您只添加了足以满足测试要求的代码,但是您必须真诚地这样做。您编写表示测试用例的测试,然后实现满足测试用例的代码,而不是为了使测试变绿而是破坏过程的一些人为尝试。那么,让您充满信心的是,您对测试用例的直观理解与测试的自动验证之间的一致性-而不是总是可以被愚弄的测试本身。

– Ant P
20 Jan 7'20在8:43



“纯粹的”人群犯的错误是试图将TDD视为严格的正式过程,而不是-这是一种必须凭直觉应用的技术。

– Ant P
20年1月7日在8:44



@Trunk我认为TDD的最初想法多年来已经有些歪曲和歪曲,变成了一种黑暗的艺术。 TDD并没有试图取代手动测试仪,这两个目的有很大不同。最终,TDD可以帮助我编写我有信心的代码,这比QA人员感兴趣的范围要狭窄得多。

– Ant P
20 Jan 7 '20 at 13:26

#13 楼

您已将问题更新为更多的“为什么不将TDD不作为核心学习工具来教授?”。其他答案已经很好地解释了为什么TDD并不是编码101的好话题,但是主要的答案实际上只是TDD本身并不是解决问题的工具。它可以用于此目的,但是就像您必须首先了解何时以及如何使用它的任何工具一样。

TDD是一个测试过程,因此,很自然地,它会作为开发过程课程,或作为软件测试课程的一部分。在编写101门课程的编码中,目标不是让学生解决问题,而是教他们如何使用各种编程概念。通常,大多数编码101和102项目将非常明确地说明如何解决问题,学生只需要了解他们所学到的以非复制粘贴方式完成任务的方式即可。

每个学生都以不同的方式学习。有些学生需要阅读它,其他一些学生则需要对他们进行口头解释,而另一些学生则除非他们精通代码,否则永远不会得到它。教TDD以帮助学习过程实际上并不会帮助大多数学生,而确实有帮助的学生呢?教师将不得不决定时间教学TDD是否值得额外的学习速度。从总体上看,教授任何一种学习方法都不值得花在课堂上的实际时间上。 (通常,学习和解决问题的能力通常留给学生自己学习,因为只有学生才能确定最适合他们的方法)。

TL:RD;不同的人有不同的有效过程。大学没有规定您应该做什么。只要给您工具,您就可以做最适合您的事情。

评论


TDD是一个测试过程,因此最自然地将其作为“开发过程”课程的一部分或作为“软件测试”课程的一部分进行教授。语句的开头和结尾不正确。 TDD不是“测试过程”。这是一个涉及测试的开发过程。区别不是平凡的:测试过程是首先具有某些东西,然后建立测试过程的东西。 TDD首先要创建东西(通过测试)。绝不会在“测试”课程中教授该课程。

–tgm1024--莫妮卡遭到虐待
20 Mar 9 '20在15:48



@ tgm1024-Monica误以为测试过程尚不存在。例如,您可以开发甚至在开发开始之前最终产品就可以通过的用户故事。 TDD只是更改了完成的顺序,但关键部分仍然是测试。它的过程部分将在Dev-Proc类中进行较高级别的介绍,而TDD的底层实际自动化测试编写将在测试类中进行介绍。 (这就是在我的大学所教的方式)。我还会争辩说,不要专注于过多使用的确切单词,因为它们不是标准化的。青年汽车

–特斯拉
20 Mar 9 '20 at 16:21

不,这又不是测试过程,我知道TDD中的顺序是什么。您仍然缺少TDD不是测试过程,而只是将测试作为开发过程的组成部分这一事实。 TDD中的步骤不是要测试某些东西。他们要创造一些东西:他们这样做的方法是首先建立一个测试。测试过程类似于列出功能规格并验证每个规格是否有效,然后进行回归测试以确保它们不会使您退后。这是一个测试过程。您甚至根本不需要开发人员。

–tgm1024--莫妮卡遭到虐待
20 Mar 11 '20 at 0:12

@ tgm1024--Monicawasmisapped您似乎想念您所使用的单词未标准化的事实。自从软件开发成为一种事物以来,关于它们的含义的普遍共识一直在不断变化。答案的关键是,TDD是一种工具,并且像其他任何工具一样,TDD也有时间和位置,但是并不能自动地适合所有人。不必担心所用单词的语义。着眼于一般点。

–特斯拉
20 Mar 11 '20 at 12:10

根据定义,当您使用错误的术语时,这是语义上的问题,是的,这些术语是标准化的;我不知道为什么您会顽固地坚持这种错误信息。在这里,我将为您详细说明:质量检查工程师接受了测试技术和测试流程的培训。质量保证工程师绝不会在TDD附近冒险,因为他们不参与开发流程。那是给软件工程师的。

–tgm1024--莫妮卡遭到虐待
20 Mar 15 '14:26



#14 楼

TDD是一种出色的实现工具,我认为您是对的,因为它对希望编写软件的人有利。


TDD根本不被教导或根本不被教导的原因是什么?至少在大学很晚?换句话说,在要求学生编写列表排序算法和类似内容之前解释TDD方法是否有问题?


最大的原因可能是教授这些程序的教授很少知道如何开发软件,因为这不是他们的专业领域。就像其他答案提到的那样,计算机科学和软件工程是不同的学科,我将计算机科学专业的学生与软件设计的物理学生的期望与物理学专业的学生进行比较。 TDD是一项需要大量实践才能真正有效教授的技能,计算机科学教授将其职业生涯的大部分时间都用于计算机科学,因此希望计算机科学系的老师真的能够以某种方式教授TDD在我看来,这不仅会使学生感到困惑,而且是不现实的。

我们需要将计算机科学和专业软件开发视为各自独立的领域。如果您的目标是学习计算机科学,那么您应该花数千美元来学习如何在React中错误地建立网站,而这笔费用是由他在职业生涯的最后30年中一直在粉笔板上进行图论研究的人承担的。同样,如果您的目标是成为一名软件工程师,我不知道您为什么要花费4年和数万美元来学习本质上只是数学的特定领域。对该领域有一个基本的了解是很好的,就像设计排气歧管的人需要了解一定数量的物理学一样,但是设计排气歧管的人不需要太深入地了解量子力学,特别是相对论和电磁学来完成他们的工作。

如果您想成为一名会计师,就可以获取会计学位,而您的教授很可能都曾在某一点上成为注册会计师。如果您想成为机械工程师,则可以获取机械工程学位,而您的教授很可能都在某一方面获得了许可工程师的资格。但是,如果您想成为一名软件工程师,则任何软件工程学位实际上都将是计算机科学学位,并且已经为您选择了一些选修课,并且几乎没有您的教授会成为专业软件开发人员。会计学位不是数学系的一部分,机械工程学位不是物理系的一部分,但是软件工程学位几乎总是属于计算机科学系的一部分。在整个学术界将这两个领域完全划分为由不同人员管理的不同部门之前,我认为总会有一长串诸如TDD之类的东西不被那些渴望成为软件工程师的学生所教。

评论


确实,教授“很少”知道如何开发软件,但是您无法在此基础上将任何可观的推销钉在TDD上。我从事专业程序员已有40年了。我也不喜欢它,因为我在评论中进行了详细说明。这又是另一种趋势(类似于极限编程),据称是“ tada!”。此刻,最终忘了底线而最终陷入了困境:您现在在组件到组件开发上花费的时间是否比在发布之前进行单元测试所花费的时间更多?

–tgm1024--莫妮卡遭到虐待
20 Mar 9 '20 at 15:53

IOW,如果您擅长TDD,那么您已经擅长于单元测试的基础知识。如果不是这样,那么在组件级开发期间进行的任何预测试都同样会很弱。不一定特定于您,但是如果您只参与了游戏几十年左右,就很难了解趋势的来龙去脉,而且更是如此:趋势为什么如此。

–tgm1024--莫妮卡遭到虐待
20 Mar 9 '20在15:55