spring boot整合Cucumber(BDD)的方法

网友投稿 298 2023-02-09


spring boot整合Cucumber(BDD)的方法

本文介绍了spring boot整合Cucumber(BDD)的方法,分享给大家,具体如下:

1、新建一个springboot工程工程结构如下:

2、添加pom依赖

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

com.chhliu

spring-boot-cucumber

0.0.1-SNAPSHOT

jar

spring-boot-cucumber

Demo project for Spring Boot and Cucumber

org.springframework.boot

spring-boot-starter-parent

1.5.6.RELEASE

1.2.4

UTF-8

UTF-8

1.7

org.springframework.boot

spring-boot-starter-web

info.cukes

cucumber-java

${cucumber.version}

info.cukes

cucumber-core

${cucumber.version}

info.cukes

cucumber-spring

${cucumber.version}

info.cukes

cucumber-junit

${cucumber.version}

junit

junit

org.springframework.boot

spring-boot-starter-test

test

org.springframework.boot

spring-boot-maven-plugin

1.7

1.7

org.codehaus.mojo

exec-maven-plugin

1.7

1.7

integration-test

java

test

com.chhliu.test.CucumberTest.java

--plugin

pretty

--glue

src/test/resources/

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

com.chhliu

spring-boot-cucumber

0.0.1-SNAPSHOT

jar

spring-boot-cucumber

Demo project for Spring Boot and Cucumber

org.springframework.boot

spring-boot-starter-parent

1.5.6.RELEASE

1.2.4

UTF-8

UTF-8

1.7

org.springframework.boot

spring-boot-starter-web

info.cukes

cucumber-java

${cucumber.version}

info.cukes

cucumber-core

${cucumber.version}

info.cukes

cucumber-spring

${cucumber.version}

info.cukes

cucumber-junit

${cucumber.version}

junit

junit

org.springframework.boot

spring-boot-starter-test

test

org.springframework.boot

spring-boot-maven-plugin

1.7

1.7

org.codehaus.mojo

exec-maven-plugin

1.7

1.7

integration-test

java

test

com.chhliu.test.CucumberTest.java

--plugin

pretty

--glue

src/test/resources/

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测YXIiXdlLSQ试启动方法

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来初始化ConfigurableApplicationContext

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实例的方式来初始化的,所以最后就会注入失败,报空指针了。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java程序员需要掌握的英语词组
下一篇:免费接口api管理平台(api接口管理系统)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~