10分钟搭建Cucumber框架

本文最后更新于:2024年11月22日 下午 04:42:52

开始之前

在我们开始之前,需要以下内容:

  • Java SE
  • 构建工具。此处选择:
    • Maven - 版本3.3.1或更高
    • IntelliJ IDEA
    • IntelliJ IDEA Cucumber for Java 插件

首先使用cucumber-archetype Maven插件创建一个空的Cucumber项目,在要创建项目的目录下打开本地Terminal,并运行以下命令:

1
mvn archetype:generate "-DarchetypeGroupId=io.cucumber" "-DarchetypeArtifactId=cucumber-archetype" "-DarchetypeVersion=7.15.0" "-DgroupId=com.shinyruo"  "-DartifactId=hellocucumber" "-Dpackage=hellocucumber" "-Dversion=1.0.0-SNAPSHOT"    "-DinteractiveMode=false"如果你本地没有这个插件的话,这个命令需要运行一会儿,

如果本地没有这个插件,Maven会自动下载

1
2
3
4
[INFO] Project created from Archetype in dir: <directory where you created the project>/cucumber
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

在IntelliJ IDEA中打开项目,运行Cucumber试试:

1
mvn test

应该会看到类似以下的结果:

1
2
3
4
5
6
7
8
9
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.141 s -- in hellocucumber.RunCucumberTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Cucumber此处运行了example.feature这个文件中给出的示例场景(Scenario)。

写一个场景(Scenario)

在Cucumber中进行行为驱动开发时,我们使用具体的示例来指定软件应该做什么。场景在生成代码之前编写。它们开始作为可执行规范。随着生成代码的出现,场景将扮演实时文档和自动化测试的角色。

在Cucumber中,一个示例被称为场景(Scenario)。场景定义在.feature文件中,这些文件默认存储在src/test/resources/hellocucumber目录(或子目录)中,当然,根据项目的需要,我们可以更改这个配置,在指定的目录下存储对应的.feature文件。比如在这个项目中,我们给RunCucumberTest加上这个注解@ConfigurationParameter(key = FEATURES_PROPERTY_NAME, value = "src/test/resources/features")就把这个目录更改为了src/test/resources/features这个目录(或子目录)。

接下来我们通过一个例子来表明应该如何写一个具体的场景。

创建一个src/test/resources/features/is_it_friday_yet.feature文件,内容如下:

1
2
3
4
5
6
7
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 isn’t Friday是一个场景,它是一个具体的示例,说明在这里软件所处的状态,或者业务场景。

以Given,When和Then开头的最后三行是我们场景的步骤。这是Cucumber将执行的内容。

查看报告中的未定义场景

现在我们有了一个场景,我们可以要求Cucumber执行它。

1
mvn test

Cucumber告诉我们有一个未定义的场景和三个未定义的步骤。它还建议一些代码片段,我们可以用这些代码片段来定义这些步骤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
Scenario: Sunday isn't Friday        # src/test/resources/features/is_it_friday_yet.feature:4
Given today is Sunday
When I ask whether it's Friday yet
Then I should be told "Nope"
[ERROR] Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.142 s <<< FAILURE! -- in hellocucumber.RunCucumberTest
[ERROR] Is it Friday yet?.Sunday isn't Friday -- Time elapsed: 0.024 s <<< ERROR!
io.cucumber.junit.platform.engine.UndefinedStepException:
The step 'today is Sunday' and 2 other step(s) are undefined.
You can implement these steps using the snippet(s) below:

@Given("today is Sunday")
public void today_is_sunday() {
// Write code here that turns the phrase above into concrete actions
throw new io.cucumber.java.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 io.cucumber.java.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 io.cucumber.java.PendingException();
}

at io.cucumber.core.runtime.TestCaseResultObserver.assertTestCasePassed(TestCaseResultObserver.java:69)
at io.cucumber.junit.platform.engine.TestCaseResultObserver.assertTestCasePassed(TestCaseResultObserver.java:22)
at io.cucumber.junit.platform.engine.CucumberEngineExecutionContext.lambda$runTestCase$4(CucumberEngineExecutionContext.java:114)
at io.cucumber.core.runtime.CucumberExecutionContext.lambda$runTestCase$5(CucumberExecutionContext.java:137)
at io.cucumber.core.runtime.RethrowingThrowableCollector.executeAndThrow(RethrowingThrowableCollector.java:23)
at io.cucumber.core.runtime.CucumberExecutionContext.runTestCase(CucumberExecutionContext.java:137)
at io.cucumber.junit.platform.engine.CucumberEngineExecutionContext.runTestCase(CucumberEngineExecutionContext.java:109)
at io.cucumber.junit.platform.engine.NodeDescriptor$PickleDescriptor.execute(NodeDescriptor.java:168)
at io.cucumber.junit.platform.engine.NodeDescriptor$PickleDescriptor.execute(NodeDescriptor.java:90)
at java.util.ArrayList.forEach(ArrayList.java:1259)
at java.util.ArrayList.forEach(ArrayList.java:1259)

