当前位置: 首页 > news >正文

Selenium 必了解—如何测试REST API

目录

前言:

Web UI测试存在的问题:

REST API测试:

依赖包

程序示例:

1-获取联系人

2-GET Request:

3-POST Request:

4- 编辑请求

5- 删除请求


前言:

Selenium WebDriver 可以用于测试 Web 应用的前端界面和功能,但是对于 Web 应用的后台接口,如 REST API,Selenium 无法直接进行测试。不过,Selenium WebDriver 也提供了相应的方法来发送 HTTP 请求和处理响应,从而进行 REST API 测试。

如果你只需要测试api,那么建议浏览这篇文章:Jmeter如何测试REST API /微服务

Web UI测试存在的问题:

  • 慢(这是因为你的浏览器首先向服务器发送一个请求以获取某些信息,一旦获得所需数据,可能需要一些时间来处理数据,并通过下载的图片和应用样式使其显示在表格中/或者以适配的格式显示,所以你必须等待整个过程完成之后才能与应用程序进行交互);

  • 费时;

  • 对于测试不同的浏览器,可能必须重复相同的测试集;

  • 浏览器是独立于selenium脚本的进程。所以同步总是一个问题;

  • UI测试有很多依赖项,比如Browsers/Versions/Grid/Driver等等。

因此,这并不意味着我们应该总是做API级别的测试并发布产品; 我们应该尝试尽可能的进行API级别测试。 我们可以只为UI测试提供较小覆盖率。

REST API测试:

与Selenium WebDriver UI测试相比,REST API测试并不难,大多数api都是GET / POST / PUT / PATCH / DELETE请求之一:

  • GET 用于从后端获取信息以显示在UI中;

  • POST 用于在后端添加新信息;

  • PUT用于更新/替换任何现有信息;

  • PATCH 用于部分更新;

  • DELETE 用于从后端删除信息。

假设你使用testNG/Junit这样的框架,并使用Selenium进行应用程序UI测试 --而现在希望在相同的框架中也包含API测试 --可能需要快速设置数据或断言等,那么接下来就让我们看看如何在本文中完成。

依赖包

在maven文件中添加如下依赖:

<dependency><groupId>com.mashape.unirest</groupId><artifactId>unirest-java</artifactId><version>1.4.9</version>
</dependency>
<dependency><groupId>org.jtwig</groupId><artifactId>jtwig-core</artifactId><version>5.87.0.RELEASE</version>
</dependency>
  • Unirest是一个简单的轻量级流畅式HTTP请求库

  • JTwig是一个非常简单的模板引擎

程序示例:

使用Rest API列出所有可用的联系人,添加/编辑/删除联系人;它还使用Angular构建了比较友好的UI界面;你可以克隆并部署到你的本地运行。

一旦上述应用程序部署成功并启动,就可以使用API GET请求获取联系人列表,显示在UI界面上。

1-获取联系人

当您访问应用程序的主页时,它会列出所有可用的联系人。

如果监视Chrome-network中的Network,可以看到发送了一些API GET请求来获取联系人列表。

  • 如果你不确定在哪里检查,在Chrome页面按下F12,Chrome开发工具将会出现。

  • 检查API url的header部分

本地部署的地址
https://localhost:4200/api/contacts?q=
而本文例子使用如下Live Demo链接:
https://restool-sample-app.herokuapp.com/你可以看到以下格式的JSON Response:
[{"id": "xiyydaS9CLqV","thumbnail": "https://www.hbo.com……","name": "Tyrion Lannister","realName": "Peter Dinklage","location": "Winterfell","isAlive": true}
]

你可以通过应用程序添加联系人,修改联系人,删除联系人等

2-GET Request:

一旦应用程序启动,可以使用API GET请求获取联系人列表,以便在应用程序中显示数据。可以使用Unirest发出上面说到的GET请求,如下所示:

String searchQueryApi = "https://restool-sample-app.herokuapp.com/api/character?search=";
JsonNode body = Unirest.get(searchQueryApi).asJson().getBody();
System.out.println(body);         // 打印完整的json响应信息
System.out.println(body.getArray().length());  // 打印item编号

