简单实现接口自动化测试(基于python+unittest)
简介
本文通过从Postman获取基本的接口测试Code简单的接口测试入手,一步步调整优化接口调用,以及增加基本的结果判断,讲解Python自带的Unittest框架调用,期望各位可以通过本文对接口自动化测试有一个大致的了解。
引言
为什么要做接口自动化测试?
在当前互联网产品迭代频繁的背景下,回归测试的时间越来越少,很难在每个迭代都对所有功能做完整回归。但接口自动化测试因其实现简单、维护成本低,容易提高覆盖率等特点,越来越受重视。
为什么要自己写框架呢?
使用Postman调试通过过直接可以获取接口测试的基本代码,结合使用requets + unittest很容易实现接口自动化测试的封装,而且requests的api已经非常人性化,非常简单,但通过封装以后(特别是针对公司内特定接口),可以进一步提高脚本编写效率。
一个现有的简单接口例子
下面使用requests + unittest测试一个查询接口
接口信息如下
请求信息:
Method:POST
URL:api/match/image/getjson
Request:
{
"category": "image",
"offset": "0",
"limit": "30",
"sourceId": "0",
"metaTitle": "",
"metaId": "0",
"classify": "unclassify",
"startTime": "",
"endTime": "",
"createStart": "",
"createEnd": "",
"sourceType": "",
"isTracking": "true",
"metaGroup": "",
"companyId": "0",
"lastDays": "1",
"author": ""
}
Response示例:
{
"timestamp" : xxx,
"errorMsg" : "",
"data" : {
"config" : xxx
}
Postman测试方法见
测试思路
1.获取Postman原始脚本
2.使用requests库模拟发送HTTP请求**
3.对原始脚本进行基础改造**
4.使用python标准库里unittest写测试case**
原始脚本实现
未优化
该代码只是简单的一次调用,而且返回的结果太多,很多返回信息暂时没用,示例代码如下
import requestsurl = "http://cpright.xinhua-news.cn/api/match/image/getjson"querystring = {"category":"image","offset":"0","limit":"30","sourceId":"0","metaTitle":"","metaId":"0","classify":"unclassify","startTime":"","endTime":"","createStart":"","createEnd":"","sourceType":"","isTracking":"true","metaGroup":"","companyId":"0","lastDays":"1","author":""}headers = {'cache-control': "no-cache",'postman-token': "e97a99b0-424b-b2a5-7602-22cd50223c15"}response = requests.request("POST", url, headers=headers, params=querystring)print(response.text)
优化 第一版
调整代码结构,输出结果Json出来,获取需要验证的response.status_code,以及获取结果校验需要用到的results['total']
#!/usr/bin/env python
#coding: utf-8
'''
unittest merchant backgroud interface
@author: zhang_jin
@version: 1.0
@see:http://www.python-requests.org/en/master/
'''import unittest
import json
import traceback
import requestsurl = "http://cpright.xinhua-news.cn/api/match/image/getjson"querystring = {"category": "image","offset": "0","limit": "30","sourceId": "0","metaTitle": "","metaId": "0","classify": "unclassify","startTime": "","endTime": "","createStart": "","createEnd": "","sourceType": "","isTracking": "true","metaGroup": "","companyId": "0","lastDays": "1","author": ""
}headers = {'cache-control': "no-cache",'postman-token': "e97a99b0-424b-b2a5-7602-22cd50223c15"}#Post接口调用
response = requests.request("POST", url, headers=headers, params=querystring)#对返回结果进行转义成json串
results = json.loads(response.text)#获取http请求的status_code
print "Http code:",response.status_code#获取结果中的total的值
print results['total']
#print(response.text)
优化 第二版
接口调用异常处理,增加try,except处理,对于返回response.status_code,返回200进行结果比对,不是200数据异常信息。
#!/usr/bin/env python
#coding: utf-8
'''
unittest merchant backgroud interface
@author: zhang_jin
@version: 1.0
@see:http://www.python-requests.org/en/master/
'''import json
import traceback
import requestsurl = "http://cpright.xinhua-news.cn/api/match/image/getjson"querystring = {"category": "image","offset": "0","limit": "30","sourceId": "0","metaTitle": "","metaId": "0","classify": "unclassify","startTime": "","endTime": "","createStart": "","createEnd": "","sourceType": "","isTracking": "true","metaGroup": "","companyId": "0","lastDays": "1","author": ""
}headers = {'cache-control': "no-cache",'postman-token': "e97a99b0-424b-b2a5-7602-22cd50223c15"}try:#Post接口调用response = requests.request("POST", url, headers=headers, params=querystring)#对http返回值进行判断,对于200做基本校验if response.status_code == 200:results = json.loads(response.text)if results['total'] == 191:print "Success"else:print "Fail"print results['total']else:#对于http返回非200的code,输出相应的coderaise Exception("http error info:%s" %response.status_code)
except:traceback.print_exc()
优化 第三版
1.该版本改动较大,引入config文件,单独封装结果校验模块,引入unittest模块,实现接口自动调用,并增加log处理模块;
2.对不同Post请求结果进行封装,不同接口分开调用;
3.测试用例的结果进行统计并最终输出
#!/usr/bin/env python
#coding: utf-8
'''
unittest interface
@author: zhang_jin
@version: 1.0
@see:http://www.python-requests.org/en/master/
'''import unittest
import json
import traceback
import requests
import time
import result_statistics
import config as cf
from com_logger import match_Loggerclass MyTestSuite(unittest.TestCase):"""docstring for MyTestSuite"""#@classmethoddef sedUp(self):print "start..."#图片匹配统计def test_image_match_001(self):url = cf.URL1querystring = {"category": "image","offset": "0","limit": "30","sourceId": "0","metaTitle": "","metaId": "0","classify": "unclassify","startTime": "","endTime": "","createStart": "","createEnd": "","sourceType": "","isTracking": "true","metaGroup": "","companyId": "0","lastDays": "1","author": ""}headers = {'cache-control': "no-cache",'postman-token': "545a2e40-b120-2096-960c-54875be347be"}response = requests.request("POST", url, headers=headers, params=querystring)if response.status_code == 200:response.encoding = response.apparent_encodingresults = json.loads(response.text)#预期结果与实际结果校验,调用result_statistics模块result_statistics.test_result(results,196)else:print "http error info:%s" %response.status_code#match_Logger.info("start image_query22222")#self.assertEqual(results['total'], 888)'''try:self.assertEqual(results['total'], 888)except:match_Logger.error(traceback.format_exc())#print results['total']'''#文字匹配数据统计def test_text_match_001(self):text_url = cf.URL2querystring = {"category": "text","offset": "0","limit": "30","sourceId": "0","metaTitle": "","metaId": "0","startTime": "2017-04-14","endTime": "2017-04-15","createStart": "","createEnd": "","sourceType": "","isTracking": "true","metaGroup": "","companyId": "0","lastDays": "0","author": "","content": ""}headers = {'cache-control': "no-cache",'postman-token': "ef3c29d8-1c88-062a-76d9-f2fbebf2536c"}response = requests.request("POST", text_url, headers=headers, params=querystring)if response.status_code == 200:response.encoding = response.apparent_encodingresults = json.loads(response.text)#预期结果与实际结果校验,调用result_statistics模块result_statistics.test_result(results,190)else:print "http error info:%s" %response.status_code#print(response.text)def tearDown(self): passif __name__ == '__main__':#image_match_Logger = ALogger('image_match', log_level='INFO')#构造测试集合suite=unittest.TestSuite()suite.addTest(MyTestSuite("test_image_match_001"))suite.addTest(MyTestSuite("test_text_match_001"))#执行测试runner = unittest.TextTestRunner()runner.run(suite)print "success case:",result_statistics.num_successprint "fail case:",result_statistics.num_fail#unittest.main()
最终输出日志信息
Zj-Mac:unittest lazybone$ python image_test_3.py
测试结果:通过.测试结果:不通过
错误信息: 期望返回值:190 实际返回值:4522.
----------------------------------------------------------------------
Ran 2 tests in 0.889sOK
success case: 1
fail case: 1
后续改进建议
1.unittest输出报告也可以推荐使用HTMLTestRunner(我目前是对结果统计进行了封装)
2.接口的继续封装,参数化,模块化
3.unittest单元测试框架实现参数化调用第三方模块引用(nose-parameterized)
4.持续集成运行环境、定时任务、触发运行、邮件发送等一系列功能均可以在Jenkins上实现。

相关文章:
简单实现接口自动化测试(基于python+unittest)
简介 本文通过从Postman获取基本的接口测试Code简单的接口测试入手,一步步调整优化接口调用,以及增加基本的结果判断,讲解Python自带的Unittest框架调用,期望各位可以通过本文对接口自动化测试有一个大致的了解。 引言 为什么要…...
【算法|双指针系列No.4】leetcode11. 盛最多水的容器
个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 🍔本专栏旨在提高自己算法能力的同时,记录一下自己的学习过程,希望…...
数据结构全集介绍
以下列举了部分常见的数据结构: 数组(Array):数组是一种线性数据结构,可以用来存储固定大小的数据集合。在数组中,每个元素都有一个对应的索引,可以通过索引直接访问和更新元素。数组的优点是访…...
力扣刷题-字符串-反转字符串
344 反转字符串 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 你可以假设数组中的所有字符都是 ASCII 码表中…...
【CCNP】第七章 动态路由协议-BGP
第一节 BGP的基本概念 BGP(Border Gateway Protocol),边界网关协议 是运行在网络和网络之间的协议,是一款EGP(外部网关协议) BGP基于TCP协议工作,目的端口号179。源端口随机,由路由…...
java学习--day24(stream流)
文章目录 今天的内容1.Stream【难点】1.1获取流的对象1.2Stream流对象下面1.2.1count和forEach1.2.2filter方法1.2.3limit1.2.4map方法1.2.5skip1.2.6concat 1.3收集流 1.基于接口和抽象类的匿名内部类的写法 abstract class Person {public abstract void eat(); } public sta…...
Multi-Grade Deep Learning for Partial Differential Equations
论文阅读:Multi-Grade Deep Learning for Partial Differential Equations with Applications to the Burgers Equation Multi-Grade Deep Learning for Partial Differential Equations with Applications to the Burgers Equation符号定义偏微分方程定义FNN定义PI…...
Docker部署rustdesk
查看镜像版本 https://hub.docker.com/r/rustdesk/rustdesk-server/tags 拉取镜像 docker pull rustdesk/rustdesk-server:1.1.8-2创建挂载目录 mkdir -p /opt/rustdesk/{hbbr,hbbs}/root运行hbbs –nethost 仅适用于 Linux,它让 hbbs/hbbr 可以看到对方真实的…...
win1011安装MG-SOFT+MIB+Browser+v10b
文章目录 安装MG-SOFTSNMP服务配置安装MG-SOFT启动MIB-Browser以及错误解决MIB Browser使用 安装MG-SOFT win10和win11安装基本一样,所以参照下面的操作即可! SNMP服务配置 打开设置,应用和功能,可选功能,选择添加功…...
PCL点云处理之Pcd文件读取、法线与曲率计算、多线程加速、属性字段合并 (二百零八)
PCL点云处理之Pcd文件读取、法线与曲率计算、多线程加速、属性字段合并(二百零八) 一、相关介绍二、算法实现1.代码一、相关介绍 (夜深人不静) 法线和曲率的计算是点云处理中常用的关键特征,PCL提供了特有的点类型PointNormal来记录这些信息,通过OMP多线程对相关的计算函…...
JavaEE-文件IO操作
构造方法 一般方法,有很多,我们以下只是列举几个经常使用的 注意在上述的操作过程中,无论是绝对路径下的这个文件还是相对路径下的这个文件,都是不存在的 Reader 使用 --> 文本文件 FileReader类所涉及到的一些方法 Fil…...
二蛋赠书四期:《Go编程进阶实战:开发命令行应用、HTTP应用和gRPC应用》
前言 大家好!我是二蛋,一个热爱技术、乐于分享的工程师。在过去的几年里,我一直通过各种渠道与大家分享技术知识和经验。我深知,每一位技术人员都对自己的技能提升和职业发展有着热切的期待。因此,我非常感激大家一直…...
MySQL数据库基本操作-DQL-排序查询
介绍 如果我们需要对读取的数据进行排序,我们就可以使用 MySQL 的 order by 子句来设定你想按哪个字段哪种方式来进行排序,再返回搜索结果。 语法 select 字段名1,字段名2,…… from 表名 order by 字段名1 [asc|desc]…...
这是一篇测试文章
这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章…...
Ubuntu plt画图 新罗马字体网格marker刻度朝内
* 字体文件:坚果云下code包,新罗马字体 参考链接:Linux下Matplotlib画图New Times Roman字体设置 - 知乎 * 刻度朝内 plt.rcParams[font.sans-serif] [Times New Roman]plt.rcParams[xtick.direction]in#设置x轴刻度向内plt.rcParams[ytic…...
flutter布局中的一些细节
前言 记录flutter使用中遇到的一些细节和坑,希望能帮助到大家 Column中不能直接嵌套ListView, (需要指定ListView的高度或者加上shrinkWrap: true属性)需要限制button的大小,可以在外部嵌套一个Container或SizedBox来限制在List…...
论文解析——AMD EPYC和Ryzen处理器系列的开创性的chiplet技术和设计
ISCA 2021 摘要 本文详细解释了推动AMD使用chiplet技术的挑战,产品开发的技术方案,以及如何将chiplet技术从单处理器扩展到多个产品系列。 正文 这些年在将SoC划分成多个die方面有一系列研究,MCM的概念也在不断更新,AMD吸收了…...
第二证券:汽车产业链股活跃,恒勃股份、博俊科技“20cm”涨停
轿车产业链股9日盘中走势活跃,截至发稿,恒勃股份、博俊科技“20cm”涨停,德迈仕涨超17%,上声电子涨超14%,川环科技涨超10%,圣龙股份、科华控股、沪光股份、上海沿浦、日盈电子、赛力斯等均涨停。 工作方面…...
孙帅Spring源码
【视频来源于:B站up主孙帅suns Spring源码视频】【微信号:suns45】...
jenkins工具系列 —— 插件 使用Changelog获取commit记录
文章目录 安装changelog插件重启jenkins配置 ChangelogExecute shell 使用 changelog邮件中html格式也可以使用构建测试(查看构建项 -> 控制台输出) 安装changelog插件 插件文件可通过 V 获取 点击 左侧的 Manage Jenkins —> Plugins ——> …...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
