您现在的位置:首页 > 教案怎么写 > 正文

测试教案怎么写 怎么TDDTDD的基本流程是什么?(一)

2021-11-10 15:10 网络整理 教案网

这篇文章的结构:

什么是TDD

TDD有广义和狭义之分。常说的狭义是TDD,也就是UTDD(Unit Test Driven Development)。广义上的TDD就是ATDD(Acceptance Test Driven Development),包括BDD(Behavior Driven Development)和Consumer-Driven Contracts Development。

本文提到的TDD是指狭义的TDD,即“单元测试驱动开发”。

TDD 是敏捷开发的核心实践和技术,也是一种设计方法论。TDD的原理是在开发功能代码之前先写单元测试用例代码,测试代码决定了需要写什么产品代码。TDD 是 XP(极限编程)的核心实践。它的主要推动者是肯特贝克。

TDD具有三个含义:

为什么 TDD 传统编码 VS TDD 编码

传统编码

TDD编码方式

TDD 的好处

减轻开发者的负担

通过一个清晰的过程,让我们一次只关注一个点,思考的负担就少了。

防护网

TDD的优势在于它涵盖了完整的单元测试,并为产品代码提供了保护网,让我们可以轻松应对需求变化或改进代码设计。

所以如果你的项目需求稳定,一气呵成,不做任何后续改动,你就能少享受到TDD带来的好处。

提前明确要求

先写测试可以帮助我们提前思考需求,明确需求的细节,而不是在代码写到一半时才发现不清楚的需求。

快速反馈

很多人讲TDD的时候,我的代码量增加了,所以开发效率降低了。但是,如果没有单元测试,则必须手动测试。你要花很多时间准备数据、启动应用程序、跳转到界面等等,而且反馈很慢。准确地说,快速反馈是单元测试的好处。

TDD怎么样

TDD

TDD的基本流程是:红、绿、重构。

机械工程测试技术 教案_测试教案怎么写_如何写测试报告

更详细的过程是:

你可能会问,如果我写一个测试用例,它显然会失败,我必须运行它吗?

是的。你可能认为测试只有成功和失败两种情况。然而,失败的种类数不胜数。只有运行测试才能确保当前的故障是您期望的故障。

一切都是为了让程序达到预期,这样当出现错误时,可以快速定位错误(肯定是刚刚修改的代码引起的,因为一分钟前的代码符合我的预期)。

这样就节省了大量调试代码的时间。

TDD 的三个规则不允许编写任何产品代码,除非它是通过失败的单元测试。在单元测试中,只允许写入可能导致失败的内容(编译错误也视为失败)。通过失败的单元测试通过的产品代码

如果违反了会怎样?

违反第一条,先写产品代码。这段代码需要实现什么?如何保证真正实现?

违反第二条,写了多次失败的测试。如果长时间测试失败,会增加开发者的压力。此外,测试可能会被重构,这会增加测试的修改成本。

违反第三条,产品代码实现了超出当前测试的功能,则这部分代码不受测试保护,不知道正确与否,需要人工测试。也许这是一个不存在的需求,它凭空增加了代码的复杂性。如果是已经存在的需求,那么下面的测试就直接通过了,破坏了TDD的节奏。

我认为它的本质是:

分开关注,一次只戴一顶帽子

在我们的编程过程中,有几个关注点:需求、实现和设计。

TDD 为我们提供了三个明确的步骤,每个步骤都侧重于一个方面。

红色:编写失败的测试。它是对一个小需求的描述。你只需要关心输入和输出。此时,您无需关心如何实现它。

绿色:专注于以最快的方式实现当前的小需求测试教案怎么写,不关心其他需求,也不关心代码质量有多糟糕。

重构:不需要考虑需求,也没有实现的压力,只需找出代码中的异味,并用一种​​方法消除它,使代码成为干净的代码。

注意力控制

人们的注意力可以被主动控制或被动吸引。如果你来回转换你的注意力,你会消耗更多的能量,你的思维也会不够完整。