[INFO]
[INFO] Results:
[INFO]
[ERROR] Errors:
[ERROR] The step 'today is Sunday' and 2 other step(s) are undefined.
You can implement these steps using the snippet(s) below:

@Given("today is Sunday")
public void today_is_sunday() {
// Write code here that turns the phrase above into concrete actions
throw new io.cucumber.java.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 io.cucumber.java.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 io.cucumber.java.PendingException();
}

复制每个未定义步骤的三个代码片段,并将它们粘贴到src/test/java/hellocucumber/stepdefs/common/Friday.java中。

再次运行Cucumber。这次输出有点不同:

1
2
3
4
[ERROR] Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.107 s <<< FAILURE! -- in hellocucumber.RunCucumberTest
[ERROR] Is it Friday yet?.Sunday isn't Friday -- Time elapsed: 0.007 s <<< ERROR!
io.cucumber.java.PendingException: TODO: implement me
at hellocucumber.stepdefs.common.Friday.today_is_sunday(Friday.java:9)

Cucumber找到了我们的步骤定义并执行了它们。它们当前标记为挂起,这意味着我们需要使它们做一些有用的事情,也就是对这些step进行实现。

查看报告中的失败/通过场景

下一步是按步骤定义中的注释所示做一些事情:

“// Write code here that turns the phrase above into concrete actions”

将步骤定义代码src/test/java/com/shinyruo/hellocucumber/stepdefs/common/Friday.java更改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.shinyruo.hellocucumber.stepdefs.common;

import io.cucumber.java.en.*;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class Friday {
private String today;
private String actualAnswer;

static String isItFriday(String today) {
return null;
}

@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(today);
}

@Then("I should be told {string}")
public void i_should_be_told(String expectedAnswer) {
assertEquals(expectedAnswer, actualAnswer);
}
}

再次运行Cucumber:

1
2
3
4
[ERROR] Is it Friday yet?.Sunday isn't Friday -- Time elapsed: 0.009 s <<< FAILURE!
org.opentest4j.AssertionFailedError: expected: <Nope> but was: <null>
at com.shinyruo.hellocucumber.stepdefs.common.Friday.i_should_be_told(Friday.java:26)
at ?.I should be told "Nope"

前两个步骤通过了,但是最后一个步骤失败了。很明显,这是因为我们的方法中返回了null,我们把它改成Nope:

1
2
3
static String isItFriday(String today) {
return "Nope";
}

再次运行Cucumber:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[INFO] Running com.shinyruo.hellocucumber.RunCucumberTest

Scenario: The example # src/test/resources/features/example.feature:3
Given an example scenario # com.shinyruo.hellocucumber.stepdefs.common.StepDefinitions.anExampleScenario()
When all step definitions are implemented # com.shinyruo.hellocucumber.stepdefs.common.StepDefinitions.allStepDefinitionsAreImplemented()
Then the scenario passes # com.shinyruo.hellocucumber.stepdefs.common.StepDefinitions.theScenarioPasses()

Scenario: Sunday isn't Friday # src/test/resources/features/is_it_friday_yet.feature:4
Given today is Sunday # com.shinyruo.hellocucumber.stepdefs.common.Friday.today_is_Sunday()
When I ask whether it's Friday yet # com.shinyruo.hellocucumber.stepdefs.common.Friday.i_ask_whether_it_s_Friday_yet()
Then I should be told "Nope" # com.shinyruo.hellocucumber.stepdefs.common.Friday.i_should_be_told(java.lang.String)
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.100 s -- in com.shinyruo.hellocucumber.RunCucumberTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

现在,我们的用例就都是通过状态了。

总结

总之,我们现在有了一个非常简陋的cucumber框架,更复杂的场景以及与其他测试工具的集成我们可以后边逐步实现。

Demo Repo


10分钟搭建Cucumber框架
https://douyushinyruo.github.io/shinyruotechtips/2024/01/a9e472a14e25/
作者
DouyuShinyruo
发布于
2024年1月24日
许可协议