译者 | 杨晓娟
审校 | 孙淑娟
Rest Assured库简介
REST(Representational State Transfer)是一种利用HTTP调用进行系统间通信的架构,客户端可以使用唯一的URI访问服务器资源以及资源返回的响应。资源的URI充当资源标识符,可以对资源执行诸如GET、POST、PUT、PATCH和DELETE等HTTP操作。
REST Assured是一个Java库,它利用领域特定语言(DSL)为Restful APIs开发健壮、可维护的测试。我们来看一下Rest Assured Library的一些显著特点:
- 它是一个开源应用程序,没有许可费用
- 使用常用的编程语言Java
- 它使Rest服务的API测试和验证变得简单流畅
- 用GPath遍历响应,非常适合XML和JSON的响应读取
- 适用于JSON模式的验证
- 可以与其他测试框架(如TestNG、JUnit等)轻松集成
- 支持所有类型HTTP方法的API自动化,如GET、POST、PUT、DELETE、PATCH等
- 支持BDD Gherkin语言,从而实现简洁的编码和易读性
Cucumber框架介绍
Cucumber是一个支持行为驱动开发(BDD)的开源测试框架,也是一个被广泛使用的框架,测试人员可以用Gherkin的简单英语编写测试用例。
为了能让非技术人员轻松理解测试过程和流程,许多组织希望将Cucumber框架与Selenium或Rest Assured集成以实现应用程序自动化。由于Cucumber允许用简单的英语纯文本编写测试和场景,因此对于许多团队成员(业务分析师、项目经理、手动测试人员)和任何其他非技术人员来说,查看和理解测试工作流程变得非常容易,这成为 Cucumber的主要优势。Cucumber被称为行为驱动开发(BDD)框架,因为它能让任何人仅通过读取feature文件便可获取应用程序的功能行为。
Cucumber框架的三个组成部分:
1.剧本(Feature)文件:此文件以测试特性、测试场景、测试标签、测试用例、测试数据等形式提供有关被测试应用程序的高级信息。以下是用于创建feature文件的几个组件:
- Feature-定义要测试的特性,通常是标题。
- Scenario-定义特定测试场景,必须要为其创建测试流。
- Scenario Outline-定义针对不同测试数据的特定测试场景,测试数据以管道符号(|)分隔的表格结构提供。
- Tags-为每个场景定义标签名,这有助于组织或分组feature文件的所有测试场景。可在上面的Feature关键字上使用标签来指示需要执行哪个feature文件。
- Given-定义特定测试场景的前置条件
- When-定义动作,也可以是与尚未执行的应用的交互动作
- And-定义与前一动作相关联的额外动作
- Then-定义预期的测试输出和要执行的后操作
- Examples-为“Scenario Outline”中编写的测试用例定义测试数据集
2.步骤定义(Step Definition)文件:创建步骤定义文件是为了将所有剧本文件测试用例步骤链接到代码。在步骤定义文件中使用Given、When、Then等几个注解来映射测试用例步骤以执行代码。对于要执行的测试用例,注解描述必须与剧本文件中提到的测试步骤相匹配。
3.测试执行(Test Runner)文件:此文件是测试套件的驱动程序文件,用于驱动或运行基于剧本文件的步骤定义文件。测试执行文件包含剧本和步骤定义文件的路径,以及要执行的、基于Cucumber的测试报告所需的标签。对基于Cucumber的HTML报告,还提供了添加插件的选项,以生成有见地的报告。
集成Rest Assured库与Cumber框架
了解了Rest Assured库和Cucumber框架,现在我们来实际理解下如何创建测试场景,并学习针对不同测试数据集进行API测试的步骤。如前所述,要将Rest Assured库与Cucumber框架集成,需要创建像feature、step definition、runner这些文件。
在继续之前,我们先创建一个简单的maven项目,并在pom.xml文件中导入所有rest assured库的依赖项和cucumber框架。
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-java</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-jvm-deps</artifactId>
<version>1.0.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-testng</artifactId>
<version>1.2.5</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.masterthought</groupId>
<artifactId>cucumber-reporting</artifactId>
<version>5.0.2</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-path</artifactId>
<version>4.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>xml-path</artifactId>
<version>4.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-schema-validator</artifactId>
<version>4.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
在使用Cucumber框架时,建议对不同的Cucumber组件使用不同的包;这有助于开发出更好的项目层次结构,并易于对测试套件的理解。
Feature文件
Reqres_api_test.feature
Feature: Test Reqres Users API's With Rest Assured Library And Cucumber Framework
@SmokeTest
Scenario Outline: Reqres GET API test
Given the valid endpoint to fetch users
When the request is sent to the server with page number “<page>”
Then validate the response of the first user record having email as “<emailID>”
Examples:
|page|emailID |
| 2 |michael.lawson@reqres.in|
| 1 |george.bluth@reqres.in|
@SmokeTest
Scenario Outline: Reqres POST API test
Given the valid endpoint with payload to create a user
When the request is sent to the server
Then the new user must be created with the name “<username>”
Examples:
|username|
| john |
上述剧本文件的目标是使用多个测试数据执行参数化测试。因此,创建测试数据时使用“Examples”关键字,并且测试数据使用管道符号作为分隔符(|)。要在剧本文件的测试步骤中添加参数,语法为“<variableName>”;上面的文件也使用了同样的方法。而且要在Examples的第一行使用相同的变量名,以根据特定参数隔离测试数据。
Step Definition文件
GetApiTest.java
package stepDefinitions;
import static io.restassured.RestAssured.given;
import org.testng.Assert;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import io.restassured.response.Response;
public class GetApiTest {
Response response;
@Given("^the valid endpoint to fetch users$")
public void setupEndpoint()
{
RestAssured.baseURI="https://reqres.in/";
RestAssured.basePath="/api/users";
}
@When("^the request is send to server with page number as \"([^\"]*)\"$")
public void sendRequest(int pageNumber)
{
response = given()
.queryParam("page",pageNumber)
.when()
.get()
.then()
.contentType(ContentType.JSON)
.extract().response();
}
@Then("^validate the response of first user record having email as \"([^\"]*)\"$")
public void validateUserData(String emailID)
{
String userEmail = response.path("data[0].email");
Assert.assertEquals(userEmail, emailID);
}
}
PostApiTest.java
package stepDefinitions;
import static io.restassured.RestAssured.given;
import java.util.HashMap;
import org.testng.Assert;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import io.restassured.response.Response;
public class PostApiTest {
Response response;
public HashMap<Object,Object> map=new HashMap<Object,Object>();
@Given("^the valid endpoint with payload to create user$")
public void setupEndpointAndPostData()
{
RestAssured.baseURI="https://reqres.in/";
RestAssured.basePath="/api/users";
map.put("name","john");
map.put("job", "Software Developer");
}
@When("^the request is send to the server$")
public void sendRequest()
{
response = given()
.contentType(ContentType.JSON)
.body(map)
.when()
.post()
.then()
.statusCode(201).contentType(ContentType.JSON)
.extract().response();
}
@Then("^the new user must be created with name as \"([^\"]*)\"$")
public void validateResponse(String name)
{
String userName = response.path("name");
Assert.assertEquals(userName, name);
}
}
上面,我们已为剧本文件中提到的两个场景分别创建了两个步骤定义文件,一个用于GET API验证,另一个用于POST API验证。
我们已经在步骤定义文件中为剧本文件定义的每个测试步骤编写了执行代码。这是rest assured与Cucumber框架进行集成的文件,因为所有的API都在这里被验证。剧本文件中编写的测试步骤在使用参数进行定义的方式上必须与注解说明中的相同。此外,我们这里使用了一些TestNG来断言服务器响应。
Runner文件
Runner.java
package testRunner;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import cucumber.api.CucumberOptions;
import cucumber.api.testng.CucumberFeatureWrapper;
import cucumber.api.testng.TestNGCucumberRunner;
@CucumberOptions(
features = "src/test/java/FeatureFile",
glue = {"stepDefinitions"},
tags = {"@SmokeTest"},
format = {
"pretty",
"html:target/cucumber-reports/cucumber-pretty",
"json:target/cucumber-reports/CucumberTestReport.json",
"rerun:target/cucumber-reports/rerun.txt"
},
plugin = "json:target/cucumber-reports/CucumberTestReport.json")
public class Runner {
private TestNGCucumberRunner testNGCucumberRunner;
@BeforeClass
public void setUp() throws Exception
{
testNGCucumberRunner = new TestNGCucumberRunner(Runner.class);
}
@Test(dataProvider="features")
public void my_test(CucumberFeatureWrapper cucumberFeature)
{
testNGCucumberRunner.runCucumber(cucumberFeature.getCucumberFeature());
}
@DataProvider
public Object[][] features()
{
return testNGCucumberRunner.provideFeatures();
}
@AfterClass
public void tearDown()
{
testNGCucumberRunner.finish();
}
}
代码走查
在Cucumber 测试执行文件中,有一个CucumberOptions注解,它接受诸如剧本文件和步骤定义文件的路径、标签名、报告格式以及HTML报告插件等参数。
为了集成Rest Assured库的Cucumber框架和TestNG框架,我们使用名为“TestNGCucumberRunner”的Cucumber框架预定义类,该类提供了runCucumber、provideFeatures、finish等多种方法。另外,“CucumberFeatureWrapper”是一个接口,用在Test注解的方法参数中,以使TestNG报告更具描述性。
TestNG.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="TestNG-Cucumber Suite" thread-count="10" parallel="tests">
<test name="Apple test">
<classes>
<class name="testRunner.Runner" />
</classes>
</test>
</suite>
这是用于配置测试套件执行的TestNG XML文件。我们使用Runner java类执行API测试;完成后,可以从target directory->cucumber-reports->cucumber-pretty->index.html查看报告。
译者介绍
杨晓娟,51CTO社区编辑,西安电子科技大学计算机专业硕士研究生,资深研发工程师,信息系统项目管理师,拥有近20年Java开发经验。分别在NEC、甲骨文、英方从事数据存储、Oracle数据库的数据迁移以及同构/异构数据库复制等研发工作,尤其在数据库、数据编码等方面有深入钻研和了解。
原文标题:API Test Automation With RestAssured Library and Cucumber BDD Framework,作者:Ramit Dhamija