您好,登錄后才能下訂單哦!
本文介紹了spring boot整合Cucumber(BDD)的方法,分享給大家,具體如下:
1、新建一個springboot工程工程結(jié)構(gòu)如下:
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接口及其實現(xiàn)類
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": "*|當(dāng)<", # "name": "Chinese simplified", # "native": "簡體中文", # "feature": "功能", # "background": "背景", # "scenario": "場景|劇本", # "scenario_outline": "場景大綱|劇本大綱", # "examples": "例子", # "given": "*|假如<|假設(shè)<|假定<" # } @bank 功能:假如我在銀行取錢的時候,如果我登錄成功并且輸入的密碼正確,那么會顯示我的銀行卡余額,假如余額為50萬 場景:銀行取錢 假如:我以"chhliu"登錄 并且:輸入的密碼為"123456" 當(dāng):確認(rèn)密碼也為"123456"時 那么:顯示銀行卡余額為"500000"
4、編寫測試類
package com.chhliu.test; import org.junit.runner.RunWith; import cucumber.api.CucumberOptions; import cucumber.api.junit.Cucumber; /** * @RunWith(Cucumber.class) 這是一個運(yùn)行器 ,指用Cucumber來運(yùn)行測試 * @CucumberOptions中的features,用于指定我們項目中要運(yùn)行的feature的目錄 * @CucumberOptions中的format,用于指定我們項目中要運(yùn)行時生成的報告,并指定之后可以在target目錄中找到對應(yīng)的測試報告 * @CucumberOptions中的glue,用于指定項目運(yùn)行時查找實現(xiàn)step定義文件的目錄 * * 在實際項目中,隨著項目的進(jìn)行,一個測試工程可能由多個feature文件組成,并且每個feature文件中可能也是由多個scenario組成。默認(rèn)情況下, * 每次運(yùn)行是運(yùn)行所有feature中的所有scenario。這樣可能導(dǎo)致正常情況下運(yùn)行一次測試腳本,需要非常長的時間來等待測試結(jié)果。 * 但是實際過程中,測試用例是有優(yōu)先級等區(qū)分的。比如smokeTest、regressionTest等?;蛘哂袝r候會有特別小部分的用例,比如等級是critical, * 這些用例需要長時間運(yùn)行來監(jiān)測系統(tǒng)是否沒有白頁或者頁面404等現(xiàn)象。 * 所以我們必須區(qū)分開所有的scenario,可以使我們在啟動測試腳本時,可以根據(jù)我們需要來運(yùn)行哪些模塊的scenaro。這時我們可以使用Tags * 在Cucumber里Tag是直接在Feature、Scenari或Scenario Outline關(guān)鍵字前給feature或scenario添加任意數(shù)量的前綴為@的tags,多個tag用空格來分隔 * @author chhliu * */ @RunWith(Cucumber.class) @CucumberOptions(plugin = {"json:target/cucumber.json", "pretty"}, features = "src/test/resources") public class CucumberTest { }
5、運(yùn)行測試類,并對測試輸出的未定義步驟進(jìn)行完善
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.當(dāng); 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; } @當(dāng)("^:確認(rèn)密碼也為\"([^\"]*)\"時$") public void 確認(rèn)密碼也為_時(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會注入不進(jìn)去 @SpringBootTest // 不加此注解會找不到bean public class Cucumber集成spring{ }
7、測試結(jié)果
2 Scenarios (2 passed)
11 Steps (11 passed)
0m0.091s
8、整合注意點(diǎn)
spring boot與Cucumber整合的時候,有個地方需要注意,因為spring boot提倡去xml化,所以傳統(tǒng)方式下,Cucumber會讀取classpath下的cucumber.xml配置文件來初始化bean的方式,和spring整合后,就不能用這種方式了,需要使用@ContextConfiguration注解來實現(xiàn)類的加載,如果是需要加載配置文件的方式的話,可以如下使用:
@ContextConfiguration(locations = { "classpath:applicationContext.xml" })
如果使用注解的方式來整合的話,使用如下:
@ContextConfiguration(classes=SpringBootCucumberApplication.class)
或者直接
@ContextConfiguration
特別注意:@ContextConfiguration注解必加,否則會出現(xiàn)bean注入失敗
下面,我們從源碼來看下為什么會造成這種情況。
該部分涉及的代碼都在cucumber-spring包下的SpringFactory類中,重點(diǎn)我們看下下面這個類:
public void start() {// cucumber測試啟動方法 if (stepClassWithSpringContext != null) {// 如果使用了@ContextConfiguration注解的話,此處不為null testContextManager = new CucumberTestContextManager(stepClassWithSpringContext); } else {// 否則stepClassWithSpringContext就為null,會進(jìn)入下面這個分支 if (beanFactory == null) { beanFactory = createFallbackContext();// 這個方法是我們要跟的重點(diǎn) } } 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) {// 會先根據(jù)classpath下的cucumber.xml來初始化<span >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這個類,該類會根據(jù)Bean的Type類型,然后newInstance實例,但是由于這個類中又注入了其他的類,而注入的類是無法通過new實例的方式來初始化的,所以最后就會注入失敗,報空指針了。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。