其请求如下图所示:

也可以在测试框架中进行简单的断言。

例如下面的示例代码确认API响应中的所有数据是否都显示在UI中:

driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://restool-sample-app.herokuapp.com/");
List<WebElement> contacts = driver.findElements(By.cssSelector("tbody > tr"));
Assert.assertEquals(contacts.size(), body.getArray().length(), "The contacts not equals with Body length");

3-POST Request:

每当我们试图添加新的联系人时,就会发送POST请求并携带如下格式JSON作为Body:

{
"thumbnail": "https://www.hbo.com……",
"name": "Test Name",
"realName": "Test Real Name",
"location": "Test location",
"isAlive": false
}

如果你的目标是自己发送请求,那么您可能不希望在JSON文件中硬编码任何值。这就是我们使用JTwig模板引擎的地方。

首先,我在模板下面创建。

{"thumbnail": "{{URL}}","name": "{{name}}","realName": "{{realName}}","location": "{{location}}","isAlive": true
}

我将上面的JSON保存在一个名为“contact.json”的文件中。现在我可以读取模板并在运行时替换这些值,如下所示:

JtwigTemplate template = JtwigTemplate.classpathTemplate("contact.json");
JtwigModel model = JtwigModel.newModel()
.with("URL", "http://n.sinaimg.cn/ent/transform/20160502/n4qY-fxrunru8640821.png")
.with("name", "TestName")
.with("realName", "TestRailName")
.with("location", "Winterfell");
template.render(model);//用上述的值替换模板表达式中的值

接下来可以发送POST请求创建新的联系人了(发送POST请求之后,在这里还可以通过UI界面进行检查联系人是否成功显示在UI界面,此处不做详细Demo)

String postApi = "https://restool-sample-app.herokuapp.com/api/character";
Unirest.post(postApi)
.header("accept", "application/json")
.header("Content-Type", "application/json")
.body(template.render(model))
.asJson();

使用上面这个方法,我们可以在应用程序中快速的添加联系人。

假设页面最多只能显示50个联系人,你需要点击翻页按钮查看更多联系人,但是在本地/QA环境中,当你启动一个新的应用程序时,可能没有足够的联系人来测试该显示功能;

如果页面对象公开了一个方法来添加联系人,则需要调用50多次,通过UI界面添加联系人可能非常耗时,由于同步问题,它可能随时会失败,并且还需要处理:比如当用例重试失败或者退出导致测试失败等情况。

但是使用Api,您可以轻松地修改页面对象,如下所示,现在你可以用它来建立数据等等。它应该比UI方法快得多,而且更不容易出错。

class ContactsPage{//all find bys//methods for interacting with web elementspublic void addContacts(int numberOfContacts){String postApi = "https://restool-sample-app.herokuapp.com/api/character";for(int i = 0; i<numberOfContacts; i++){Unirest.post(postApi).header("accept", "application/json").header("Content-Type", "application/json").body(template.render(model)) .asJson();}}
}

Unirest可以很容易地在page对象中使用,如上面的示例所示。

4- 编辑请求

要编辑联系人,我们需要发送如下所示的PUT请求。

String editApi = "https://restool-sample-app.herokuapp.com/api/character/{contact_id}";
JtwigModel model = JtwigModel.newModel()
.with("name", "Snow").with("location", "Winterfell");
Unirest.put(editApi).routeParam("contact_id", "T2S6kHv4cS1A").header("accept", "application/json").header("Content-Type", "application/json").body(template.render(model)).asJson();

更新了Name:

5- 删除请求

删除就这就更简单了。

String editApi = "https://restool-sample-app.herokuapp.com/api/character/{contact_id}";
Unirest.delete(editApi).routeParam("contact_id", "T2S6kHv4cS1A").asJson();

我们可以使用这个API来清理测试是新建的数据,这样就保持测试之后的数据清洁,不会过多的新建无用甚至垃圾数据。

