简介
1.创建Feature特征文件
Cucumber的用例场景在特征文件.feature
中定义,这些文件存储在 src/test/resources
目录(或子目录)中。
那么下面我们创建一个示例的文件 src/test/resources/hellocucumber/Demo.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:
后面的内用为整个文件的描述文档,当cucumber运行时这段文字不会被执行
第四行Scenario: Sunday is not Friday
Scenario是一个关键字,表示这是一个具体示例,说明了该场景的作用是什么
最后三行以关键字 Given,When和Then 开头的语句,这个是cucumber要执行的部分。
- cucumber关键字
关键字 | 中文输出 |
---|---|
Feature | ”功能“ |
Rule (as of Gherkin 6) | “Rule” |
Example (or Scenario) | “例子” 或者 “场景” (在使用中多使用Scenario),“剧本” |
given | "* ",“假如”,“假设”,“假定” |
when | "* " “当” |
then | "* ", “那么” |
and | "* ",“而且”,“并且”,“同时” |
but | "* ", “但是” |
Background | ”背景“ |
Scenario Outline (or Scenario Template) | “场景大纲”,“剧本大纲” |
Examples | “例子” |
在使用其他语言作为关键字时 需要在文件开头添加#cucumber --i18n <language_code>
字样来让cucumber识别对应的语言,例如我么使用中文时,需要在文件开头添加 #cucumber --i18n zh-CN
不然cucumber无法认出中文,如果需要查看cucumber支持哪些语言可以使用cucumber --i18n help
进行查询 当然你也可以在cucumber关键字列表中查看对应的关键字
2.定义Step步骤文件
我使用的是 Intellij IDEA 下生成 Steps 文件,在编写 feature 文件的过程中,IDEA 会提示目前文件中哪些步骤(steps)是没有对应的 Java step 文件,如下图所示,Intellij IDEA 会以黄色的小灯泡这个提示标志来进行提醒:
大家只需要按照如下的步骤来生成对应的 Steps 文件即可:
点击该提示图标,并从弹出的菜单项中选择“Create Step Definition”或者“Create All Steps Definition”;
在弹出的“Create New Step Definition File”模式窗口中填写文件名称、实现语言以及文件位置等信息即可;
重复步骤 1 和 2 直到所有的 step 都生成对应的 Java step definition 即可,以下为生成的steps文件
3.步骤的验证
我们将上述步骤生成的steps文件中内容修改为
@Given("today is Sunday")
public void today_is_Sunday() {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
@When("I ask whether it's Friday yet")
public void i_ask_whether_it_s_Friday_yet() {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
@Then("I should be told {string}")
public void i_should_be_told(String string) {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
让我们再次运行cucumber项目试试会有什么反应呢?
这里我们使用mvn test来执行cucumber的任务,得到以下结果
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running hellocucumber.RunCucumberTest
@DemoTest
Feature: Is it Friday yet?
Everybody wants to know when it's Friday
@DemoTest @all
Scenario: Sunday isn't Friday # hellocucumber/Demo.feature:6
Given today is Sunday # HelloDemo.today_is_Sunday()
cucumber.api.PendingException: TODO: implement me
at hellocucumber.HelloDemo.today_is_Sunday(HelloDemo.java:15)
at ✽.today is Sunday(classpath:hellocucumber/Demo.feature:7)
When I ask whether it's Friday yet # HelloDemo.i_ask_whether_it_s_Friday_yet()
Then I should be told "Nope" # HelloDemo.i_should_be_told(String)
Tests run: 1, Failures: 0, Errors: 0, Skipped: 1, Time elapsed: 0.384 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 1
这里的执行结果说明cucumber找到我们定义的steps,并把它标记为Skipped
,这说明我们可以使用cucumber进行一些想要进行的事情
你可能会好奇,如果我的用例执行失败了之后我的报告会有什么样的显示呢?
我们将以下代码复制进我们定义的steps文件中
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import cucumber.api.PendingException;
import static org.junit.Assert.assertEquals;
class IsItFriday {
static String isItFriday(String today) {
return null;
}
}
public class HelloDemo {
private String today;
private String actualAnswer;
@Given("today is Sunday")
public void today_is_Sunday() {
today = "Sunday";
}
@When("I ask whether it's Friday yet")
public void i_ask_whether_it_s_Friday_yet() {
actualAnswer = IsItFriday.isItFriday(today);
}
@Then("I should be told {string}")
public void i_should_be_told(String expectedAnswer) {
assertEquals(expectedAnswer, actualAnswer);
}
}
让我们再次执行mvn test 运行,得到以下报告
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running hellocucumber.RunCucumberTest
@DemoTest
Feature: Is it Friday yet?
Everybody wants to know when it's Friday
@DemoTest @all
Scenario: Sunday isn't Friday # hellocucumber/Demo.feature:6
Given today is Sunday # HelloDemo.today_is_Sunday()
When I ask whether it's Friday yet # HelloDemo.i_ask_whether_it_s_Friday_yet()
Then I should be told "Nope" # HelloDemo.i_should_be_told(String)
java.lang.AssertionError: expected:<Nope> but was:<null>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
at hellocucumber.HelloDemo.i_should_be_told(HelloDemo.java:33)
at ✽.I should be told "Nope"(classpath:hellocucumber/Demo.feature:9)
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.364 sec <<< FAILURE!
Sunday isn't Friday(Is it Friday yet?) Time elapsed: 0.023 sec <<< FAILURE!
java.lang.AssertionError: expected:<Nope> but was:<null>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
at hellocucumber.HelloDemo.i_should_be_told(HelloDemo.java:33)
at ✽.I should be told "Nope"(classpath:hellocucumber/Demo.feature:9)
Results :
Failed tests: Sunday isn't Friday(Is it Friday yet?): expected:<Nope> but was:<null>
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
从这个报告我们可以看到cucumber用例执行失败后的样子,我们可以从这里面看出来前两步运行成功了,但是最后一步没有成功,原因是 expected:<Nope> but was:<null>
所以我们将上述代码中的 reurn null
修改为return "Nope"
然后再次运行mvn test
class IsItFriday {
static String isItFriday(String today) {
return "Nope";
}
}
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running hellocucumber.RunCucumberTest
@DemoTest
Feature: Is it Friday yet?
Everybody wants to know when it's Friday
@DemoTest @all
Scenario: Sunday isn't Friday # hellocucumber/Demo.feature:6
Given today is Sunday # HelloDemo.today_is_Sunday()
When I ask whether it's Friday yet # HelloDemo.i_ask_whether_it_s_Friday_yet()
Then I should be told "Nope" # HelloDemo.i_should_be_told(String)
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.366 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
从报告中我们可以看出cucumber执行成功了,这些场景并不能满足我们日常的测试任务,我们在测试中需要使用到更多的变量来让我们的测试用例更加的完善,为了让我们的用例有更加多的可能性,我们可以使用cucumber中的Scenario Outline
和Examples
进行关联让我们的用例有更多的变化
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 |
将生成的steps文件修改为
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import cucumber.api.PendingException;
import static org.junit.Assert.assertEquals;
class IsItFriday {
static String isItFriday(String today) {
return "Friday".equals(today) ? "TGIF" : "Nope";
}
}
public class HelloDemo {
private String today;
private String actualAnswer;
@Given("today is {string}")
public void today_is(String today) {
this.today = today;
}
@When("I ask whether it's Friday yet")
public void i_ask_whether_it_s_Friday_yet() {
actualAnswer = IsItFriday.isItFriday(today);
}
@Then("I should be told {string}")
public void i_should_be_told(String expectedAnswer) {
assertEquals(expectedAnswer, actualAnswer);
}
}
再次运行cucumber得到以下报告
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running hellocucumber.RunCucumberTest
@DemoTest
Feature: Is it Friday yet?
Everybody wants to know when it's Friday
@DemoTest @all
Scenario: Sunday isn't Friday # hellocucumber/Demo.feature:6
Given today is "<day>" # HelloDemo.today_is(String)
When I ask whether it's Friday yet # HelloDemo.i_ask_whether_it_s_Friday_yet()
Then I should be told "Nope" # HelloDemo.i_should_be_told(String)
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.389 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
4.测试运行
Cucumber测试用例有不光可以使用mvn test
启动还有两种启动方式,debug mode下,两种方式都可以对Steps 文件代码进行debug:
通过Junit启动
我们要使用Junit来启动cucumber的话需要确定依赖 cucumber-junit
是否存在
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
cucumber基于JUnit4。如果您使用的是JUnit 5,请记住也包括junit-vintage-engine依赖项
我们发现当我们创建cucumber项目时,cucumber会自动为我们生成一个RunCucumberTest.java
的文件
package hellocucumber;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;
@RunWith(Cucumber.class)
@CucumberOptions(plugin = {"pretty"})
public class RunCucumberTest {
}
这将会执行同一程序包中的所有执行方案
@CucumberOptions
还提供了许多额外的配置,例如你想告诉cucumber使用两个格式化插件pretty
和html
这可以run文件中这样指定:
@RunWith(Cucumber.class)
@CucumberOptions(plugin = {"pretty", "html:target/cucumber"})
public class RunCucumberTest {
}
更多的配置信息可以再 官方文档中查看
通过IDEA启动
如果你想通过IDEA直接运行的话你可以在对应的feature文件中选择scenario然后右键选择运行,这样就会运行指定的scenario
定制化运行
在日常的测试中我们会生成很多的feature文件,每次执行的时候我们不能去一个个执行或者全部运行,我们只想运行我们需要的部分,所以在cucumber还支持tag来区分运行的场景,而且一个场景可以拥有多个tag,这样在运行时就会更加方便的让我们运行指定的文件了,例如下面代码
@RunWith(Cucumber.class)
@CucumberOptions(
plugin = {
"pretty",
"html:target/html-report/",
"json:target/json-report/run.json"
},
features = {
"classpath:hellocucumber"
},
glue = {
"hellocucumber"
},
monochrome=true,
tags = {
"@all"
}
)
public class RunCucumberTest {
}
指定 Cucumber 运行结果报告
Cucumber 本身支持多种报告格式以适用于不同环境下调用的报告输出:
- pretty :用于在命令行环境下执行 Cucumber 测试用例所产生的报告,如果您的 console 支持,pretty 形式的报告还可以按照颜色显示不同的运行结果;如下图所示的例子分别显示了用例执行通过和用例没有 Steps definitions 的输出报告:
- JSON 格式报告示例
[
{
"line": 3,
"elements": [
{
"start_timestamp": "2020-01-09T08:41:07.634Z",
"line": 6,
"name": "Sunday isn\u0027t Friday",
"description": "",
"id": "is-it-friday-yet?;sunday-isn-t-friday",
"type": "scenario",
"keyword": "Scenario",
"steps": [
{
"result": {
"duration": 1950678,
"status": "passed"
},
"line": 7,
"name": "today is \"\u003cday\u003e\"",
"match": {
"arguments": [
{
"val": "\"\u003cday\u003e\"",
"offset": 9
}
],
"location": "HelloDemo.today_is(String)"
},
"keyword": "Given "
},
{
"result": {
"duration": 789329,
"status": "passed"
},
"line": 8,
"name": "I ask whether it\u0027s Friday yet",
"match": {
"location": "HelloDemo.i_ask_whether_it_s_Friday_yet()"
},
"keyword": "When "
},
{
"result": {
"duration": 2408473,
"status": "passed"
},
"line": 9,
"name": "I should be told \"Nope\"",
"match": {
"arguments": [
{
"val": "\"Nope\"",
"offset": 17
}
],
"location": "HelloDemo.i_should_be_told(String)"
},
"keyword": "Then "
}
],
"tags": [
{
"name": "@DemoTest"
},
{
"name": "@all"
}
]
}
],
"name": "Is it Friday yet?",
"description": " Everybody wants to know when it\u0027s Friday",
"id": "is-it-friday-yet?",
"keyword": "Feature",
"uri": "classpath:hellocucumber/Demo.feature",
"tags": [
{
"name": "@DemoTest",
"type": "Tag",
"location": {
"line": 2,
"column": 1
}
}
]
}
]
- 简单的 HTML 格式报告示例