使用TDD开发,我们需要主动控制attention。写测试的时候发现没有定义一个类,IDE提示编译错误。这时候,如果你创建了这个类,你的注意力就不会放在需求上,已经切换到了实现方面,我们应该集中精力写这个测试,想想它是否表达了需求,开始消除确认无误后编译出错。

为什么很多人做不了TDD?

测试教案怎么写_机械工程测试技术 教案_如何写测试报告

不会合理拆分任务

在TDD之前,任务是拆分的,一个大需求被分成多个小需求。

您还可以拆分多个功能。

不能写测试

什么是有效的单元测试?很多人写测试。他们甚至不知道正在测试什么,或者他们甚至没有断言。它们可以通过控制台输出和视觉比较来验证。

一个好的单元测试应该遵循几个原则:

不会只写实现

很多人在写实现的时候不能专注于当前的需求,不小心实现了其他的需求,破坏了节奏感。

当谈到实现时,它不会采取小步骤。

不会重构

我不知道 Clean Code 是什么,我没有看到 Smell,我也没有及时重构它。当我想重构时很难开始。

我不知道如何用适当的“技巧”来消除气味。

基础设施

对于特定的技术栈,单元测试基础设施没有搭建好,导致在编写测试时无法专注于测试用例。

实例

编写一个程序来计算文本文件words.txt 中每个单词的出现频率。

为简单起见,假设:

例如,假设 words.txt 包含以下内容:

天气晴朗

晴天是

您的程序应输出以下内容,按频率的相反顺序排序:

如何写测试报告_测试教案怎么写_机械工程测试技术 教案

4

是 3

晴天2

第一天

请不要往下读,想想你会怎么做。

(思考3分钟……)

当一个新手得到这样的需求时,他会把所有的代码写在一个 main() 方法中。伪代码如下:

main() {
    // 读取文件
    ...
    // 分隔单词
    ...
    // 分组
    ...
    // 倒序排序
    ...
    // 拼接字符串
    ...
    // 打印
    ...
}

思路很清晰,但往往是一口气完成,最后运行,但输出不符合预期,然后开始断点调试。

这段代码没有任何封装。这也是为什么很多人在听说有的公司把一个方法限制在10行以内的时候,立马跳出来说这是不可能的。10行可以做什么?我们的业务逻辑很复杂...

这样的代码有什么问题?

好吧,让我们来谈谈 TDD。读取文件和输出控制台的测试代码是怎么写的?

当然,我们可以通过Mock和Stub来隔离IO,但是真的有必要吗?

有人问 Kent Beck 这个问题:

你真的会测试一切吗?甚至会测试 getter 和 setter 吗?

Kent Beck 说:公司邀请我去实现商业价值,而不是写测试代码。

所以我只在我没有信心的地方写测试代码。

对于我们的程序来说,读取文件和打印到控制台都是调用系统API,所以你可以很放心。最不自信的是中间的业务逻辑。

所以我们可以对程序做一些封装。根据“代码清洁度”,可以在有注释的地方提取方法,可以用方法名代替注释:

main() {
    String words = read_file('words.txt')
    String[] wordArray = split(words)
    Map frequency = group(wordArray)
    sort(frequency)
    String output = format(frequency)
    print(output)
}

是否可以分别为 split、group、sort 和 format 编写单元测试?

如何写测试报告_测试教案怎么写_机械工程测试技术 教案

当然,他们的输入输出是非常清晰的。

等等,你可能会说,这不是测试驱动设计吗?你是如何开始设计的?好问题!

TDD应该提前设计吗?

Kent Beck 没有提前设计,他会选择最简单的用例,直接写出来,用最简单的代码通过测试。逐渐增加测试,使代码更复杂,并使用重构来驱动设计。

在这个需求中,最简单的场景是什么?

即文件内容为空,输出也为空。

当然,对于复杂的问题,你可能会在编写的时候添加新的用例,但是对于这么简单的话题,你基本上可以提前考虑什么用例会驱动什么产品代码。

