测试驱动开发 (TDD) 的好处已广为人知,它能提升产品质量和开发效率。每次编写代码测试时,都能确保代码的正确性,并能及时发现未来可能出现的代码错误。
行为驱动开发 (BDD) 在此基础上更进一步,它测试的是产品的行为,而非仅仅是代码,确保产品行为符合预期。本文将介绍如何使用 Cucumber 框架编写 BDD 风格的自动化验收测试。Cucumber 的优势在于,测试用例可以用简洁的自然语言编写,方便项目中非技术人员理解。阅读本文后,您可以判断 Cucumber 是否适合您的团队,并开始编写自己的验收测试。准备好了吗?让我们开始吧!
关键要点
- BDD 在 TDD 的基础上,测试的是产品的行为而非代码,使其更易于被包括非技术人员在内的更广泛的利益相关者理解。
- Cucumber 是一个 BDD 框架,它使用 Gherkin(一种易于理解的语言)来定义测试用例,确保所有利益相关者都能理解并参与测试过程。
- Gherkin 语法将测试结构化为场景和特性,使用简单的 Given、When、Then 步骤来描述行为,而无需规定技术实现。
- Cucumber.js 与 JavaScript 项目集成,运行 Gherkin 定义的测试,并通过各种插件和配置支持异步操作和外部测试工具。
- Cucumber.js 的设置包括通过 npm 安装模块,配置它来查找特性文件和步骤定义,以及将其可选地集成到构建脚本或任务运行器(如 Grunt 或 Gulp)中。
- 本文提供了一个基本的 Cucumber 测试示例,演示了为加法和乘法设置 Gherkin 场景,使用简单的断言来验证这些操作的正确性。
- 本文还概述了 Cucumber.js 的高级功能,例如对异步测试的支持、用于参数化测试的场景大纲以及用于设置前提条件和后置条件的钩子,以增强测试能力。
BDD 与 TDD 的区别
主要体现在测试的结构和编写方式上。在 TDD 中,测试由编写代码的开发人员编写、维护和理解。其他人可能根本不需要阅读测试,这完全没问题。但在 BDD 中,测试需要被比编写功能的开发人员多得多的人理解。许多利益相关者都关心产品行为是否正确,例如 QA 人员、产品分析师、销售人员,甚至高层管理人员。这意味着,理想情况下,BDD 测试需要以任何理解产品的人都能理解的方式编写。区别在于:
const assert = require('assert'); const webdriver = require('selenium-webdriver'); const browser = new webdriver.Builder() .usingServer() .withCapabilities({'browserName': 'chrome' }) .build(); browser.get('http://en.wikipedia.org/wiki/Wiki'); browser.findElements(webdriver.By.css('[href^="/wiki/"]')) .then(function(links){ assert.equal(19, links.length); // 假设的数字 browser.quit(); });
以及:
const assert = require('assert'); const webdriver = require('selenium-webdriver'); const browser = new webdriver.Builder() .usingServer() .withCapabilities({'browserName': 'chrome' }) .build(); browser.get('http://en.wikipedia.org/wiki/Wiki'); browser.findElements(webdriver.By.css('[href^="/wiki/"]')) .then(function(links){ assert.equal(19, links.length); // 假设的数字 browser.quit(); });
这两个测试执行相同的操作,但一个是可读的自然语言,另一个只能被了解 JavaScript 和 Selenium 的人理解。本文将向您展示如何使用 Cucumber.js 框架在 JavaScript 项目中实现 BDD 测试,从而使您的产品受益于这种级别的测试。
什么是 Cucumber/Gherkin?
Cucumber 是一个用于行为驱动开发的测试框架。它允许您以 Gherkin 格式定义测试,并通过将其与代码绑定来使这些 Gherkin 可执行。Gherkin 是一种领域特定语言 (DSL),用于编写 Cucumber 测试。它允许以人类可读的格式编写测试脚本,然后可以在产品开发中的所有利益相关者之间共享。Gherkin 文件是包含用 Gherkin 语言编写的测试的文件。这些文件通常具有 .feature 文件扩展名。这些 Gherkin 文件的内容通常简称为“Gherkin”。
Gherkin
在 Gherkin 定义的测试中,您有特性和场景的概念。它们类似于其他测试框架中的测试套件和测试用例,提供了一种清晰的测试结构方式。场景只是一个单独的测试。它应该只测试应用程序中的一个方面。特性是一组相关的场景。因此,它将测试应用程序中许多相关的方面。理想情况下,Gherkin 文件中的特性将与应用程序中的特性紧密映射——因此得名。每个 Gherkin 文件都包含一个特性,每个特性都包含一个或多个场景。场景然后由步骤组成,这些步骤按特定顺序排列:
- Given – 这些步骤用于在执行测试之前设置初始状态
- When – 这些步骤是实际要执行的测试
- Then – 这些步骤用于断言测试结果
理想情况下,每个场景都应该是一个单独的测试用例,因此 When 步骤的数量应该保持非常少。步骤是完全可选的。例如,如果您根本不需要设置任何内容,则可能没有 Given 步骤。Gherkin 文件旨在易于阅读,并使参与产品开发的任何人都能受益。这包括非技术人员,因此 Gherkin 文件应始终使用业务语言而不是技术语言编写。这意味着,例如,您不引用单个 UI 组件,而是描述您想要测试的产品概念。
Gherkin 测试示例
以下是搜索 Google 的 Cucumber.js 的 Gherkin 示例:
Given I have opened a Web Browser When I load the Wikipedia article on "Wiki" Then I have "19" Wiki Links
我们可以立即看到,此测试告诉我们做什么,而不是如何做。它使用任何人都能理解的语言编写,并且——重要的是——无论最终产品如何调整,它都最有可能保持正确。Google 可能会决定完全更改其 UI,但只要功能等效,则 Gherkin 仍然准确。您可以在 Cucumber wiki 上阅读更多关于 Given When Then 的信息。
Cucumber.js
在以 Gherkin 格式编写测试用例后,您需要一种方法来执行它们。在 JavaScript 世界中,有一个名为 Cucumber.js 的模块允许您执行此操作。它允许您定义 JavaScript 代码,Cucumber.js 可以将其连接到 Gherkin 文件中定义的各种步骤。然后,它通过加载 Gherkin 文件并按正确的顺序执行与每个步骤关联的 JavaScript 代码来运行测试。例如,在上面的示例中,您将拥有以下步骤:
const assert = require('assert'); const webdriver = require('selenium-webdriver'); const browser = new webdriver.Builder() .usingServer() .withCapabilities({'browserName': 'chrome' }) .build(); browser.get('http://en.wikipedia.org/wiki/Wiki'); browser.findElements(webdriver.By.css('[href^="/wiki/"]')) .then(function(links){ assert.equal(19, links.length); // 假设的数字 browser.quit(); });
不必过于担心所有这些含义——稍后将详细解释。但本质上,它定义了一些方法,Cucumber.js 框架可以使用这些方法将您的代码绑定到 Gherkin 文件中的步骤。
(以下内容与原文基本一致,略作调整以保持流畅性和可读性,并对部分语句进行同义词替换)
将 Cucumber.js 包含在您的构建中
将 Cucumber.js 包含在您的构建中,只需将 cucumber 模块添加到您的构建中,然后配置它即可运行。第一步如下所示:
Given I have opened a Web Browser When I load the Wikipedia article on "Wiki" Then I have "19" Wiki Links
第二步取决于您如何执行构建。
手动运行
手动执行 Cucumber 相对容易,最好先确保您可以这样做,因为以下解决方案都是自动执行相同操作的方法。安装后,可执行文件将是 ./node_modules/.bin/cucumber.js
。运行它时,它需要知道在文件系统上的哪个位置可以找到所有必需的文件。这些文件既包括 Gherkin 文件,也包括要执行的 JavaScript 代码。按照惯例,所有 Gherkin 文件都将保存在 features 目录中,如果您没有指示它执行其他操作,则 Cucumber 也将在同一目录中查找要执行的 JavaScript 代码。但是,指示它查找这些文件的位置是一种明智的做法,这样您可以更好地控制构建过程。例如,如果您将所有 Gherkin 文件保存在 myFeatures 目录中,并将所有 JavaScript 代码保存在 mySteps 中,则可以执行以下操作:
Given I have loaded Google When I search for "cucumber.js" Then the first result is "GitHub - cucumber/cucumber-js: Cucumber for JavaScript"
-r
标志是一个包含 JavaScript 文件的目录,Cucumber 会自动加载这些文件用于测试。还有一些其他标志可能也很有趣——只需阅读帮助文本即可了解它们的工作方式:$ ./node_modules/.bin/cucumber.js --help
。这些目录会递归扫描,因此您可以根据具体情况将文件嵌套得浅或深。
npm 脚本
手动运行 Cucumber 后,将其添加到构建中作为 npm 脚本是一个简单的情况。您只需将以下命令(无需完全限定路径,因为 npm 会为您处理)添加到您的 package.json
中,如下所示:
Given('I have loaded Google', function() {}); When('I search for {stringInDoubleQuotes}', function() {}); Then('the first result is {stringInDoubleQuotes}', function() {});
完成后,您可以执行:
$ npm install --save-dev cucumber
它将完全按照您之前所做的那样执行 Cucumber 测试。
Grunt
确实存在一个用于执行 Cucumber.js 测试的 Grunt 插件。不幸的是,它已经过时了,并且不适用于更新版本的 Cucumber.js,这意味着如果您使用它,您将错过许多改进。相反,我更喜欢的方法是简单地使用 grunt-shell 插件以与上述完全相同的方式执行命令。安装后,配置它只需将以下插件配置添加到您的 Gruntfile.js 中:
const assert = require('assert'); const webdriver = require('selenium-webdriver'); const browser = new webdriver.Builder() .usingServer() .withCapabilities({'browserName': 'chrome' }) .build(); browser.get('http://en.wikipedia.org/wiki/Wiki'); browser.findElements(webdriver.By.css('[href^="/wiki/"]')) .then(function(links){ assert.equal(19, links.length); // 假设的数字 browser.quit(); });
现在,和以前一样,您可以通过运行 grunt shell:cucumber
来执行测试。
Gulp
Gulp 与 Grunt 的情况完全相同,因为现有的插件已经过时,并且将使用旧版本的 Cucumber 工具。同样,在这里您可以使用 gulp-shell 模块像在其他场景中一样执行 Cucumber.js 命令。设置它很简单:
Given I have opened a Web Browser When I load the Wikipedia article on "Wiki" Then I have "19" Wiki Links
现在,和以前一样,您可以通过运行 gulp cucumber
来执行测试。
您的第一个 Cucumber 测试
请注意,本文中的所有代码示例都可以在 GitHub 上找到。
现在我们知道了如何执行 Cucumber,让我们实际编写一个测试。在这个示例中,我们将做一些相当人为的事情,只是为了展示系统的工作原理。实际上,您会做更复杂的事情,例如直接调用您正在测试的代码、对正在运行的服务进行 HTTP API 调用或控制 Selenium 来驱动 Web 浏览器以测试您的应用程序。我们的简单示例将证明数学仍然有效。我们将有两个特性——加法和乘法。首先,让我们进行设置。
Given I have loaded Google When I search for "cucumber.js" Then the first result is "GitHub - cucumber/cucumber-js: Cucumber for JavaScript"
您如何执行测试完全取决于您。在这个示例中,为了简单起见,我将手动执行它。在一个真实的项目中,您将使用上述选项之一将其集成到您的构建中。
Given('I have loaded Google', function() {}); When('I search for {stringInDoubleQuotes}', function() {}); Then('the first result is {stringInDoubleQuotes}', function() {});
现在,让我们编写我们的第一个实际特性。这将放在 features/addition.feature
中:
$ npm install --save-dev cucumber
非常简单,非常易于阅读。它准确地告诉我们正在做什么,而没有告诉我们如何去做。让我们尝试一下:
(以下内容与原文基本一致,略作调整以保持流畅性和可读性,并对部分语句进行同义词替换)
然后让我们编写我们的第一个步骤文件。这将简单地按照 Cucumber 输出告诉我们的方式实现步骤,这不会做任何有用的事情,但会整理输出。这将放在 steps/maths.js
中:
const assert = require('assert'); const webdriver = require('selenium-webdriver'); const browser = new webdriver.Builder() .usingServer() .withCapabilities({'browserName': 'chrome' }) .build(); browser.get('http://en.wikipedia.org/wiki/Wiki'); browser.findElements(webdriver.By.css('[href^="/wiki/"]')) .then(function(links){ assert.equal(19, links.length); // 假设的数字 browser.quit(); });
defineSupportCode
钩子是 Cucumber.js 的一种方法,允许您提供它将用于各种不同情况的代码。所有这些都将被涵盖,但本质上,任何时候您想要编写 Cucumber 将直接调用的代码,它都需要在这些块中的一个内部。您会注意到,此处的示例代码定义了三个不同的步骤——每个 Given、When 和 Then 一个。每个块都给出一个字符串(或者如果您需要的话,是一个正则表达式),该字符串与特性文件中的步骤匹配,以及在该步骤匹配时执行的函数。占位符可以放在步骤字符串中(或者如果您使用的是正则表达式,则使用捕获表达式代替),这些占位符将被提取出来并作为参数提供给您的函数。执行此操作将提供更简洁的输出,同时仍然实际上什么也不做:
(以下内容与原文基本一致,略作调整以保持流畅性和可读性,并对部分语句进行同义词替换)
现在让我们让它全部工作。我们只需要在我们步骤定义中实现代码即可。我们还将进行一些整理,以使阅读更容易。这实际上消除了对回调参数的需求,因为我们没有做任何异步操作。之后,我们的 steps/maths.js
将如下所示:
Given I have opened a Web Browser When I load the Wikipedia article on "Wiki" Then I have "19" Wiki Links
执行它看起来像这样:
(以下内容与原文基本一致,略作调整以保持流畅性和可读性,并对部分语句进行同义词替换)
就这样,我们得到了一个非常易于扩展的测试套件,它证明了数学是正确的。作为一个练习,为什么不尝试扩展它以支持减法呢?如果您遇到困难,可以在评论中寻求帮助。
(以下内容与原文基本一致,略作调整以保持流畅性和可读性,并对部分语句进行同义词替换,并对部分章节进行合并和简化)
更高级的 Cucumber.js技巧
这都很好,但是 Cucumber 可以做一些更高级的事情,这将使我们的生活更轻松。
异步步骤定义
到目前为止,我们只编写了同步步骤定义。但是,在 JavaScript 世界中,这通常不够好。JavaScript 中的很多东西都需要异步,因此我们需要一些方法来处理它。谢天谢地,Cucumber.js 有几种内置的方法来处理这个问题,这取决于您的喜好。上面暗示过的方法,这是处理异步步骤的更传统的 JavaScript 方法,是使用回调函数。如果您指定步骤定义应该将回调函数作为其最后一个参数,则只有在触发此回调后,才认为步骤已完成。在这种情况下,如果回调使用任何参数被触发,则这被认为是一个错误,并且步骤将失败。如果它在没有任何参数的情况下被触发,则认为步骤已成功。但是,如果根本没有触发回调,则框架最终会超时并使步骤失败。故事的寓意?如果您接受回调参数,请确保调用它。例如,使用回调进行 HTTP API 调用的步骤定义可能如下所示。这是使用 Request 编写的,因为它在响应上使用回调。
(以下内容与原文基本一致,略作调整以保持流畅性和可读性,并对部分语句进行同义词替换)
另一种方法,也是更优选的方法是通过返回类型。如果您从步骤返回一个 Promise,则只有当 Promise 完成时,才认为步骤已完成。如果 Promise 被拒绝,则步骤将失败;如果 Promise 被 fulfilled,则步骤将成功。或者,如果您返回的内容不是 Promise,则步骤将立即被认为已成功。这包括返回 undefined 或 null。这意味着您可以在步骤执行期间选择是否需要返回 Promise,并且框架将根据需要进行调整。例如,使用 Promises 进行 HTTP API 调用的步骤定义可能如下所示。这是使用 Fetch API 编写的,因为它在响应上返回一个 Promise。
(以下内容与原文基本一致,略作调整以保持流畅性和可读性,并对部分语句进行同义词替换,并对部分章节进行合并和简化)
特性背景、场景大纲、数据表、钩子、事件和世界
这些高级特性,例如特性背景、场景大纲、数据表,以及钩子函数(Before, After, BeforeStep, AfterStep等)和事件处理机制,都能够极大地提高测试效率和可读性。通过合理运用这些功能,可以编写更简洁、更易维护的BDD测试。 World
对象允许在不同的步骤定义之间共享数据和状态,从而简化测试逻辑。
(以下内容与原文基本一致,略作调整以保持流畅性和可读性,并对部分语句进行同义词替换)
总结
行为驱动开发是一种确保产品具有正确行为的绝佳方法,而 Cucumber 作为一种工具,是一种非常强大的方法,可以实现这一点,以便产品的每个利益相关者都能阅读、理解甚至编写行为测试。本文只是触及了 Cucumber 能够实现的皮毛,因此我鼓励您自己尝试一下,以了解其强大功能。Cucumber 还拥有一个非常活跃的社区,他们的邮件列表和 Gitter 频道是寻求帮助的好方法,如果您需要的话。您是否已经在使用 Cucumber?本文是否鼓励您尝试一下?无论哪种方式,我都想在下面的评论中听到您的声音。本文由 Jani Hartikainen 进行了同行评审。感谢所有 SitePoint 的同行评审者,使 SitePoint 内容达到最佳状态!
(以下内容与原文基本一致,略作调整以保持流畅性和可读性,并对部分语句进行同义词替换)
关于使用 Cucumber 和 Gherkin 的 JavaScript 中 BDD 的常见问题 (FAQ)
(以下内容与原文基本一致,略作调整以保持流畅性和可读性,并对部分语句进行同义词替换)
以上是BDD在JavaScript:开始使用Cucumber和Gherkin的详细内容。更多信息请关注PHP中文网其他相关文章!

JavaScript字符串替换方法详解及常见问题解答 本文将探讨两种在JavaScript中替换字符串字符的方法:在JavaScript代码内部替换和在网页HTML内部替换。 在JavaScript代码内部替换字符串 最直接的方法是使用replace()方法: str = str.replace("find","replace"); 该方法仅替换第一个匹配项。要替换所有匹配项,需使用正则表达式并添加全局标志g: str = str.replace(/fi

利用轻松的网页布局:8个基本插件 jQuery大大简化了网页布局。 本文重点介绍了简化该过程的八个功能强大的JQuery插件,对于手动网站创建特别有用

因此,在这里,您准备好了解所有称为Ajax的东西。但是,到底是什么? AJAX一词是指用于创建动态,交互式Web内容的一系列宽松的技术。 Ajax一词,最初由Jesse J创造

10款趣味横生的jQuery游戏插件,让您的网站更具吸引力,提升用户粘性!虽然Flash仍然是开发休闲网页游戏的最佳软件,但jQuery也能创造出令人惊喜的效果,虽然无法与纯动作Flash游戏媲美,但在某些情况下,您也能在浏览器中获得意想不到的乐趣。 jQuery井字棋游戏 游戏编程的“Hello world”,现在有了jQuery版本。 源码 jQuery疯狂填词游戏 这是一个填空游戏,由于不知道单词的上下文,可能会产生一些古怪的结果。 源码 jQuery扫雷游戏

本教程演示了创建通过Ajax加载的动态页面框,从而可以即时刷新,而无需全页重新加载。 它利用jQuery和JavaScript。将其视为自定义的Facebook式内容框加载程序。 关键概念: Ajax和JQuery

此JavaScript库利用窗口。名称属性可以管理会话数据,而无需依赖cookie。 它为浏览器中存储和检索会话变量提供了强大的解决方案。 库提供了三种核心方法:会话

本教程演示了如何使用jQuery创建迷人的视差背景效果。 我们将构建一个带有分层图像的标题横幅,从而创造出令人惊叹的视觉深度。 更新的插件可与JQuery 1.6.4及更高版本一起使用。 下载


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

SublimeText3 Linux新版
SublimeText3 Linux最新版

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

WebStorm Mac版
好用的JavaScript开发工具

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器