【本文目标】
本文主要有三个demo:
- 使用Java运行Cucumber。
- Cucumber与Junit4的集成。
- Cucumber与Spring Boot 2.5.7 + Junit5的集成。
1. Cucumber介绍
官网:cucumber.io/
Cucumber是一个BDD的测试框架,BDD:Behavior-Driven Development(行为驱动测试),即以功能使用者的角度,编写需求场景。
Cucumber并不是java独有的,而是支持很多种语言,如js, ruby, c++, go等等。总体上来说,它是一种测试思想(BDD)的实现。
一个系统 --> 很多个feature(即功能) --> 基于每个功能编写的测试。
比如我们写了一个功能,叫验证今天是不是星期五。那么我们在编写Cucumber 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"
可以看到Cucumber的feature定义文件,由若干个关键字组成,如Feature, Scenerio, Given, When, Then...等等。这些关键字是Gherkin语法,如同其它语言的语法一样,都是有特定的规则的,只需要在定义的时候遵循即可。
另外,我们也可以看到这样的feature定义,就很直白,它建立起开发人员与非技术人员(如产品经理)之间的桥梁,即可以清楚的通过behavior来驱动功能上的测试。我想,这就是cucumber流行起来的原因之一吧。
2. Cucumber在IDE中的插件
可以预先安装下Cucumber的插件:Cucumber for Java,这个插件可以识别feature中的语法。
3. 与Java的集成
可以通过一个具体的例子来看看Cucumber是如何运行的。
首先是依赖,主要依赖的包有cucumber-java,这个包主要是可以把cucumber的feature文件中的Gherkin语法转成java认识的。
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>7.6.0</version>
</dependency>
参考官网中的例子:cucumber.io/docs/guides…
在resources下新建目录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文件,我们需要写java代码来实现上述的feature:
public class Stepdefs {
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) {
System.out.println(actualAnswer.equals(expectedAnswer) ? "Pass" : "Failed");
}
}
【运行feature文件】:
【运行结果】:
4. 与JUnit4集成
JUnit分版本4和5,这里介绍的是Cucumber与4的集成。
在第3章介绍的Cucumber hello world例子中,我们需要手动运行feature文件,但实际项目中,我们需要在CI阶段(通常是在Jenkins中通过maven去编绎在git中的代码),而在mvn package的过程中,我们希望maven不仅编译运行单元测试,还要运行cucumber相关的测试。
4.1 首先是依赖介绍
除了上述的cucumber-java包外,还需要引入cucumber-junit的依赖:
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>7.6.0</version>
<scope>test</scope>
</dependency>
cucumber-junit依赖默认会引入junit-4.13.2,由此可以看出,这里与junit版本4集成的:
4.2 Junit文件的编写
新建java类:CucumberIT.java
@RunWith就是Junit4中最常见的运行器(Junit5用的是@ExtendWith)。@RunWith的参数Cucumber.class就是Junit的入口类,类似Spring中的SpringRunner.java)。@CucumberOptions可以指定一些Cucumber的配置类,这里指定了feature文件所在的路径。
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;
@RunWith(Cucumber.class)
@CucumberOptions(features="src/main/resources/features")
public class CucumberIT {
}
建好文件后,我们可以运行这个文件,可以看到is_it_friday_yet.feature会被执行。
4.3 集成到mvn test goal中
除了jar包的引入和编写Junit入口文件,我们还需要告诉maven在test阶段,还需要运行上述的Junit入口类——CucumberIT.java。
默认情况下,我们运行mvn test会执行plugin=maven-surefire-plugin,这里我们需要显式的引入这个插件,并且额外加上上述的junit入口类。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<includes>
**/CucumberIT*.java
</includes>
</configuration>
</plugin>
</plugins>
</build>
5. 与Spring Boot + JUnit5 集成
参考:
- 文章:Example of creating Cucumber based BDD tests using JUnit5 and Spring Dependency Injection
- 上述文章中的 Github
网上很多Cucumber的例子,但很多都是与Junit4的集成(我在第4章介绍了)。所以本章介绍Cucumber与Spring Boot + Junit5的集成。
5.1 依赖
- 首先是
Spring boot相关的依赖:web starter和test starter。 - 接着就是
Cucumber和Junit5相关的依赖,使用的是dependencyManagement,更为方便的管理。 - 依赖的
cucumber-junit-platform-engine,则是cucumber与junit5的依赖,而第4章与junit4的集成,用的是cucumber-junit。
<!-- 引用的是Spring Boot 2.5.7 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.7</version>
</parent>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-bom</artifactId>
<version>7.6.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.9.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Spring相关的依赖:引用的是web starter以及test starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Cucumber 相关 -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-spring</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<scope>test</scope>
</dependency>
<!-- JUnit5 相关 -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
5.2 Spring boot相关的类
- 首先创建
Spring boot启动类,使用注解:@SpringBootApplication。主要为了使用@SpringBootTest的时候,可以自动引用该启动类,以便使用@ComponentScan。 - 其次创建
UserService,使用注解@Service。主要是为了在BDD的Steps类中测试使用@Autowired来引用Spring bean。
5.3 Cucumber相关的资源
这个和第3章一样:
- /src/main/resources/festures下:
is_it_friday_yet.feature Stepdefs.java类,在这个类中,我们可以使用@Autowired来引入上述的UserService,以便可以测试Spring context是否生效!!!
5.4 新建测试相关类
首先是新建与Spring集成的类:CucumberBootstrap.java
@CucumberContextConfiguration注解告诉Cucumber需要使用Spring的context configuration。@SpringBootTest,在###5.2中有介绍。
@CucumberContextConfiguration
@SpringBootTest
public class CucumberBootstrap {
}
另外一个就是重要的类就是Cucumber与Junit5的集成的类,主要是通过这个类,Junit5可以找到Cucumber的features的文件,然后执行bdd测试。
这里如果使用**Test结尾,就不需要像第4章一样,在maven插件maven-surefire-plugin中显式的引用这个类,因为插件默认会include以Test结尾的文件。
有些文章中写Cucumber与Junit5的集成,使用的注解还是@RunWith(Cucumber.class),那么这种就还是与Junit4的集成了。
还有些文章中会介绍使用注解@Cucumber,该注解位于包io.cucumber.junit.platform.engine.Cucumber中,截至我写文章的时间,这个类已经被mark成@Deprecated了,点进去看,会推荐使用@Suite。这就是为啥下述使用@Suite,而不是@Cucumber的原因。
@Suite
@SelectClasspathResource("features")
public class CucumberTest {
}
5.5 运行测试
可以通过运行CucumberTest.java来跑Cucumber的features文件,也可使用mvn test来跑全部的features文件。
结果: