cucumber-gherkin
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCucumber & Gherkin Skill
Cucumber & Gherkin 技能指南
BDD testing framework with plain-text executable specifications. Gherkin syntax with step definitions in Ruby, JavaScript, Java, or Python.
基于纯文本可执行规格说明的BDD测试框架。支持Ruby、JavaScript、Java或Python语言的步骤定义与Gherkin语法。
Core Concepts
核心概念
Cucumber reads executable specifications in plain text and validates software behavior. Gherkin is the structured grammar making plain text machine-readable.
┌────────────┐ ┌──────────────┐ ┌───────────┐
│ Steps │ │ Step │ │ │
│ in Gherkin ├──matched with──>│ Definitions ├───manipulates──>│ System │
└────────────┘ └──────────────┘ └───────────┘Cucumber 读取纯文本格式的可执行规格说明,并验证软件行为。Gherkin 是一种结构化语法,让纯文本内容能够被机器识别。
┌────────────┐ ┌──────────────┐ ┌───────────┐
│ Steps │ │ Step │ │ │
│ in Gherkin ├──matched with──>│ Definitions ├───manipulates──>│ System │
└────────────┘ └──────────────┘ └───────────┘Gherkin Syntax Quick Reference
Gherkin语法速查
Primary Keywords
核心关键字
gherkin
Feature: Short description
Optional multi-line description explaining the feature.
Background:
Given common setup steps for all scenarios
Rule: Business rule grouping (Gherkin 6+)
Scenario: Concrete example illustrating the rule
Given an initial context (past tense, setup)
When an action occurs (present tense, trigger)
Then expected outcome (assertion)
And additional step
But negative assertion
Scenario Outline: Parameterized scenario
Given there are <start> items
When I remove <remove> items
Then I should have <remaining> items
Examples:
| start | remove | remaining |
| 12 | 5 | 7 |
| 20 | 5 | 15 |gherkin
Feature: Short description
Optional multi-line description explaining the feature.
Background:
Given common setup steps for all scenarios
Rule: Business rule grouping (Gherkin 6+)
Scenario: Concrete example illustrating the rule
Given an initial context (past tense, setup)
When an action occurs (present tense, trigger)
Then expected outcome (assertion)
And additional step
But negative assertion
Scenario Outline: Parameterized scenario
Given there are <start> items
When I remove <remove> items
Then I should have <remaining> items
Examples:
| start | remove | remaining |
| 12 | 5 | 7 |
| 20 | 5 | 15 |Step Keywords
步骤关键字
| Keyword | Purpose | Example |
|---|---|---|
| Setup/precondition | |
| Action/trigger | |
| Assertion/outcome | |
| Continue previous type | |
| Negative continuation | |
| Bullet-style step | |
| 关键字 | 用途 | 示例 |
|---|---|---|
| 初始化/前置条件 | |
| 动作/触发事件 | |
| 断言/预期结果 | |
| 延续同类型步骤 | |
| 反向延续步骤 | |
| 无序列表式步骤 | |
Data Structures
数据结构
Data Tables - tabular data:
gherkin
Given the following users exist:
| name | email | role |
| Alice | alice@example.com | admin |
| Bob | bob@example.com | user |Doc Strings - multi-line text:
gherkin
Given a blog post with content:
"""markdown
# My Post Title
This is the content of my blog post.
"""数据表 - 表格形式的数据:
gherkin
Given the following users exist:
| name | email | role |
| Alice | alice@example.com | admin |
| Bob | bob@example.com | user |文档字符串 - 多行文本:
gherkin
Given a blog post with content:
"""markdown
# My Post Title
This is the content of my blog post.
"""Tags
标签
gherkin
@smoke @critical
Feature: User authentication
@wip
Scenario: Login with valid credentials
...
@slow @database
Scenario: Bulk user import
...Tag expressions: , ,
@smoke and not @slow@gui or @api(@smoke or @critical) and not @wipgherkin
@smoke @critical
Feature: User authentication
@wip
Scenario: Login with valid credentials
...
@slow @database
Scenario: Bulk user import
...标签表达式:、、
@smoke and not @slow@gui or @api(@smoke or @critical) and not @wipStep Definitions
步骤定义
Match Gherkin steps to code. Use Cucumber Expressions (preferred) or Regular Expressions.
将Gherkin步骤与代码关联。推荐使用Cucumber表达式,也支持正则表达式。
Ruby
Ruby
ruby
Given('I have {int} cucumbers in my belly') do |count|
@belly = Belly.new
@belly.eat(count)
end
When('I wait {int} hour(s)') do |hours|
@belly.wait(hours)
end
Then('my belly should growl') do
expect(@belly.growling?).to be true
endruby
Given('I have {int} cucumbers in my belly') do |count|
@belly = Belly.new
@belly.eat(count)
end
When('I wait {int} hour(s)') do |hours|
@belly.wait(hours)
end
Then('my belly should growl') do
expect(@belly.growling?).to be true
endWith data table
With data table
Given('the following users exist:') do |table|
table.hashes.each do |row|
User.create!(row)
end
end
undefinedGiven('the following users exist:') do |table|
table.hashes.each do |row|
User.create!(row)
end
end
undefinedJavaScript
JavaScript
javascript
const { Given, When, Then } = require('@cucumber/cucumber');
Given('I have {int} cucumbers in my belly', function(count) {
this.belly = new Belly();
this.belly.eat(count);
});
When('I wait {int} hour(s)', async function(hours) {
await this.belly.wait(hours);
});
Then('my belly should growl', function() {
expect(this.belly.isGrowling()).toBe(true);
});
// With data table
Given('the following users exist:', async function(dataTable) {
for (const row of dataTable.hashes()) {
await User.create(row);
}
});javascript
const { Given, When, Then } = require('@cucumber/cucumber');
Given('I have {int} cucumbers in my belly', function(count) {
this.belly = new Belly();
this.belly.eat(count);
});
When('I wait {int} hour(s)', async function(hours) {
await this.belly.wait(hours);
});
Then('my belly should growl', function() {
expect(this.belly.isGrowling()).toBe(true);
});
// With data table
Given('the following users exist:', async function(dataTable) {
for (const row of dataTable.hashes()) {
await User.create(row);
}
});Java
Java
java
public class StepDefinitions {
@Given("I have {int} cucumbers in my belly")
public void iHaveCucumbersInMyBelly(int count) {
belly = new Belly();
belly.eat(count);
}
@When("I wait {int} hour(s)")
public void iWaitHours(int hours) {
belly.wait(hours);
}
@Then("my belly should growl")
public void myBellyShouldGrowl() {
assertTrue(belly.isGrowling());
}
}java
public class StepDefinitions {
@Given("I have {int} cucumbers in my belly")
public void iHaveCucumbersInMyBelly(int count) {
belly = new Belly();
belly.eat(count);
}
@When("I wait {int} hour(s)")
public void iWaitHours(int hours) {
belly.wait(hours);
}
@Then("my belly should growl")
public void myBellyShouldGrowl() {
assertTrue(belly.isGrowling());
}
}Cucumber Expressions
Cucumber表达式
Built-in parameter types: , , , , (anonymous)
{int}{float}{word}{string}{}Optional text: matches "cucumber" or "cucumbers"
Alternative text: matches "color" or "colour"
cucumber(s)color/colour内置参数类型:、、、、(匿名)
{int}{float}{word}{string}{}可选文本: 匹配 "cucumber" 或 "cucumbers"
备选文本: 匹配 "color" 或 "colour"
cucumber(s)color/colourHooks
钩子
Scenario Hooks
场景钩子
ruby
undefinedruby
undefinedRuby
Ruby
Before do |scenario|
runs before each scenario
end
After do |scenario|
runs after each scenario
screenshot if scenario.failed?
end
```javascript
// JavaScript
const { Before, After } = require('@cucumber/cucumber');
Before(async function(scenario) {
// runs before each scenario
});
After(async function(scenario) {
// runs after each scenario
if (scenario.result.status === 'FAILED') {
await this.screenshot();
}
});Before do |scenario|
runs before each scenario
end
After do |scenario|
runs after each scenario
screenshot if scenario.failed?
end
```javascript
// JavaScript
const { Before, After } = require('@cucumber/cucumber');
Before(async function(scenario) {
// runs before each scenario
});
After(async function(scenario) {
// runs after each scenario
if (scenario.result.status === 'FAILED') {
await this.screenshot();
}
});Conditional Hooks (with tags)
条件钩子(带标签)
ruby
Before('@database') do
DatabaseCleaner.start
end
After('@database') do
DatabaseCleaner.clean
endjavascript
Before({ tags: '@browser and not @headless' }, async function() {
this.browser = await launchBrowser();
});ruby
Before('@database') do
DatabaseCleaner.start
end
After('@database') do
DatabaseCleaner.clean
endjavascript
Before({ tags: '@browser and not @headless' }, async function() {
this.browser = await launchBrowser();
});Global Hooks
全局钩子
ruby
BeforeAll do
# once before any scenario
end
AfterAll do
# once after all scenarios
endruby
BeforeAll do
# once before any scenario
end
AfterAll do
# once after all scenarios
endBest Practices
最佳实践
Declarative over Imperative
声明式优于命令式
Good (declarative):
gherkin
When "Bob" logs in
Then he sees his dashboardAvoid (imperative):
gherkin
When I visit "/login"
And I enter "bob" in "username"
And I enter "secret" in "password"
And I click "Login"
Then I should see "Dashboard"推荐(声明式):
gherkin
When "Bob" logs in
Then he sees his dashboard避免(命令式):
gherkin
When I visit "/login"
And I enter "bob" in "username"
And I enter "secret" in "password"
And I click "Login"
Then I should see "Dashboard"Focus on Behavior, Not Implementation
聚焦行为,而非实现
- Describe what the system does, not how
- Use domain language stakeholders understand
- Keep scenarios short (3-5 steps recommended)
- One behavior per scenario
- 描述系统做什么,而非怎么做
- 使用利益相关者能理解的领域语言
- 保持场景简短(建议3-5个步骤)
- 每个场景对应一个行为
Background Usage
Background的使用
- Keep backgrounds short (≤4 lines)
- Use only for essential shared context
- Move implementation details to step definitions
- 保持Background简短(≤4行)
- 仅用于必要的共享上下文
- 将实现细节移至步骤定义中
Running Cucumber
运行Cucumber
bash
undefinedbash
undefinedRuby
Ruby
bundle exec cucumber
cucumber --tags "@smoke and not @wip"
cucumber features/login.feature:10 # specific line
bundle exec cucumber
cucumber --tags "@smoke and not @wip"
cucumber features/login.feature:10 # specific line
JavaScript
JavaScript
npx cucumber-js
npx cucumber-js --tags "@smoke"
npx cucumber-js
npx cucumber-js --tags "@smoke"
Java (with Maven)
Java (with Maven)
mvn test -Dcucumber.filter.tags="@smoke"
undefinedmvn test -Dcucumber.filter.tags="@smoke"
undefinedAdditional References
更多参考资料
For comprehensive details, see reference files:
- - Complete Gherkin language reference
references/gherkin-syntax.md - - Step definition patterns by language
references/step-definitions.md - - Hooks, configuration, and runners
references/hooks-config.md - - Anti-patterns and advanced patterns
references/best-practices.md
如需详细内容,请查看参考文件:
- - 完整Gherkin语言参考
references/gherkin-syntax.md - - 各语言的步骤定义模式
references/step-definitions.md - - 钩子、配置及运行器
references/hooks-config.md - - 反模式与进阶模式
references/best-practices.md