public class ContactsPageTest{  private String editApi = "https://localhost:4200/api/contacts/{contact_id}";@Testpublic void someUItest1(){//}@Testpublic void someUItest2(){//}@AfterTestpublic void teardown(){for(String contactid: listOfContacts){Unirest.delete(editApi).routeParam("contact_id", contactid).asJson();}}
}

总结:

通过在现有的测试框架/页面对象中使用Unirest,可以和REST api进行交互,还可以使用这些api在应用程序中进行快速设置数据,以便进行快速功能验证;

正如上面的示例中所提到的,只要可能,就尽量使用api进行测试。

完整Demo代码(请配合上述介绍使用):

package com.morningstar.automation.pdf.Download;
import org.jtwig.JtwigModel;
import org.jtwig.JtwigTemplate;
import org.openqa.selenium.WebDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
public class testRestAPI {
WebDriver driver;
@Test
public void testOne() throws Exception {
//GET Request:
String searchQueryApi = "https://restool-sample-app.herokuapp.com/api/character?search=";
JsonNode body = Unirest.get(searchQueryApi).asJson().getBody();
System.out.println(body); // 打印完整的json响应信息
System.out.println(body.getArray().length()); // 打印item编号
//验证联系人数量与UI界面显示的数量
//driver = new ChromeDriver();
//driver.manage().window().maximize();
//driver.get("https://restool-sample-app.herokuapp.com/");
//List<WebElement> contacts = driver.findElements(By.cssSelector("tbody > tr"));
//Assert.assertEquals(contacts.size(), body.getArray().length(), "The contacts not equals with Body length");
//添加一个新的联系人
JtwigTemplate template = JtwigTemplate.classpathTemplate("contact.json");
//JtwigModel model = JtwigModel.newModel()
//.with("URL", "http://n.sinaimg.cn/ent/transform/20160502/n4qY-fxrunru8640821.png")
//.with("name", "TestName")
//        .with("realName", "TestRailName")
//        .with("location", "Winterfell");
//template.render(model); //gives the json in the above format by replacing the template expressions
//GET Request:
//String postApi = "https://restool-sample-app.herokuapp.com/api/character";
//Unirest.post(postApi)
//        .header("accept", "application/json")
//        .header("Content-Type", "application/json")
//        .body(template.render(model))
//        .asJson();
//编辑请求, PUT
String editApi = "https://restool-sample-app.herokuapp.com/api/character/{contact_id}";
JtwigModel model = JtwigModel.newModel()
.with("name", "Snow").with("location", "Winterfell");
Unirest.put(editApi).routeParam("contact_id", "T2S6kHv4cS1A").header("accept", "application/json").header("Content-Type", "application/json").body(template.render(model)).asJson();
//删除请求 Delete
//String editApi = "https://restool-sample-app.herokuapp.com/api/character/{contact_id}";
//Unirest.delete(editApi)
//        .routeParam("contact_id", "T2S6kHv4cS1A")
//        .asJson();
}
@AfterClass
public void tearDown() {
// driver.quit();
}
}

contact.json文件就放置于根目录下斜体样式:

{"thumbnail": "http://n.sinaimg.cn/ent/transform/20160502/n4qY-fxrunru8640821.png","name": "{{name}}","realName": "{{realName}}","location": "{{location}}","isAlive": true
}

