测试驱动开发(TDD)的测试是否总是单元测试?


41

到目前为止,我了解测试驱动的开发,因此仅当单元测试失败(红色)时,才可以编写高效的代码。基于此,我有一个问题,即测试驱动方法是否也可以应用于其他形式的测试。


6
嵌套使用不止一种不同级别的红色/绿色/重构也很常见。例如,您可以在编写验收/行为测试时遵循红色/绿色/重构,其中验收测试的“绿色”阶段本身包含单元测试的多个红色/绿色/重构迭代。
肖恩·伯顿

1
标题与问题内容不符。标题为“测试始终是单元测试 ”(答案:否,除单元测试外还可以存在其他类型的测试),内容询问“您必须先编写测试吗?”。
AnoE

@AnoE内容的第一句话只是一个介绍性陈述。秒句不询问是否必须首先编写测试,而是询问TDD方法是否可以用于TDD以外的其他测试方法。
user1364368

@ user1364368,请随意重新表述一下问题,至少我对您的初读意图和投票最多的问题感到困惑,而在解决这两个句子时,也是从第一个开始。
AnoE

@AnoE我更改了第二个句子的开头以明确实际的问题是什么。
user1364368

Answers:


27

TDD所需要的只是编写一个失败的测试,然后修改代码以使其通过。

通常,“单元测试”既小又快速,可以单独测试部分代码。因为它们速度很快,所以它也使红色/绿色/重构循环也很快。但是,它们只能单独测试零件。因此,您还需要其他测试(集成,验收等)。遵循相同的原则仍然是一种好习惯:编写失败的测试,然后修改代码以使其起作用。请注意,它们通常较慢,因此会影响红色/绿色/重构周期。


59

红绿色重构周期基于一个非常合理的原理:

只有您看到的信任测试通过和失败。

是的,它也适用于自动集成测试。还要手动测试。哎呀,它适用于汽车电池测试仪。这就是您测试测试的方式。

有些人认为单元测试涵盖了可以测试的最小内容。有些人认为任何可以快速测试的东西。TDD不仅仅是红色绿色的重构周期,而且该部分具有一组非常特定的测试:理想情况下,在提交一组更改之前,您最好先运行一次这些测试。每次进行更改时都将运行这些测试。对我来说,这些是您的单元测试。


1
这也是为什么在测试错误时否定测试很重要的原因之一:您要确保其他所有功能都可以正常工作,因此在旁边有两个测试(一个产生确切的预期错误,另一个不产生错误)互相帮助提升信心,在未来的这个红/绿状态将持续下去。
Matthieu M.

12

但是,我想知道测试驱动方法是否也可以应用于其他形式的测试。

是的,做到这一点的众所周知的方法是行为驱动的开发。从BDD的正式规范中生成的测试可以称为“单元测试”,但是它们通常不会像在真正的TDD中那样低级,它们可能更适合术语“验收测试”。


8

到目前为止,我了解测试驱动的开发,因此仅当单元测试失败(红色)时,才可以编写高效的代码。

不可以。只允许您编写最简单的代码来更改测试消息。它没有说明哪种测试。

实际上,您可能会首先针对接受标准编写一个失败的(红色)接受测试,更准确地说,就是编写可能会失败的最简单的接受测试。之后,您运行测试,观察它是否失败,并验证它是否因正确的原因而失败。然后,为该接受标准的一部分功能编写失败的功能测试,再次,编写可能会失败的最简单的功能测试,运行它,观察它是否失败,并验证它是否因正确的原因而失败。然后编写一个失败的单元测试,这是可能会失败的最简单的单元测试,运行它以观察失败,并验证它是否因正确的原因而失败。

现在,您编写了可能会更改错误消息的最简单的生产代码。再次运行测试,确认错误消息已更改,错误消息方向正确,并且代码出于正确的原因更改了消息。(理想情况下,错误消息应该现在就消失了,并且测试应该通过,但是通常,采取微小的步骤来更改消息而不是尝试使测试一次通过是更好的选择–这就是原因为什么测试框架的开发人员在错误消息上花费了很多精力!)

一旦单元测试通过,就可以在测试的保护下重构生产代码。(请注意,此时,验收测试和功能测试仍然失败,但这没关系,因为您仅重构了单元测试所涵盖的单个单元。)

现在,您创建下一个单元测试并重复上述步骤,直到功能测试也通过为止。在功能测试的保护下,您现在可以跨多个单元进行重构。

现在将重复此中间周期,直到通过验收测试为止,此时您可以在整个系统中进行重构。

现在,您选择下一个验收标准,外部循环再次开始。

TDD的“发现者”肯特·贝克(他不喜欢“发明家”一词,他说人们一直以来都在这样做,他只是给它起了个名字,并写了一本关于它的书)。称之为“放大和缩小”。

注意:您并不总是需要三个级别的测试。也许有时候您需要更多。更多时候,您需要的更少。如果您的功能很小,并且功能测试很快,那么您可以不使用(或使用较少的单元测试)。通常,您只需要验收测试和单元测试。或者,您的接受标准非常精细,以至于您的接受测试功能测试。

肯特·贝克说,如果他有一个快速,小型且专注的功能测试,他将首先编写单元测试,让单元测试驱动代码,然后再次删除(部分)覆盖代码的单元测试。快速功能测试涵盖的范围。请记住:测试代码也是需要维护和重构的代码,数量越少越好!

