spring boot整合Cucumber(BDD)的方法
本文介绍了spring boot整合cucumber(bdd)的方法,分享给大家,具体如下:
1、新建一个springboot工程工程结构如下:
2、添加pom依赖
<?xml version="1.0" encoding="utf-8"?> <project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <groupid>com.chhliu</groupid> <artifactid>spring-boot-cucumber</artifactid> <version>0.0.1-snapshot</version> <packaging>jar</packaging> <name>spring-boot-cucumber</name> <description>demo project for spring boot and cucumber</description> <parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>1.5.6.release</version> <relativepath /> <!-- lookup parent from repository --> </parent> <properties> <cucumber.version>1.2.4</cucumber.version> <project.build.sourceencoding>utf-8</project.build.sourceencoding> <project.reporting.outputencoding>utf-8</project.reporting.outputencoding> <java.version>1.7</java.version> </properties> <dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <dependency> <groupid>info.cukes</groupid> <artifactid>cucumber-java</artifactid> <version>${cucumber.version}</version> </dependency> <dependency> <groupid>info.cukes</groupid> <artifactid>cucumber-core</artifactid> <version>${cucumber.version}</version> </dependency> <dependency> <groupid>info.cukes</groupid> <artifactid>cucumber-spring</artifactid> <version>${cucumber.version}</version> </dependency> <dependency> <groupid>info.cukes</groupid> <artifactid>cucumber-junit</artifactid> <version>${cucumber.version}</version> <exclusions> <exclusion> <groupid>junit</groupid> <artifactid>junit</artifactid> </exclusion> </exclusions> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-test</artifactid> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <plugin> <groupid>org.codehaus.mojo</groupid> <artifactid>exec-maven-plugin</artifactid> <configuration> <source>1.7</source> <target>1.7</target> </configuration> <executions> <execution> <phase>integration-test</phase> <goals> <goal>java</goal> </goals> <configuration> <classpathscope>test</classpathscope> <mainclass>com.chhliu.test.cucumbertest.java</mainclass> <arguments> <argument>--plugin</argument> <argument>pretty</argument> <argument>--glue</argument> <argument>src/test/resources/</argument> </arguments> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
2、编写service接口及其实现类
package com.chhliu.service; /** * 模拟登录 * @author chhliu * */ public interface userinfoservicei { boolean login(string username, string password, string confirmpassword); }
package com.chhliu.service; import org.springframework.stereotype.service; @service("userinfoservice") public class userinfoservice implements userinfoservicei{ public boolean login(string username, string password, string confirmpassword){ return (username.equals("chhliu") && password.equals("123456") && confirmpassword.equals("123456")); } }
3、编写feature文件
#language: zh-cn #"zh-cn": { # "but": "*|但是<", # "and": "*|而且<|并且<|同时<", # "then": "*|那么<", # "when": "*|当<", # "name": "chinese simplified", # "native": "简体中文", # "feature": "功能", # "background": "背景", # "scenario": "场景|剧本", # "scenario_outline": "场景大纲|剧本大纲", # "examples": "例子", # "given": "*|假如<|假设<|假定<" # } @bank 功能:假如我在银行取钱的时候,如果我登录成功并且输入的密码正确,那么会显示我的银行卡余额,假如余额为50万 场景:银行取钱 假如:我以"chhliu"登录 并且:输入的密码为"123456" 当:确认密码也为"123456"时 那么:显示银行卡余额为"500000"
4、编写测试类
package com.chhliu.test; import org.junit.runner.runwith; import cucumber.api.cucumberoptions; import cucumber.api.junit.cucumber; /** * @runwith(cucumber.class) 这是一个运行器 ,指用cucumber来运行测试 * @cucumberoptions中的features,用于指定我们项目中要运行的feature的目录 * @cucumberoptions中的format,用于指定我们项目中要运行时生成的报告,并指定之后可以在target目录中找到对应的测试报告 * @cucumberoptions中的glue,用于指定项目运行时查找实现step定义文件的目录 * * 在实际项目中,随着项目的进行,一个测试工程可能由多个feature文件组成,并且每个feature文件中可能也是由多个scenario组成。默认情况下, * 每次运行是运行所有feature中的所有scenario。这样可能导致正常情况下运行一次测试脚本,需要非常长的时间来等待测试结果。 * 但是实际过程中,测试用例是有优先级等区分的。比如smoketest、regressiontest等。或者有时候会有特别小部分的用例,比如等级是critical, * 这些用例需要长时间运行来监测系统是否没有白页或者页面404等现象。 * 所以我们必须区分开所有的scenario,可以使我们在启动测试脚本时,可以根据我们需要来运行哪些模块的scenaro。这时我们可以使用tags * 在cucumber里tag是直接在feature、scenari或scenario outline关键字前给feature或scenario添加任意数量的前缀为@的tags,多个tag用空格来分隔 * @author chhliu * */ @runwith(cucumber.class) @cucumberoptions(plugin = {"json:target/cucumber.json", "pretty"}, features = "src/test/resources") public class cucumbertest { }
5、运行测试类,并对测试输出的未定义步骤进行完善
package com.chhliu.test; import javax.annotation.resource; import org.junit.assert; import com.chhliu.service.userinfoservicei; import cucumber.api.java.zh_cn.假如; import cucumber.api.java.zh_cn.当; import cucumber.api.java.zh_cn.那么; public class cucumber集成spring { @resource(name="userinfoservice") private userinfoservicei service; private string username; private string password; private string confirmpassword; @假如("^:我以\"([^\"]*)\"登录$") public void 我以_登录(string arg1) throws throwable { this.username = arg1; } @假如("^:输入的密码为\"([^\"]*)\"$") public void 输入的密码为(string arg1) throws throwable { this.password = arg1; } @当("^:确认密码也为\"([^\"]*)\"时$") public void 确认密码也为_时(string arg1) throws throwable { this.confirmpassword = arg1; } @那么("^:显示银行卡余额为\"([^\"]*)\"$") public void 显示银行卡余额为(string arg1) throws throwable { boolean islogin = service.login(username, password, confirmpassword); if(islogin){ system.out.println("登录成功!查询余额如下:"+arg1); assert.assertequals("500000", arg1); } } }
6、在测试步骤上添加注解支持
@runwith(springjunit4classrunner.class) @contextconfiguration // 不加此注解,bean会注入不进去 @springboottest // 不加此注解会找不到bean public class cucumber集成spring{ }
7、测试结果
2 scenarios (2 passed)
11 steps (11 passed)
0m0.091s
8、整合注意点
spring boot与cucumber整合的时候,有个地方需要注意,因为spring boot提倡去xml化,所以传统方式下,cucumber会读取classpath下的cucumber.xml配置文件来初始化bean的方式,和spring整合后,就不能用这种方式了,需要使用@contextconfiguration注解来实现类的加载,如果是需要加载配置文件的方式的话,可以如下使用:
@contextconfiguration(locations = { "classpath:applicationcontext.xml" })
如果使用注解的方式来整合的话,使用如下:
@contextconfiguration(classes=springbootcucumberapplication.class)
或者直接
@contextconfiguration
特别注意:@contextconfiguration注解必加,否则会出现bean注入失败
下面,我们从源码来看下为什么会造成这种情况。
该部分涉及的代码都在cucumber-spring包下的springfactory类中,重点我们看下下面这个类:
public void start() {// cucumber测试启动方法 if (stepclasswithspringcontext != null) {// 如果使用了@contextconfiguration注解的话,此处不为null testcontextmanager = new cucumbertestcontextmanager(stepclasswithspringcontext); } else {// 否则stepclasswithspringcontext就为null,会进入下面这个分支 if (beanfactory == null) { beanfactory = createfallbackcontext();// 这个方法是我们要跟的重点 } } notifycontextmanagerabouttestclassstarted(); if (beanfactory == null || isnewcontextcreated()) { beanfactory = testcontextmanager.getbeanfactory(); for (class<?> stepclass : stepclasses) { registerstepclassbeandefinition(beanfactory, stepclass); } } gluecodecontext.instance.start(); }
我们在来跟下createfallbackcontext方法:
private configurablelistablebeanfactory createfallbackcontext() { configurableapplicationcontext applicationcontext; if (getclass().getclassloader().getresource("cucumber.xml") != null) {// 会先根据classpath下的cucumber.xml来初始化<span style="font-family:arial, helvetica, sans-serif;">configurableapplicationcontext</span> applicationcontext = new classpathxmlapplicationcontext("cucumber.xml"); } else {// 如果没有配置cucumber.xml的话,会new genericapplicationcontext applicationcontext = new genericapplicationcontext(); } applicationcontext.registershutdownhook(); configurablelistablebeanfactory beanfactory = applicationcontext.getbeanfactory(); beanfactory.registerscope(gluecodescope.name, new gluecodescope()); for (class<?> stepclass : stepclasses) { registerstepclassbeandefinition(beanfactory, stepclass); } return beanfactory; }
最后,来说下genericapplicationcontext这个类,该类会根据bean的type类型,然后newinstance实例,但是由于这个类中又注入了其他的类,而注入的类是无法通过new实例的方式来初始化的,所以最后就会注入失败,报空指针了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
spring-boot-2.0.3不一样系列之源码篇 - run方法(三)之createApplicationContext,绝对有值得你看的地方
-
Spring Boot Dubbo 构建分布式服务的方法
-
Spring Boot实现STOMP协议的WebSocket的方法步骤
-
spring boot整合Cucumber(BDD)的方法
-
十、Spring boot 简单优雅的整合 Swagger2
-
Spring Boot使用yml格式进行配置的方法
-
Spring-Data-JPA整合MySQL和配置的方法
-
spring boot 中设置默认网页的方法
-
Spring Boot Gradle发布war到tomcat的方法示例
-
spring boot整合hessian的示例