 作为一位过来人也是希望大家少走一些弯路,在这里我给大家分享一些自动化测试前进之路的必须品,希望能对你带来帮助。(WEB自动化测试、app自动化测试、接口自动化测试、持续集成、自动化测试开发、大厂面试真题、简历模板等等),相信能使你更好的进步!

留【自动化测试】即可【自动化测试交流】:574737577(备注ccc)icon-default.png?t=N4P3http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=eSv73sPKaVXpq9JeRq1Kboh1D-w19xXu&authKey=Qs1Sduo9tp2wfkOYvRyyFCoblyT7fBhH4PPisEb1G63n1UckS6wQU50e9ar1LAOz&noverify=0&group_code=574737577

 

 

相关文章:

Selenium 必了解—如何测试REST API

目录 前言&#xff1a; Web UI测试存在的问题&#xff1a; REST API测试&#xff1a; 依赖包 程序示例&#xff1a; 1-获取联系人 2-GET Request&#xff1a; 3-POST Request: 4- 编辑请求 5- 删除请求 前言&#xff1a; Selenium WebDriver 可以用于测试 Web 应用的…...

pytorch安装老版本

比如1.7.1&#xff0c; cuda 10.1 pip install torch1.7.1cu101 -f https://download.pytorch.org/whl/torch_stable.html官网查看有哪些可以装的&#xff1a; https://download.pytorch.org/whl/torch_stable.html...

怎么自学电脑编程

首要之首&#xff1a;不要急于选择一种语言 新手们有一个常见的错误就是犹豫于判断哪种编程语言是做好的、最该先学的。 我们有很多的选择&#xff0c;但你不能说那种语言最好。 我们应该理解&#xff1a;说到底&#xff0c;什么语言并不重要。 重要的是理解数据结构、控制逻辑…...

【华为OD统一考试B卷 | 100分】斗地主之顺子(C++ Java JavaScript Python)

文章目录 题目描述输入描述输出描述用例C++JavajavaScriptpython题目描述 在斗地主扑克牌游戏中, 扑克牌由小到大的顺序为:3,4,5,6,7,8,9,10,J,Q,K,A,2,玩家可以出的扑克牌阵型有:单张、对子、顺子、飞机、炸弹等。 其中顺子的出牌规则为:由至少5张由小到大连续递增的扑…...

案例39:基于Java办公自动化管理系统开题报告设计

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…...

基于山景BP10128音频处理器高通滤波器算法设计

+ hezkz17进数字音频答疑 山景BP10128音频处理器是一款高性能的数字信号处理器,专门用于音频信号的处理和增强。它采用先进的数字信号处理技术和算法,能够对音频信号进行实时处理,并且具有高效、稳定、可靠等特点。 该处理器具有以下主要功能: 均衡器:支持低音、中音、…...

docker搭建本地私有仓库

一、搭建本地私有仓库 有时候使用Docker Hub这样的公共仓库可能不方便&#xff0c;这种情况下用户可以使用registry创建一个本地仓库供私人使用&#xff0c;这点跟Maven的管理类似。 使用私有仓库有许多优点&#xff1a; 1&#xff09;节省网络带宽&#xff0c;针对于每个镜像…...

Asp.net某店POS积分管理系统-清除履历表、日志表、月购买额(源代码+论文)

大型百货店作为日常生活中不可缺少的一部分,给人们的生活提供了很大的方便。而为这样一个庞大而复杂的购物平台,提供一套完备的管理系统支持是很必要的。在现代销售行业中,会员制、积分管理、代金消费的概念已经越来越普及。为了吸引更多消费者,加大销售企业的竞争力。就需…...

Baumer工业相机堡盟工业相机如何使用BGAPISDK的相机图像时间戳计算运行时间以及时间差(C#)

Baumer工业相机堡盟工业相机如何使用BGAPISDK的相机图像时间戳计算运行时间以及时间差&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机BGAPI SDK和图像时间戳的技术背景Baumer工业相机使用BGAPISDK控制相机数据流的方式1.引用合适的类文件2.使用BGAPISDK获取时间戳的…...

python:消除已安装库在import导入时出现红线问题

问题 在pycharm中&#xff0c;对于已经安装的库文件&#xff0c;在进行import导入时出现红线&#xff0c;不影响运行&#xff0c; 简单有效的消除红线的方法。 解决办法 在工程目录中的程序可以采用Mark directory - Source Root方法。 对于安装的第三方库文件环境不在本工程…...

关闭nginx容器之后,再次启动,原来宿主机映射的端口失效的问题解决

最近用containerd在部署nginx的时候&#xff0c;发生了一个比较诡异的问题&#xff0c;当笔者通过nerdctl stop把原来的nginx容器关闭&#xff0c;然后再通过nerdctl run启动一个新的nginx容器的时候&#xff0c;把原来的宿主机端口映射到这个新容器上&#xff0c;但新启动的容…...

【小沐学Python】Python实现在线电子书(MkDocs + readthedocs + github + Markdown)

文章目录 1、简介2、安装3、创建新项目4、添加页面5、编辑导航页6、设置主题7、更改图标图标8、构建网站9、部署9.1 准备github项目9.2 注册登录Read the Docs9.3 导入github项目到 Read the Docs 10、Markdown语法10.1 横线10.2 标题10.3 段落10.4 文字高亮10.5 换行10.6 斜体…...

Python 中的短路评估

文章目录 Python 中的逻辑运算符or (或)运算符AND 运算符 什么是短路在 Python 中使用 AND 运算符进行短路在 Python 中使用 OR 运算符进行短路 本文是关于使用逻辑运算符在 Python 中显示短路行为。 Python 中的逻辑运算符 or (或)运算符 OR&#xff1a;两个操作数均使用 Py…...

LVGL源码分析(1):lv_ll链表的实现

在LVGL中难免需要用到链表&#xff1a;group中的对象需要用链表来存储&#xff0c;这样可以切换对象的焦点&#xff1b;再比如LVGL内部的定时器&#xff0c;多个定时器也是用链表进行存储的。这篇文章就来分析一下LVGL中链表的源码。 文章目录 1 链表结构体2 插入元素源码分析…...

js判断数据类型的几种方法及其局限性(typeof, instanceof, Object.prototype.toString.call())

​ js中判断了类型的方法有很多, 这篇文章主要来说一下常用的几种判断类型的方法,以及使用: 每个方法都各有优缺点,在日常使用的时候请结合这些优缺点进行斟酌: 1. 使用typeof判断数据类型 javaScript中typeof可以判断以下类型: undefined: 未定义的变量或者值 boolean: 布…...

【MySQL】一文带你掌握聚合查询和联合查询

文章目录 1. 聚合函数1.1 COUNT1.2 SUM1.3 AVG1.4 MAX&#xff0c;MIN 2. GROUP BY3. HAVING4. 联合查询4.1 内连接4.2 外连接4.3 自连接4.4 子连接 5.合并查询5.1 UNION5.2 UNION ALL 1. 聚合函数 概念&#xff1a; 聚合函数是一种用于处理数据集合的函数&#xff0c;它将多个…...

初步了解JVM

JVM 整体组成部分 类加载器 类加载过程 加载&#xff1a;使用IO读取字节码文件&#xff0c;转换并存储&#xff0c;为每个类创建一个Class对象&#xff0c;存储在方法区中 链接&#xff08;验证&#xff0c;准备&#xff0c;解析&#xff09; ​ 验证:对字节码文件格式进…...

嘀嗒陪诊小程序v1.0.8+小程序前端

嘀嗒陪诊小程序功能相对简单&#xff0c;后台也简捷&#xff0c;如果只是做个陪诊服务的小程序也基本能满足了&#xff0c;整体测试了下海参崴发现BUG&#xff0c;小程序端也能正常为使用&#xff0c;唯一用户授权接口是老的。 应用背景&#xff1a;人口老龄化少子化&#xff…...

Java中线程的生命周期

Java中线程的生命周期 Java中线程的声明周期与os中线程的生命周期不太一样&#xff0c;java中线程有6个状态&#xff0c;见下&#xff1a; NEW: 初始状态&#xff0c;线程被创建出来但没有被调用 start() 。RUNNABLE: 运行状态&#xff0c;线程被调用了 start()等待运行的状态…...

光线追踪RayTracing,基本原理,判断物体与光线相交

光线的三点假设&#xff1a; 光线按直线传播光线之间不会发生碰撞光线会经过一系列折射反射进入摄像机 可以从摄像机发出光线&#xff0c;推出可逆的光路 上图中&#xff0c;透明球在与相机直连的线条处&#xff0c;需要将折射和反射的着色点结果相加&#xff0c;如果有光源直…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !

我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...