您可能会想到以下用例:

Martin Fowler 的观点是,在我们编写代码来做 Big Front Up Design 之前,我们必须在开始编写代码之前设计所有细节。

有了重构工具之后,设计的压力就小了很多,因为有测试代码保护,我们可以随时重构实现。但这并不意味着我们不需要提前设计。提前设计可以让我们与他人讨论,并在开始编写代码之前迭代几次。在纸上迭代总是比更改代码更快。

我个人很认同 Martin Fowler 的做法,先在脑子里设计(当然我脑子不够用,所以我用纸来画),经过几次迭代后开始写作。这样,我还是会用最简单的实现来通过测试。但是重构的时候有方向,效率更高。

回到这个程序,我发现当前的包不是抽象的。更理想的设计是:

分解任务

main() {
    String words = read_file('words.txt')
    String output = word_frequency(words)
    print(output)
}
word_frequency(words) {
    String[] wordArray = split(words)
    Map frequency = group(wordArray)
    sort(frequency)
    return format(frequency)
}

这个时候,还有两个选择。有些人喜欢自上而下,有些人喜欢自下而上,我个人更喜欢前者。

从现在开始,只需遵循红绿重构循环即可。

大多数TDD都做的不好,也就是没有之前的任务分解和Example列举的过程。

想看TDD过程可以参考我的直播。

或者,如有必要,我也可以录制有关此主题的视频。

常问问题

测试教案怎么写_机械工程测试技术 教案_如何写测试报告

为什么要先写测试测试教案怎么写,后补测试?

OK,但是写完实现后,马上写一个测试,用测试来验证实现。如果先手动测试,调试代码,再添加单元测试,会觉得很鸡肋,增加工作量。

无论您是先测试还是后测试,您都可以享受快速反馈,但如果您先测试,您还可以享受另一个好处,即使用意图驱动的编程来减少返工。因为你的测试代码是产品代码的客户端(调用者),你可以随意编写测试代码(方法名、参数、返回值等),然后实现产品代码,而不是先写实现然后写Testing,前者返工少。

我刚刚写了一个测试,但还没有写一个实现。明知道运行测试会报错,为什么还要运行呢?

其实,测试的结果不仅仅是通过和失败,因为失败的可能性有很多。所以如果知道肯定失败,就运行测试,目的是看是否报了预期的错误。

小步子固然好,但你真的需要这么小步子吗?

台阶太大,容易拉鸡蛋。

练习时需要养成小步的习惯,工作时可以自由切换步的大小。

当您有信心时,您可以采取更长的步骤。当你没有信心时,你可以立即切换到小步模式。如果只能迈出大步,就很难迈出小步。

测试代码会成为维护负担吗?

在维护时,我们也遵循TDD流程,先修改测试代码看需求变化,让测试失败,再修改产品代码通过。

这样你就不用维护测试用例,而是使用测试用例。

为什么要快速实施?

实际上,二分查找法是用来隔离问题的。测试通过硬编码后,基本确定测试没有问题,然后实现产品代码。如果测试失败,则是产品代码问题。

所以这小步主要是隔离问题,也就是可以和Debug说再见了。

为什么测试代码应该简单?

如果一个测试失败,修复的时候改的是测试代码而不是产品代码,也就是测试代码写的不好。

当测试代码足够简单时,如果测试失败,您就有足够的信心得出结论,它一定是产品代码有问题。

什么时候不适合TDD?

如果您正在进行不需要长期维护的探索性技术研究(Spike),并且测试基础设施的构建成本很高,那么最好进行手动测试。

此外,还有“可测试性极差的遗留系统”和“使用对测试不友好的技术堆栈”的系统。TDD 可能会超过收益。

学习路径 《有效的单元测试》 《代码清洁》 《重构》 转型优先前提 《以测试为导向的开发实例》 《以测试为导向的成长型面向对象软件》扩展阅读

本文最初发表于 GitChat。文章已免费发表。欢迎购买问答记录。