如何使用 Serenity BDD 进行 API 测试?

前文「如何使用 Serenity BDD 进行 UI 测试?」介绍了使用 Serenity BDD 与 Selenium 进行 Web UI 测试的方法,但 Serenity BDD 不仅限于进行 UI 测试,还可以使用其进行 REST API 测试。本文即介绍使用 Serenity BDD 与 REST Assured 进行 API 测试的方法。

REST Assured 是一个非常易用的、用于测试 RESTful API 的 Java 类库,之前专门介绍过其使用方法(如何使用 REST Assured 做 API 测试?),本文不再对 REST Assured 的基础进行赘述,而仅关注 Serenity BDD 与 REST Assured 的集成。

本文针对的测试场景是:「调用 GitHub REST API 创建一个 Issue」,测试工程使用 Maven 管理。

下面列出测试工程所使用的 JDK、Maven 与 Serenity BDD 的版本:

JDK:Amazon Corretto 17.0.8
Maven:3.9.2
Serenity BDD:4.1.20

测试工程目录结构如下:

serenity-bdd-api-test-demo
├─ src/test
│   ├─ java
│   │    └─ com.example.tests
│   │       ├─ actions
│   │       │   └─ CreateIssueAction.java
│   │       ├─ utils
│   │       │   └─ ConfigUtil.java
│   │       └─ GitHubIssueTest.java
│   └─ resources
│       └─ config.properties
└─ pom.xml

该工程的目录结构非常简单:actions 包用于放置一组动作类,该类的方法可使用 @Given@When@Then 注解来标记,分别进行准备、执行和断言;utils 包用于放置工具类,其下的 ConfigUtil.java 用于读取配置文件中的变量;resources/config.properties 为工程的配置文件,存放了待测试仓库基础 URL 和 GitHub Token。

测试工程用到的依赖如下:

