当前位置:   article > 正文

DolphinScheduler 如何用 Java+Rest-Assured+PageObject 进行自动化测试

dolphinscheduler java

点击蓝字 关注我们

1a851a17f0cb079d4bdf19ce526f500f.png

作者 | 闫旭平

本文将介绍如何基于 DolphinScheduler 和 REST Assured 来进行接口自动化测试,并使用 PageObject 模式管理你的测试用例。

最终产物:通过 PageObject +REST Assured + Junit 完成你的 Java 接口自动化测试,更加快捷、高效地保证你的项目接口质量。

01

概念简介

01

接口自动化测试

一般讲的接口测试指的是对某个给定接口进行功能测试,输入不同的参数时,接口返回值是否正确。下图是经典的测试金字塔模型。

ef8f42cfd54d90abb51f2a1ce833c20f.png

在这个模型中,越往下比例会占的越高,也就是说在一个产品测试中,单元测试比例是最高的,依次是接口测试和 UI自动化测试,最顶端是人工测试部分。服务端接口测试在中部,承上启下,由此可见其重要性。

简单来说,接口测试就是参照接口文档,调用接口,看结果的返回是否跟文档说明一致;另外,再测试一下接口对异常逻辑的处理比如非法参数或边界值。

而接口自动化测试是对系统或组件之间的接口进行测试,主要是校验数据的交换,传递和控制管理过程,以及相互逻辑依赖关系。接口自动化测试具有数据与脚本分离,测试结果自动提交通知,提高测试脚本和测试数据的维护便利等优点。

02

REST-assured

REST-assured 是一个开源的 Java 库,用来测试和验证 REST API。动态语言如 Groovy,Ruby 执行 API 测试非常简单,但对 Java 来说就有点费力了。而 REST Assured 使得用 Java 语言测试 API 和使用 Ruby 和 Groovy 执行测试一样简单。

REST Assured 是一种 JAVA DSL(Domain Specific Language)领域特定语言 [ 通常被定义为一种特别针对某类特殊问题的计算机语言,它不打算解决其领域外的问题。],用来简化测试 REST Services,并简化 HTTP Builder 顶层。REST Assured 支持发起任意 HTTP 请求 GET, POST, PUT, DELETE, OPTIONS, PATCH 和 HEAD, 包括详述清单,比如参数,头部,cookie 和实体,并验证这些请求的响应。

REST Assured 基于Apache Http Client,提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且支持 HTTP 协议最新的版本。

下面介绍基于 DolphinScheduler 和 REST Assured 进行接口自动化测试的全过程。

02

安装

01

Java8环境

  1. sudo apt-get update
  2. sudo apt-get install openjdk-8-jdk
  3. java -version

配置Java环境变量,~/.bashrc 或者 ~/.zshrc

  1. # 确认你的jdk的目录是否为这个,配置环境变量
  2. export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-amd64
  3. export PATH=$PATH:$JAVA_HOME/bin

Apache DolphinScheduler 3.1.2

详细安装可见官网:https://dolphinscheduler.apache.org/en-us/docs/latest/user_doc/guide/installation/standalone.html

下载DolphinScheduler 3.1.2

  1. # 进入需要安装DolphinScheduler的目录
  2. mkdir dolphinscheduler && cd "$_"
  3. ## install DolphinScheduler
  4. wget <https://mirrors.tuna.tsinghua.edu.cn/apache/dolphinscheduler/3.1.2/apache-dolphinscheduler-3.1.2-bin.tar.gz>
  5. tar -zxvf apache-dolphinscheduler-3.1.2-bin.tar.gz
  6. rm apache-dolphinscheduler-3.1.2-bin.tar.gz

启动DolphinScheduler

  1. ## start DolphinScheduler
  2. cd apache-dolphinscheduler-3.1.2-bin
  3. bash bin/dolphinscheduler-daemon.sh start standalone-server
  4. ## 可以通过以下命令查看日志

启动后,稍等一会服务启动即可进入DolphinScheduler的页面

打开 http://localhost:12345/dolphinscheduler/ui,可以看到DolphinScheduler页面

账号:admin,密码:dolphinscheduler123

8b16e7fa53972b79f83e326cae0435e9.png

02

REST Assured环境

