Cucumber行为驱动开发BDD入门教程 JavaScript版

本博客从Cucumber官方教程翻译过来,因水平有限,翻译有误的地方请读者不吝赐教。

原网页点击这里。

以下是翻译部分:


在这个快速教程中,你将学习如何:

  • 安装Cucumber

  • 使用Gherkin语法写第一个场景(Scenario)

  • 使用JavaScript写第一个步骤定义(step definition)

  • 运行Cucumber

  • 学习BDD的基本工作流

我们将用Cucumber来开发一个可以辨别今天是否已经星期五的小型库(library)。

在我们开始前,你需要以下工具:

  • Node.js

  • 一个文本编辑器

打开终端,验证Node.js已经恰当安装了:

node -v
npm -v

这两行命令各自都应该会打印出版本号。

 

创建一个空的Cucumber项目

我们通过创建一个新的文件夹和一个空的Node.js项目来开始。

mkdir hellocucumber
cd hellocucumber
npm init --yes

添加Cucumber作为开发的依赖

npm install cucumber --save-dev

在文本编辑器中打开package.json,改变test处,使它看起来像:

{
 "name": "hellocucumber",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
   "test": "cucumber-js"
},
 "keywords": [],
 "author": "",
 "license": "ISC",
 "devDependencies": {
   "cucumber": "^5.0.3"
}
}

准备文件结构

mkdir features
mkdir features/step_definitions

在项目的根目录创建一个cucumber.js文件,添加以下内容:

module.exports = {
 default: `--format-options '{"snippetInterface": "synchronous"}'`
}

创建一个features/step_definitions/stepdefs.js文件,添加以下内容:

const assert = require('assert');
const { Given, When, Then } = require('cucumber');

你现在就有了一个安装了Cucumber的简单项目。

 

 

验证Cucumber安装

为了确保每个组件在一起能够正确工作,我们现在运行Cucumber

# Run via NPM
npm test

#Run standalone
./node_modules/.bin/cucumber-js

你应该能看见类似下面内容:

0 Scenarios
0 steps
0m00.000s

Cucumber的输出告诉我们它没有发现可以运行的场景。

 

 

写一个Scenario

当我们用Cucumber来完成BDD时,我们使用具体的例子(example)来指定我们想要软件完成什么功能。场景(Scenario)要在产品代码之前编写。它们(指场景)以可执行规范(executable specification)的身份作为它们生命周期的开始。当产品代码做出来后,场景就承担起活文件(living documentation)和自动化测试(automated tests)的角色。

在Cucumber中,一个实例(example)被称为一个场景(Scenario)。场景在.feature文件中定义, 该文件放在features文件夹或其子文件夹中。

一个具体的实例(concrete example)是星期天不是星期五。

创建一个名为features/is_it_friday_yet.feature空文件,添加以下内容:

Feature: Is it Friday yet?
Everybody wants to know when it's Friday

Scenario: Sunday isn't Friday
  Given today is Sunday
  When I ask whether it's Friday yet
  Then I should be told "Nope"

这个文件的第一行以关键字Feature:开头,后跟着一个名字。使用和文件名一样的名字比较好。

第二行是对特征(feature)的简要介绍。Cucumber不会运行这行,它只起到文档记录的作用。

第四行中Scenario: Sunday is not Friday是一个场景(Scenario),就是一个描述了软件表现什么行为的具体实例(concrete example)。

最后以关键字Given,WhenThen开头的三行是四个场景的步骤(step)。这里是Cucumber将会执行的地方。

 

 

看到提示scenario是undefined

既然我们有了一个场景,我们可以让Cucumber执行它。

npm test

Cucumber将会告诉我们,有一个undefined的场景和三个undefined的步骤。同时Cucumber还会建议我们用一些代码片段来定义(define)这三个步骤:

UUU

Warnings:

1) Scenario: Sunday is not Friday # features/is_it_friday_yet.feature:4
  ? Given today is Sunday
      Undefined. Implement with the following snippet:

        Given('today is Sunday', function () {
          // Write code here that turns the phrase above into concrete actions
          return 'pending';
        });

  ? When I ask whether it's Friday yet
      Undefined. Implement with the following snippet:

        When('I ask whether it\'s Friday yet', function () {
          // Write code here that turns the phrase above into concrete actions
          return 'pending';
        });

  ? Then I should be told "Nope"
      Undefined. Implement with the following snippet:

        Then('I should be told {string}', function (string) {
          // Write code here that turns the phrase above into concrete actions
          return 'pending';
        });


1 Scenario (1 undefined)
3 steps (3 undefined)
0m00.000s

复制这三个undefined步骤的代码片段,把它们粘到features/step_definitions/stepdefs.js

 

 

看到提示scenario是pending

重新运行Cucumber。这次输出有一点不一样:

P--

Warnings:

1) Scenario: Sunday is not Friday # features/is_it_friday_yet.feature:4
  ? Given today is Sunday # features/step_definitions/stepdefs.js:3
      Pending
  - When I ask whether it's Friday yet # features/step_definitions/stepdefs.js:8
  - Then I should be told "Nope" # features/step_definitions/stepdefs.js:13

1 Scenario (1 pending)
3 steps (1 pending, 2 skipped)
0m00.001s

Cucumber发现了我们的一个步骤定义并且执行了它。它们被标识为pending,意味着我们需要让它们做一些有意义的事情。

 

 

看到提示scenario为failing

下一步就是完成在步骤定义的注释告诉我们要做的事情。

Write code here that turns the phrase above into concrete actions

