---
title: "基本語法：輔助設定 - Cucumber 的文件測試法"
date: 2024-02-02T00:00:00+08:00
publishDate: 2024-02-02T00:00:00+08:00
lastmod: 2023-12-06T15:50:15+08:00
tags: ["Cucumber","教學","測試","Gherkin","輔助"]
series: "test-with-cucumber"
toc: true
permalink: "https://blog.aotoki.me/posts/2024/02/02/test-with-cucumber-syntax-support/"
language: "zh-tw"
---


Cucumber 的 Gherkin 語法本身並不複雜，然而除了步驟定義（Step Definition）之外，我們還可以加入輔助方法、標籤等等設定，讓我們的測試案例更加容易維護。

<!--more-->

## 標籤{#tag}

標籤功能在 Cucumber 中預設會用來標記「處理中（Work In Progress）」的功能，這樣就可以避免還沒實作的功能因為已經撰寫好文件，而破壞持續整合（Continuous Integration）的運作，而中斷整個開發流程。

```gherkin
@wip
Feature: 按讚功能
  @wip
  Scenario: 單次點選可以增加一個讚
```

標籤可以針對 `Feature` 或者 `Scenario` 來做標記，如果是部分完成的功能可以針對還沒實現的場景標記就可以確保已經實作的功能被測試。

除此之外，我們也可以針對這些標籤進行特定的操作，像是「切換功能開關（Feature Flag）」之類的處置。

```gherkin
@pre-release
Feature: 按讚功能
```

接下來只需要在 `features/support/env.rb` 或者 `features/support/env.js` 裡面，利用掛鉤（Hook），描述這個標籤要做的事情。

```ruby
Before('@pre-release') do
  # 啟用功能
end
```

```ts
const { Before } = require('@cucumber/cucumber')

Before({ tags: '@pre-release' }, async () => {
  // 啟用功能
})
```

這樣我們就可以針對尚未釋出的新功能也進行測試，而不用擔心被使用者實際使用到這些功能。

## 輔助方法{#helper}

在步驟定義的時候，我們可能經常要建立使用者，或者產生一些測試資料。然而當類似的步驟增加時，我們會有許多的重複實現，假設這些行為都是類似的，我們可以透過輔助法（Helper）來彙整這些重複的動作。

```ruby
module UserTestHelpers
  def create_user(name:)
    # ...
  end
end

World(UserTestHelpers)
```

在 Ruby 的環境中，我們像這樣定義一個模組，就會被加入到 Cucumber 運行的測試環境中，然而在 JavaScript 的環境中，要加入輔助方法比較複雜一些，會需要使用自訂世界（Custom World）的機制，也算是受限於語言特性。

> 正因如此 Ruby 會使用 `World` 這個語法去擴充原有世界。

## 世界{#world}

在 Cucumber 的觀點下，測試是在一個世界中運作的，因此我們實際上描述的是一個世界發生的事件與產生的變化。在這樣的前提下，我們在前面步驟做的所有改變，都能在後續的步驟存取到。

```ruby
Given('開始計數') do
  @count = 1
end

When('增加計數') do
  @count += 1
end
```

```ts
When('增加計數', async function (this: World, user: string text: string) {
  this.count += 1
})
```

那麼，當我們想加入新的輔助方法或者全域狀態時，在 JavaScript 的環境就需要自訂一個世界，對這些資訊進行描述。

```ts
const { setWorldConstructor, World, When } = require('@cucumber/cucumber')

class CustomWorld extends World {
  count = 0

  constructor(options) {
    super(options)
  }

  createUser(name: string) {
    // ...
  }
}

setWorldConstructor(CustomWorld)
```

像這樣子，我們就能夠讓 Cucumber 意識到 `this.count` 的存在，以及可以使用 `this.creaetUser()` 來進行一些處理。

這些會是我們在使用 Cucumber 撰寫測試會使用到的常見語法，接下來我們就會實際的以開發簡單的小功能來實際感受用 Cucumber 來撰寫文件並且同步進行測試的效果如何。

