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過程來開發一個非常簡單的函數,以及怎樣使用函數來驗證多個場景。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM