API 测试框架:cucumber+springBoot+restAssured
1)项目结构如下:
2) pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demoForCucumber</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demoForCucumber</name> <description>Demo project for Spring Boot</description> <properties> <cucumber.version>2.3.1</cucumber.version> <cucumber-reporting.version>3.14.0</cucumber-reporting.version> <maven.compiler.version>3.7.0</maven.compiler.version> <java.compiler.version>1.8</java.compiler.version> <rest-assured.version>4.2.0</rest-assured.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> </dependency> <!--handle cucumber framework--> <!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java8 --> <dependency> <groupId>io.cucumber</groupId> <artifactId>cucumber-java8</artifactId> <version>${cucumber.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-spring --> <dependency> <groupId>io.cucumber</groupId> <artifactId>cucumber-spring</artifactId> <version>${cucumber.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-junit --> <dependency> <groupId>io.cucumber</groupId> <artifactId>cucumber-junit</artifactId> <version>${cucumber.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/net.masterthought/cucumber-reporting --> <dependency> <groupId>net.masterthought</groupId> <artifactId>cucumber-reporting</artifactId> <version>${cucumber-reporting.version}</version> </dependency> <!--handle setter and getter--> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.22</version> <optional>true</optional> </dependency> <!--handle rest-assured test API --> <!-- https://mvnrepository.com/artifact/io.rest-assured/rest-assured --> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <version>${rest-assured.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/io.rest-assured/json-path --> <dependency> <groupId>io.rest-assured</groupId> <artifactId>json-path</artifactId> <version>${rest-assured.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
2) application.yaml
只是简单配置了一个URL 作为示例
#file: noinspection undefined spring: url: weather: https://qqlykm.cn/api/free/weather
3)URLConfig.java
引用lombok处理getter and setter, 用于获取配置在application.yaml中的配置
(notice: 使用lombok的时候,除了加入依赖包,还要记得在idea中安装 lombok 插件)
1 package com.example.demoForCucumber.config; 2 3 4 import org.springframework.beans.factory.annotation.Value; 5 import org.springframework.context.annotation.Configuration; 6 import lombok.Getter; 7 import lombok.Setter; 8 /* 9 * @author Helen Lee 10 * @create 2022/12/23 11 * @description 12 */ 13 @Getter 14 @Setter 15 @Configuration 16 public class URLConfig { 17 @Value("${spring.url.weather}") 18 private String urlWeather; 19 }
4)FreeWeatherAPIBase.java
使用rest-assured 处理 API call
package com.example.demoForCucumber.baseAPIControl; /* * @author Helen Lee * @create 2022/12/23 * @description */ import com.example.demoForCucumber.config.URLConfig; import io.restassured.RestAssured; import io.restassured.response.Response; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; @Service public class FreeWeatherAPIBase { @Autowired URLConfig urlConfig; public Map headersForFreeWeather(){ Map headers = new HashMap(); // headers.put("Content-Type","application/json"); headers.put("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15"); return headers; } public Response GET_freeWeather(Map headers,Map parameters){ Response response = RestAssured.given() .headers(headers) .params(parameters) .when() .get(this.urlConfig.getUrlWeather()+"/get"); return response; } }
5)API_01_GET_freeWeather.feature
测试场景示例
@API Feature: API_01_GET_freeWeather Scenario Outline: get weather by city Given I have a correct headers for GET_freeWeather And parameter_city=[<city>] for GET_freeWeather When GET_freeWeather receive this request Then it will return http status=[200] from GET_freeWeather And we can find success=[true] from response body of GET_freeWeather And we can find city=[<city>] from response body of GET_freeWeather Examples: |city| | 广州 | | 上海 |
6)GET_freeWeather_steps.java
对应API_01_GET_freeWeather.feature的step 定义。
(notice: 需要在steps里面加上标签@SpringBootTest, 否则使用cucumber runner执行时不能自动加载springBoot的配置)
package com.example.demoForCucumber.steps; import com.example.demoForCucumber.DemoForCucumberApplication; import com.example.demoForCucumber.baseAPIControl.FreeWeatherAPIBase; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; import cucumber.api.java.en.When; import io.restassured.response.Response; import org.junit.Assert; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.HashMap; import java.util.Map; /* * @author Helen Lee * @create 2022/12/23 * @description */ @SpringBootTest(classes = DemoForCucumberApplication.class) public class GET_freeWeather_steps { Map headers; Map parameters=new HashMap<>(); Response response; @Autowired FreeWeatherAPIBase freeWeatherAPIBase; @Given("I have a correct headers for GET_freeWeather") public void set_headers(){ this.headers= this.freeWeatherAPIBase.headersForFreeWeather(); } @Given("parameter_(.*)=\\[(.*)] for GET_freeWeather") public void set_parameter(String parameterName,String parameterValue){ this.parameters.put(parameterName,parameterValue); } @When("GET_freeWeather receive this request") public void call_API(){ this.response = this.freeWeatherAPIBase.GET_freeWeather(this.headers,this.parameters); } @Then("it will return http status=\\[(.*)] from GET_freeWeather") public void check_http_status(int status){ Assert.assertEquals(status,this.response.getStatusCode()); } @Then("we can find success=\\[(.*)] from response body of GET_freeWeather") public void check_successStatus(boolean successStatus){ Assert.assertEquals(successStatus,this.response.jsonPath().getBoolean("success")); } @Then("we can find city=\\[(.*)] from response body of GET_freeWeather") public void check_targetCity(String city){ Assert.assertEquals(city,this.response.jsonPath().getString("city")); } }
7)DemoForCucumberApplicationTests.java
cucumber runnepackage com.example.demoForCucumber;
(notice: runner 里面可以增加rerun的配置来获取失败的用例,以便后面生,cucumber,重新执行失败用例)
import cucumber.api.CucumberOptions; import cucumber.api.junit.Cucumber; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(Cucumber.class) @CucumberOptions( tags = {"@API"}, features = {"src/main/resources/features"}, glue = {"com.example.demoForCucumber"}, plugin = { "pretty", "html:target/cucumber", "json:target/cucumberReportJsonFiles/cucumber-report.json",
"rerun:target/failed_rerun.txt"
} ) public class DemoForCucumberApplicationTests { @Test void contextLoads() { } }
8) 最后执行DemoForCucumberApplicationTests.java, 可以得到如下结果
9) 查看HTML 报告
(有兴趣的同学可以看下一篇cucumber:使用cucumber-reporting 插件优化HTML report)
通过浏览器打开index.html