但是,我想知道测试驱动方法是否也可以应用于其他形式的测试。

您并不是真的将TDD应用于测试。您将其应用于整个开发过程。这就是性能测试的“驱动”部分驱动 -Development手段:所有的发展是由测试驱动。该试验不仅带动你写的代码,他们也开车什么的代码来写,旁边写一个代码。他们驱动您的设计。他们告诉您什么时候完成。他们告诉您接下来要做什么。它们告诉您代码中的设计缺陷(难以编写测试时)。

Keith Braithwaite创建了一个演习,他将其称为TDD,就好像您是故意的那样。它包含一组您必须严格遵守的规则(基于Bob Martin叔叔的TDD的三个规则,但更为严格),旨在指导您更严格地应用TDD。它最适合与结对编程(这样结对可以确保您没有违反规则)和一名讲师一起使用。

规则是:

  1. 准确地编写一个新测试,这似乎是可以解决问题的最小测试
  2. 看到它失败了;编译失败计为失败
  3. 通过编写您在test方法中可以实现的最少实现代码,使(1)通过测试
  4. 重构以消除重复,否则可以根据需要改进设计。请严格遵守以下步骤:
    1. 您需要一个新方法-等待重构时间,然后…通过执行其中一种方法来创建新的(非测试)方法,而没有其他方法:
      • 首选:对根据(3)创建的实现代码执行Extract Method,以在测试类中创建新方法,或者
      • 如果您必须:将(3)中的实现代码移到现有的实现方法中
    2. 您需要一个新类-等待重构时间,然后…创建非测试类以提供Move方法的目的地,而没有其他原因
    3. 通过执行Move方法,用方法填充实现类,而没有其他方法

这些规则旨在执行TDD。它们并不是实际在生产中进行TDD的目的(尽管没有什么可以阻止您进行尝试)。他们可能会感到沮丧,因为有时您似乎要迈出几千个微小的小步骤而没有取得任何实际进展。


2

TDD完全不限于传统软件测试社区所称的“单元测试”。这种非常普遍的误解是肯特·贝克(Kent Beck)在描述他的TDD实践时不幸地超载了“单位”一词的结果。他所说的“单元测试”是一种独立运行的测试。它不依赖于其他测试。每个测试都必须设置所需的状态,并在完成后进行任何清理。从这个意义上说,TDD意义上的单元测试是一个单元。它是自包含的。它可以单独运行,也可以与任何其他单元测试一起以任何顺序运行。

参考:“通过示例进行的测试驱动开发”,作者:Kent Beck

肯特·贝克(Kent Beck)在第32章-掌握TDD中描述了“单元测试”的含义


1

我还没有读过任何书,也一直没有完全遵循“标准的” TDD做法,但是在我看来,我完全同意的TDD哲学的要点是,您必须首先定义成功。从“该项目的目标是什么?”到设计的每个级别,这一点都很重要。改为“这种小方法的输入和输出应该是什么?”

定义成功的方法有很多。一个有用的方法,特别是对于那些可能具有很多极端情况的低级方法,是用代码编写测试。对于某些抽象级别,仅写下有关模块目标或其他内容的快速注释,甚至只是在心理上检查自己(或请同事)以确保一切都有意义并保持在合理状态即可。逻辑的地方。有时用代码描述集成测试会有所帮助(当然,这有助于使它自动化),有时定义一个合理的快速测试计划会很有用,您可以使用该计划来确保所有系统以您所使用的方式协同工作在期待。

但是,无论您使用哪种特定的技术或工具,在我看来,要摆脱TDD哲学的关键是,首先要确定成功。否则,您将投掷飞镖,然后在碰到的任何地方画靶心。


1

在“ 测试驱动开发”一文中:这不是我们的意思,史蒂夫·弗里曼(Steve Freeman)展示了TDD大图的以下幻灯片(请参见下面的答案)。这包括一个步骤“写一个失败的端到端测试”,然后是“写一个失败的单元测试”。(单击以放大,其位于右上角)

因此,在TDD中没有测试不是始终是单元测试。

是的,您可以(也许应该)从更高级别的端到端测试开始,该测试在编写第一个单元测试之前就失败了。此测试描述了您想要实现的行为。这将覆盖更多级别的test-pyramid。Adrian Sutton解释了LMAX的经验,经验表明端到端测试可以发挥重要作用

在此处输入图片说明


-1

不,由于简单的实际原因,它不能应用于其他类型的测试:其他类型的测试执行所需的时间过长。

典型的TDD周期为:编写失败的测试,实施,重构代码。介于两者之间的步骤是构建和执行测试,而这些步骤需要快速完成。如果不是,那么人们将开始跳过步骤,然后您就不再进行TDD。


1
这是不正确的:根据程序和测试(和语言)的不同,端到端集成测试可以轻松在不到3秒的时间内运行。即使设计合理,也完全可以在极短的时间内运行完整的端到端测试套件。所以“不能”是很强的。
乔纳森·

@jcast我再也没有见过这么快的东西。我在上一个项目中进行的功能测试花费了30秒,而且速度很快。集成时间更长。就我而言,没有其他意义。另外,单元测试是所有测试中最快的-因此使用它们是有意义的。
BЈовић
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.