pom.xml中添加

  1. <dependency>
  2. <groupId>io.rest-assured</groupId>
  3. <artifactId>rest-assured</artifactId>
  4. <version>5.3.0</version>
  5. </dependency>

03

新建配置文件

  1. public class dolphinConfig {
  2. public String userName= "admin";
  3. public String passWord = "dolphinscheduler123";
  4. public String baseUrl = "http://localhost:12345/dolphinscheduler";
  5. private static dolphinConfig dolphinConfig;
  6. public static dolphinConfig getInstance(){
  7. if (dolphinConfig==null){
  8. dolphinConfig=new dolphinConfig();
  9. }
  10. return dolphinConfig;
  11. }
  12. }

实例化RequestSpecification方法减少重复代码

Template方法是修改json文件,进行json文件参数化测试,只针对差异化参数修改json文件

  1. import com.jayway.jsonpath.DocumentContext;
  2. import com.jayway.jsonpath.JsonPath;
  3. import io.restassured.specification.RequestSpecification;
  4. import java.io.IOException;
  5. import java.nio.charset.StandardCharsets;
  6. import java.nio.file.Files;
  7. import java.nio.file.Path;
  8. import java.nio.file.Paths;
  9. import java.util.HashMap;
  10. import static io.restassured.RestAssured.given;
  11. public class Restful {
  12. HashMap<String, Object> query= new HashMap<String, Object>();
  13. public static RequestSpecification baseRequest = given();
  14. public static String template(String pathfile, HashMap<String, Object> map) throws IOException {
  15. Path path = Paths.get(pathfile);
  16. String jsonString = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
  17. DocumentContext document = JsonPath.parse(jsonString);
  18. map.entrySet().forEach(entry->{
  19. document.set(entry.getKey(),entry.getValue());
  20. });
  21. return document.jsonString();
  22. }
  23. }

初始化接口,重复的参数提炼成新方法供后面继承的方法调用

  1. import static io.restassured.RestAssured.given;
  2. public class baseRequest extends Restful{
  3. public baseRequest() {
  4. api_init();
  5. }
  6. public void api_init(){
  7. baseRequest = given()
  8. .log().all()
  9. .header("sessionId", dolphin.session())
  10. .header("Accept","application/json, text/plain, */*")
  11. .header("language","zh_CN")
  12. .header("Content-Type","application/x-www-form-urlencoded")
  13. //.contentType(ContentType.JSON);
  14. }
  15. }

Session持久化,减少冗余鉴权

  1. import static org.hamcrest.Matchers.equalTo;
  2. public class dolphin extends baseRequest {
  3. public static String baseUrl = null;
  4. public static String userName = null;
  5. public static String passWord = null;
  6. private static String sessionId = null;
  7. public static String logIn(){
  8. baseUrl = dolphinConfig.getInstance().baseUrl;
  9. userName = dolphinConfig.getInstance().userName;
  10. passWord = dolphinConfig.getInstance().passWord;
  11. sessionId = baseRequest
  12. .queryParam("userName",userName)
  13. .queryParam("userPassword",passWord)
  14. .post(baseUrl+"/login")
  15. .then().statusCode(200)
  16. .body("code", equalTo(0)).extract().path("data.sessionId");
  17. return sessionId;
  18. }
  19. public static String session(){
  20. if (sessionId== null){
  21. sessionId= logIn();
  22. }
  23. return sessionId;
  24. }
  25. }

对项目增删改查接口进行建模

  1. import base.dolphin;
  2. import io.restassured.response.Response;
  3. public class project extends dolphin {
  4. public Response create(String projectName,String description){
  5. Response response= baseRequest
  6. .param("projectName",projectName)
  7. .param("description",description)
  8. .param("userName",userName)
  9. .when().post(baseUrl+"/projects")
  10. .then().statusCode(201).extract().response();
  11. api_init();
  12. return response;
  13. }
  14. public Response update(Long projectCode,String projectName,String description){
  15. Response response= baseRequest
  16. .param("projectName",projectName).param("description",description)
  17. .param("userName",userName)
  18. .when().put(baseUrl+"/projects/"+ projectCode)
  19. .then().statusCode(200).extract().response();
  20. api_init();
  21. return response;
  22. }
  23. public Response delete(Long projectCode){
  24. Response response= baseRequest
  25. .when().delete(baseUrl+"/projects/"+ projectCode)
  26. .then().statusCode(200).extract().response();
  27. api_init();
  28. return response;
  29. }
  30. public Response search(Integer pageSize, Integer pageNo, String searchName){
  31. if (pageSize ==null | pageSize < 10){
  32. pageSize =10;
  33. }
  34. if (pageNo ==null | pageNo < 1) {
  35. pageNo =1;
  36. }
  37. Response response= baseRequest
  38. .param("pageSize",pageSize)
  39. .param("pageNo",pageNo)
  40. .param("searchVal",searchName)
  41. .when().get(baseUrl+"/projects")
  42. .then().statusCode(200).extract().response();
  43. api_init();
  44. return response;
  45. }
  46. public Response search(String searchName){
  47. Response response= baseRequest
  48. .param("pageSize",10)
  49. .param("pageNo",1)
  50. .param("searchVal",searchName)
  51. .when().get(baseUrl+"/projects")
  52. .then().statusCode(200).extract().response();
  53. api_init();
  54. return response;
  55. }
  56. }