<!-- serenity bdd -->
<dependency>
    <groupId>net.serenity-bdd</groupId>
    <artifactId>serenity-core</artifactId>
    <version>${serenity-bdd.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>net.serenity-bdd</groupId>
    <artifactId>serenity-rest-assured</artifactId>
    <version>${serenity-bdd.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>net.serenity-bdd</groupId>
    <artifactId>serenity-junit5</artifactId>
    <version>${serenity-bdd.version}</version>
    <scope>test</scope>
</dependency>

<!-- logback -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.5.6</version>
    <scope>test</scope>
</dependency>

<!-- junit 5 -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>${junit.version}</version>
    <scope>test</scope>
</dependency>

可以看到,Serenity BDD 为主要的依赖,包含了 Serenity 基础功能、REST Assured,以及 Serenity 和 JUnit 5 集成的相关模块;其次,还引用了 Logback 和 JUnit 5 依赖,分别用于日志打印和单元测试执行。

除了如上依赖外,还在 pom.xml 文件引用了两个插件:maven-compiler-pluginserenity-maven-plugin,分别用于工程编译和测试报告生成。

下面对代码的关键部分进行分析。

2 代码分析

2.1 Action 类

我们将对应 BDD 中 @Given@When@Then 部分的逻辑封装到了 Action 类当中。CreateIssueAction.java 即负责 Issue 创建相关的各种操作。

// src/test/java/com/example/tests/actions/CreateIssueAction.java
package com.example.tests.actions;

import com.example.tests.utils.ConfigUtil;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.restassured.http.ContentType;
import io.restassured.response.Response;
import net.serenitybdd.core.steps.UIInteractions;

import java.util.HashMap;
import java.util.Map;

import static io.restassured.path.json.JsonPath.from;
import static net.serenitybdd.rest.SerenityRest.given;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;

public class CreateIssueAction extends UIInteractions {
    private int statusCode;
    private String responseBody;

    @Given("新增一个标题为 {0} 的 Issue")
    public void createIssue(String title) {
        // request
        Map<String, Object> requestBody = prepareRequestBody(title);

        // response
        Response response = given().contentType(ContentType.JSON)
                .accept(ContentType.JSON)
                .header("Authorization", "Bearer " + ConfigUtil.getProperty("GITHUB_TOKEN"))
                .body(requestBody)
                .post("/issues")
                .then()
                .extract().response();

        // extract
        this.statusCode = response.getStatusCode();
        this.responseBody = response.asString();
    }

    @Then("响应码为 {0},响应体中的 Issue 标题为 {1}")
    public void responseShouldBeValid(int statusCode, String title) {
        // extract fields
        String issueTitle = from(responseBody).getString("title");

        // assertions
        assertThat(statusCode, equalTo(this.statusCode));
        assertThat(title, equalTo(issueTitle));
    }

    private Map<String, Object> prepareRequestBody(String title) {
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("title", title);
        return requestBody;
    }
}

可以看到,CreateIssueAction 类继承了 Serenity 的 UIInteractions 类,UIInteractions 类虽然在命名上带了 UI,但不表示其仅用于 UI 交互操作,其除了具有操作 UI 的能力外,还具有操作 API 的能力。

CreateIssueAction 类的 createIssue() 方法标注了 @Given 注解,内部使用 REST Assured 发起了 Issue 创建请求并记录了响应结果;responseShouldBeValid() 方法标注了 @Then 注解,负责获取响应体返回的标题并进行断言。

2.2 单元测试类

测试用例的入口为普通的 JUnit 5 单元测试类,一个测试类可以包含一组相关的测试。

负责测试 Issue 创建的部分被放置在了 GitHubIssueTest 类中,其代码如下:

// src/test/java/com/example/tests/GitHubIssueTest.java
package com.example.tests;

import com.example.tests.actions.CreateIssueAction;
import com.example.tests.utils.ConfigUtil;
import io.restassured.RestAssured;
import net.serenitybdd.junit5.SerenityJUnit5Extension;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(SerenityJUnit5Extension.class)
public class GitHubIssueTest {
    private CreateIssueAction createIssueAction;

    @BeforeAll
    public static void setUp() {
        RestAssured.baseURI = ConfigUtil.getProperty("GITHUB_BASE_URI");
    }

    @Test
    public void testIssueCreation() {
        String title = "Serenity API Test";
        createIssueAction.createIssue(title);
        createIssueAction.responseShouldBeValid(201, title);
    }
}

可以看到,该类使用 @ExtendWith(SerenityJUnit5Extension.class) 注解修饰,表示其启动由 Serenity JUnit5 扩展来负责;然后在 setUp() 方法设置了基础 URI;在测试方法 testIssueCreation() 调用了 createIssueAction 创建了 Issue 并断言了结果。

3 程序运行及报告查看

本示例工程可以直接在 IntelliJ IDEA 中运行,也可以在命名行键入如下命令运行:

mvn clean verify

运行完成后,会在 target/site/serenity 文件夹生成 HTML 测试报告。打开后,效果如下:

Serenity 生成的 HTML 报告

可以看到,报告展示的信息非常详细,包含了每个步骤的执行情况,并针对发起 API 请求的步骤,记录了请求 URL、请求体和响应体等信息。

4 小结

综上,本文以创建 GitHub Issue 为测试场景,介绍了使用 Serenity BDD 与 REST Assured 进行 API 测试的方法。

本文完整示例工程已提交至 GitHub,欢迎关注或 Fork。

参考资料

[1] Serenity BDD: Your First API Test - https://serenity-bdd.github.io/docs/tutorials/rest

[2] 磊磊落落:如何使用 Serenity BDD 进行 UI 测试?- https://leileiluoluo.com/posts/how-to-perform-ui-testing-using-serenity-bdd.html

[3] 磊磊落落:如何使用 REST Assured 做 API 测试?- https://leileiluoluo.com/posts/how-to-perform-api-testing-using-rest-assured.html

评论

正在加载评论......