尝试在步骤的代码中使用同样的单词。

把你的步骤定义代码变成这样:

const assert = require('assert');
const { Given, When, Then } = require('cucumber');

function isItFriday(today) {
 // We'll leave the implementation blank for now
}

Given('today is Sunday', function () {
 this.today = 'Sunday';
});

When('I ask whether it\'s Friday yet', function () {
 this.actualAnswer = isItFriday(this.today);
});

Then('I should be told {string}', function (expectedAnswer) {
 assert.equal(this.actualAnswer, expectedAnswer);
});

重新运行Cucumber:

..F

Failures:

1) Scenario: Sunday is not Friday # features/is_it_friday_yet.feature:4
  ✔ Given today is Sunday # features/step_definitions/stepdefs.js:8
  ✔ When I ask whether it's Friday yet # features/step_definitions/stepdefs.js:12
  ✖ Then I should be told "Nope" # features/step_definitions/stepdefs.js:16
      AssertionError [ERR_ASSERTION]: undefined == 'Nope'
          at World.<anonymous> (/private/tmp/tutorial/hellocucumber/features/step_definitions/stepdefs.js:17:10)

1 Scenario (1 failed)
3 steps (1 failed, 2 passed)

进步了!前两个步骤通过了,但是最后一个失败了。

 

 

看到提示scenario为passing

让我们完成可能的最简单的事情来让场景得以通过。在这个例子中,只需要让函数返回Nope就可以了:

function isItFriday(today) {
 return 'Nope';
}

重新运行Cucumber:

...

1 Scenario (1 passed)
3 steps (3 passed)
0m00.003s

恭喜你!你已经得到你的第一个Cucumber全绿的场景。

 

 

添加另一个failing测试

下一个要测试的东西是,当今天是星期五的时候我们应该得到结果为正确。

更新is-it-friday-yet.feature文件:

Feature: Is it Friday yet?
Everybody wants to know when it's Friday

Scenario: Sunday isn't Friday
  Given today is Sunday
  When I ask whether it's Friday yet
  Then I should be told "Nope"

Scenario: Friday is Friday
  Given today is Friday
  When I ask whether it's Friday yet
  Then I should be told "TGIF"

我们需要增加一个步骤定义来设置today为Friday:

Given('today is Friday', function () {
 this.today = 'Friday';
});

当我们运行这个测试时,将会失败:

.....F

Failures:

1) Scenario: Friday is Friday # features/is_it_friday_yet.feature:9
  ✔ Given today is Friday # features/step_definitions/stepdefs.js:8
  ✔ When I ask whether it's Friday yet # features/step_definitions/stepdefs.js:16
  ✖ Then I should be told "TGIF" # features/step_definitions/stepdefs.js:20
      AssertionError [ERR_ASSERTION]: 'Nope' == 'TGIF'
          + expected - actual

          -Nope
          +TGIF

          at World.<anonymous> (/private/tmp/tutorial/hellocucumber/features/step_definitions/stepdefs.js:21:10)

2 scenarios (1 failed, 1 passed)
6 steps (1 failed, 5 passed)

这是因为我们还没有完成逻辑部分!让我们接下来完成这个工作。

 

 

通过

我们应该更新我们的代码,让它真的去验证today是否等于Friday

function isItFriday(today) {
 if (today === "Friday") {
   return "TGIF";
} else {
   return "Nope";
}
}

重新运行Cucumber:

......
2 scenarios (2 passed)
6 steps (6 passed)
0m00.002s

 

 

使用变量和实例

众所周知,一个星期除了星期天和星期五外还有其它天。让我们使用变量来更新场景,然后验证更多的可能性。我们将会使用变量和实例来验证星期五,星期天和任意其它天。

更新is-it-friday-yet.feature文件。注意当我们开始使用多个实例(Examples)时,我们是如何从单个场景(Scenario)到场景大纲(Scenario Outline)的:

Feature: Is it Friday yet?
Everybody wants to know when it's Friday

Scenario Outline: Today is or is not Friday
  Given today is "<day>"
  When I ask whether it's Friday yet
  Then I should be told "<answer>"

Examples:
  | day | answer |
  | Friday | TGIF |
  | Sunday | Nope |
  | anything else! | Nope |

我们需要用一个读取<day>字符串的值的步骤定义来替换原来的步骤定义中的today is Sundaytoday is Friday两处地方。更新stepdefs.js文件,像下面这样:

const assert = require('assert');
const { Given, When, Then } = require('cucumber');

function isItFriday(today) {
 if (today === "Friday") {
   return "TGIF";
} else {
   return "Nope";
}
}

Given('today is {string}', function (givenDay) {
 this.today = givenDay;
});

When('I ask whether it\'s Friday yet', function () {
 this.actualAnswer = isItFriday(this.today);
});

Then('I should be told {string}', function (expectedAnswer) {
 assert.equal(this.actualAnswer, expectedAnswer);
});

重新运行Cucumber:

.........

3 scenarios (3 passed)
9 steps (9 passed)
0m00.001s

 

 

重构

既然我们有了可以工作的代码,我们应该做一些重构工作:

  • 我们应该把isItFriday函数从测试代码中移到生成代码中

  • 我们可以从步骤定义中的某些地方提取一些helper方法,这样在分布在几个地方的函数都可以使用。

 

 

总结

在这个简短的教程中,你了解了如何安装Cucumber,如何跟着BDD过程来开发一个非常简单的函数,以及怎样使用函数来验证多个场景。

猜你喜欢

转载自www.cnblogs.com/wangnig/p/10332397.html