对项目增删改查接口进行测试

  1. import org.junit.jupiter.api.*;
  2. import org.junit.jupiter.params.ParameterizedTest;
  3. import org.junit.jupiter.params.provider.ValueSource;
  4. import static org.hamcrest.Matchers.equalTo;
  5. class projectTest {
  6. static project project;
  7. @BeforeAll
  8. static void setUp() {
  9. if (project == null){
  10. project=new project();
  11. }
  12. }
  13. @AfterAll
  14. static void setDown(){
  15. int total = project.search("").then().log().all().extract().path("data.total");
  16. for (int i = 0; i < total; i++) {
  17. Long projectCode = project.search("").then().extract().path("data.totalList[0].code");
  18. project.delete(projectCode);
  19. }
  20. }
  21. @Test
  22. @Disabled
  23. void search(){
  24. project.search("").body();
  25. String code=String.valueOf(project.search("").path("data.totalList[0].find{ it.name == 'test666' }.code"));
  26. System.out.println("projectcode"+ code);
  27. }
  28. @ParameterizedTest
  29. @ValueSource(strings={"ApiTestCreateProject123","ApiTestCreateProject456","ApiTestCreateProject789"})
  30. @DisplayName("create project Testcase")
  31. void create(String name) {
  32. String projectname =name;
  33. project.create(projectname,"")
  34. .then().body("code", equalTo(0));
  35. project.search(projectname)
  36. .then().body("data.totalList[0].name",equalTo(projectname));
  37. }
  38. @Nested
  39. @DisplayName("update projectName Testcase")
  40. class update_delete{
  41. @Test
  42. void update() {
  43. project.create("ApiTestCreateProject_update_init","ApiTestCreateProject_update_init")
  44. .then().body("code", equalTo(0));
  45. Long projectCode = project.search("ApiTestCreateProject_update_init")
  46. .then().log().all().body("data.totalList[0].name", equalTo("ApiTestCreateProject_update_init"))
  47. .extract().path("data.totalList[0].code");
  48. project.update(projectCode,"ApiTestCreateProject_update_now","ApiTestCreateProject_update_now")
  49. .then().body("code", equalTo(0));
  50. project.search("ApiTestCreateProject_update_now")
  51. .then().body("data.totalList[0].name",equalTo("ApiTestCreateProject_update_now"));
  52. }
  53. @Nested
  54. @DisplayName("delete project")
  55. class delete{
  56. @Test
  57. void delete(){
  58. Long projectCode = project.search("ApiTestCreateProject_update_now")
  59. .then().log().all().body("data.totalList[0].name", equalTo("ApiTestCreateProject_update_now"))
  60. .extract().path("data.totalList[0].code");
  61. project.delete(projectCode);
  62. }
  63. }
  64. }

测试结果:

4c57cc4a9ef47d5b0b5c5d986378ec05.png

04

对数据源中心接口进行建模

  1. import base.dolphin;
  2. import io.restassured.response.Response;
  3. import java.io.IOException;
  4. import java.util.HashMap;
  5. public class datasource extends dolphin {
  6. public Response create(HashMap<String,Object> map) throws IOException {
  7. String body = template("dolphin/resource/data/database.json",map);
  8. Response response = baseRequest.body(body)
  9. .when().post(baseUrl+"/datasources")
  10. .then().statusCode(201).extract().response();
  11. api_init();
  12. return response;
  13. }
  14. public Response connect(HashMap<String, Object> map) throws IOException {
  15. String body = template("dolphin/resource/data/database.json",map);
  16. Response response = baseRequest.body(body)
  17. .when().post(baseUrl+"/datasources/connect")
  18. .then().statusCode(200).extract().response();
  19. api_init();
  20. return response;
  21. }
  22. public Response update(int datasourceid,HashMap<String, Object> map) throws IOException {
  23. String body = template("/data/database.json",map);
  24. Response response = baseRequest.body(body)
  25. .when().put(baseUrl+"/datasources/"+ datasourceid)
  26. .then().statusCode(200).extract().response();
  27. api_init();
  28. return response;
  29. }
  30. }

数据源中心接口测试用例:

  1. import org.junit.jupiter.api.AfterEach;
  2. import org.junit.jupiter.api.BeforeEach;
  3. import org.junit.jupiter.api.Test;
  4. import java.io.IOException;
  5. import java.util.HashMap;
  6. import static org.hamcrest.Matchers.equalTo;
  7. class datasourceTest {
  8. datasource datasource;
  9. @BeforeEach
  10. void setUp() {
  11. if (datasource == null){
  12. datasource=new datasource();
  13. }
  14. }
  15. @AfterEach
  16. void tearDown() {
  17. }
  18. @Test
  19. void create() throws IOException {
  20. HashMap<String,Object> map=new HashMap<>();
  21. map.put("type","MYSQL");
  22. map.put("name","apiTestmysql");
  23. map.put("userName","root");
  24. map.put("password","root@123");
  25. datasource.create(map).then().body("code",equalTo(0));
  26. }
  27. @Test
  28. void connet() throws IOException {
  29. HashMap<String, Object> map=new HashMap<>();
  30. map.put("type","MYSQL");
  31. map.put("name","apiTestmysql");
  32. map.put("userName","root");
  33. map.put("password","root@123");
  34. map.put("database","xuxutestdb123");
  35. datasource.connect(map).then().body("code",equalTo(0));
  36. }
  37. }

测试结果:

21fdc779fa1db1a3f08f7f148a794b5c.png

测试用例源码地址:https://github.com/XuXuClassMate/My_Test_JAProject/tree/master/dolphin/org.xuxuclassmate

05

总结

本文主要介绍了在 Apache DolphinScheduler 使用 Rest-Assured 进行接口自动化测试的过程,我们使用PageObject 来管理测试用例,可以降低测试用例及单个接口的维护成本。

参与贡献

随着国内开源的迅猛崛起,Apache DolphinScheduler 社区迎来蓬勃发展,为了做更好用、易用的调度,真诚欢迎热爱开源的伙伴加入到开源社区中来,为中国开源崛起献上一份自己的力量,让本土开源走向全球。

80fcade3acac9ad7ceb688a07d264527.png

参与 DolphinScheduler 社区有非常多的参与贡献的方式,包括:

ff4e2c78fe8c5bb7d645fd49622c0d81.png

贡献第一个PR(文档、代码) 我们也希望是简单的,第一个PR用于熟悉提交的流程和社区协作以及感受社区的友好度。

社区汇总了以下适合新手的问题列表:https://github.com/apache/dolphinscheduler/issues/5689

非新手问题列表:https://github.com/apache/dolphinscheduler/issues?q=is%3Aopen+is%3Aissue+label%3A%22volunteer+wanted%22

如何参与贡献链接:https://dolphinscheduler.apache.org/zh-cn/community/development/contribute.html

来吧,DolphinScheduler开源社区需要您的参与,为中国开源崛起添砖加瓦吧,哪怕只是小小的一块瓦,汇聚起来的力量也是巨大的。

参与开源可以近距离与各路高手切磋,迅速提升自己的技能,如果您想参与贡献,我们有个贡献者种子孵化群,可以添加社区小助手微信(Leonard-ds) ,手把手教会您( 贡献者不分水平高低,有问必答,关键是有一颗愿意贡献的心 )。

33bd56074b9f5e9ae3f44cb6eedd64b9.jpeg

添加社区小助手微信(Leonard-ds) 

添加小助手微信时请说明想参与贡献。

来吧,开源社区非常期待您的参与。

< 声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】

推荐阅读
相关标签