接口自动化框架搭建

article/2025/10/19 0:02:00

1.自动化测试流程

-- 需求分析。需求文档,接口文档,抓包接口

-- 测试计划。通常包含项目的进度,是否自动化,优先级

-- 测试用例(是从手工测试提取出来的)

-- 用例评审

-- 执行测试。(写代码)

-- 测试报告

接到项目之后,如何去进行需求分析:

1.需求文档,功能展示以及交互

2.接口文档,后端数据是怎么传输的

3.数据库账号,数据库地址,结构帮大家熟悉整个项目的轮廓,字段

4.测试环境,环境怎么搭建

5.原型图

测试计划:

通常是由测试经理或者项目经理来编写的

1.可行分析,是否要引入自动化,哪此场景引入自动化,哪此功能引入自动化,做自动化不是全量覆盖,不可能是所有用例都进行自动化,

2.风险因子,存在哪此风险

3.时间管控,主要是时间、技术、进度、优先级的管控

4.技术,使用什么技术(python、java),使用什么测试单元框架(unittest、pytest)

测试用例:

写到excel,手工测试用例,指的是全量的测试用例,不是自动化测试用例

案例:

通常来说,任何一个项目或是新功能,会先进行手工测试,也是要进行全量的用例编写

自动化测试主要包括:

1.冒烟测试:主流程是否能正常运行

2.回归测试:验证开发修复的bug是否正常,并没有引入新的bug

3.持续集成:一天要重复测试好几次

2.接口需求分析

接口文档:

-- 纸质(电子 )

-- open api,swagger(网站)

-- 什么都没有,全凭一张嘴(自己抓包)

通过抓包或postman调试工具来设计测试用例,预期结果

3.用例设计

用excel进行编写,最好是一个接口编写一个sheet页,这样好进行测试

注意json格式数据一定要规范,双引号,英文的逗号等

预期结果可以使用postman调试工具来获取

4.编写自动化测试用例函数

领导丢给你一个自动化测试计划

先不要着急做到十全十美,第一步是验证你的自动化测试程序是否能正常运行

先把功能实现

写一个单独的自动化测试用例函数。以test_开头,需要有请求发送,得到响应结果,断言,生成测试报告

新建一个test_register.py,代码如下:

import unittest
import requestsclass TestRegister(unittest.TestCase):def test_register_01(self):'''步骤:1.准备测试数据2.发送接口请求,得到实际结果3.预期结果和实际结果的断言'''# 1.准备测试数据url = 'http://api.lemonban.com:8766/futureloan/member/register'method = 'post'headers = {'X-Lemonban-Media-Type': 'lemonban.v2'}json_data = {"mobile_phone": "", "pwd": "12345678"}expected = {"code": 1,"msg": "手机号为空","data": None,"copyright": "Copyright 柠檬班 © 2017-2019 湖南省零檬信息技术有限公司 All Rights Reserved"}# 2.发送接口请求,得到实际结果response = requests.request(method=method,url=url,headers=headers,json=json_data)actual = response.json()# 3.预期结果和实际结果的断言self.assertEqual(expected,actual)
# 有多少条用例就可以写多少个自动化测试函数,这里就不写所有的了

新建一个run.py来收集用例,运行用例,代码如下:

import unittest
import unittestreport# 收集测试用例
suite = unittest.defaultTestLoader.discover('tests')
# 生成测试报告
runner = unittestreport.TestRunner(suite)
runner.run()

运行结果:

有了以上的基础后,我们可以引入ddt,优化下测试用例函数,降低代码重复率。

ddt适用的场景:不同的数据,测试步骤是一样的

之前有一章是讲框架搭建,然后我们创建的共同的包可以拿来直接使用Python框架模型搭建_晒不黑的黑煤球的博客-CSDN博客

Python项目路径_晒不黑的黑煤球的博客-CSDN博客

直接复制之前的common,config,data包来用,

注意:第一点:设置根目录,第二点:将data目录里的数据更换成新建的excel表格

主要是用到excel.py,config.py

excel.py代码如下:

from openpyxl import load_workbookdef read_excel(file_name, sheet_name):wb = load_workbook(file_name)sheet = wb[sheet_name]data = list(sheet.values)titles = data[0]rows = [dict(zip(titles, row)) for row in data[1:]]return rows

config.py代码如下:

import os# 获取config.py当前文件的路径
curren_path = os.path.abspath(__file__)
# 配置文件目录的路径
config_dir = os.path.dirname(curren_path)
# config包的路径
cf_dir = os.path.dirname(config_dir)
# 拼接出data的路径
data_dir = os.path.join(cf_dir, 'data')
# 拼接出测试用例cases.xlsx的路径
cases_dir = os.path.join(data_dir, 'cases.xlsx')
# host地址
host = 'http://api.lemonban.com:8766'

因为测试跟开发环境不是同一个,会经常替换,所以把host写到配置文件里,这样方便操作,不用修改excel表格中的每一条

新建一个test_register_ddt.py,代码如下:

import unittest
import requests
import json
from common.excel import read_excel
from config import config
from ddt import ddt,data
from common.logger import log# 得到测试数据
excel_data = read_excel(file_name=config.cases_dir, sheet_name='register')@ddt
class TestRegister(unittest.TestCase):@data(*excel_data)def test_register(self,info):'''步骤:1.准备测试数据2.发送接口请求,得到实际结果3.预期结果和实际结果的断言'''# 1.准备测试数据log.info(f'正在测试{info}')# 要把配置文件的host跟取出来excel表中的url进行拼接url = config.host + info['url']method = info['method']# 将json格式字符串转化成字典,因为requests.request需要字典格式headers = json.loads(info['headers'])json_data = json.loads(info['json'])expected = json.loads(info['expected'])# 2.发送接口请求,得到实际结果response = requests.request(method=method, url=url,headers=headers, json=json_data)actual = response.json()# 3.预期结果和实际结果的断言self.assertEqual(expected, actual)

运行结果:

总结:

调试过程:

1.首先程序报错,从报错信息中查看error  message:Invalid URL '/futureloan/member/register': No schema supplied

2.找到报错行,报错信息中哪个文件是你写的,行号,跳到行号

3.如果有多个文件是自己编写的,行号都找出来

4.哪一行出错,就在哪一行设置断点,通过debug调试

5.分层思想

tests/:存储自动化用例

common/:通用模块

logs/:保存日志文件

data/:保存测试数据,excel文件

setting/:配置文件

reports/:保存测试报告

run.py:收集用例,运行用例,生成测试报告

6.注册接口测试优化

6.1测试报告展示不覆盖

通过时间戳来解决测试报告不覆盖问题

使用BeautifulReport生成测试报告

import unittest
from BeautifulReport import BeautifulReport
from datetime import datetime# 收集测试用例
suite = unittest.defaultTestLoader.discover('tests')
# 生成测试报告
'''默认的report.html需要改成report-2021-10-26-13-10.html
如何生成文件名
1.获取现在的时间戳 ts = 2021-10-26-13-10
2.字符串拼接f'report-{ts}.html'
3.字符串拼接f'reports/report-{ts}.html'
'''
# 获取时间戳
ts = datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
# 拼接文件目录
filename = f'reports/report-{ts}.html'
runner = BeautifulReport(suite)
runner.report('测试报告',filename=filename)

运行结果:

 使用unnittestreport生成测试报告

import unittest
import unittestreport
from datetime import datetime# 收集测试用例
suite = unittest.defaultTestLoader.discover('tests')
# 生成测试报告
ts = datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
filename = f'report-{ts}.html'
runner = unittestreport.TestRunner(suite, filename=filename)
runner.run()

 运行结果:

注意:unnittestreport生成的报告会自动创建reports目录,因此filename = f'report-{ts}.html'不需要手动添加reports目录,但BeautifulReport需要手动添加

 

可以看到每次运行一次run.py,就会生成一个当前系统时间命名的.html文件

6.2注册的手机号码生成

方案1:手工把手机号+1,运营商(号段)不支持,或者造成跟别人的号码冲突

方案2:数据库清掉,最好不要清库,不一定有数据库删除权限

方案3:使用第三方库faker来伪造手机号码,使用前需要安装pip install faker

faker用法,安装后一定要导入

from faker import Faker# 生成手机号
# 不填写locale=['zh-cn'],得到是国外的手机号码
faker = Faker()
print(faker.phone_number())
# 得到是中国的手机号码
faker = Faker(locale=['zh-cn'])
print(faker.phone_number())
# 得到一个地址
print(faker.address())
# 得到一个公司名
print(faker.company())
# 得到一个人的姓名
print(faker.name())
# 得到一个身份证号
print(faker.ssn())

运行结果:

218.367.2113
13910723249
河南省玉珍市高港杨街U座 326239
通际名联网络有限公司
张涛
230403194705041796

接着来搞一下动态数据替换,修改之前编写过的代码

把伪造手机号封装成一个函数,方便调用,新建一个phone_number.py放在common目录下

phone_number.py代码如下:

from faker import Fakerdef mobile_phone():faker = Faker(locale=['zh-cn'])return faker.phone_number()

修改测试用例内容:

需要伪造手机号的地方做个标记

修改test_register_ddt.py代码如下:

import unittest
import requests
import json
from common.excel import read_excel
from config import config
from ddt import ddt, data
from common.logger import log
from common.phone_number import mobile_phone# 得到测试数据
excel_data = read_excel(file_name=config.cases_dir, sheet_name='register')@ddt
class TestRegister(unittest.TestCase):@data(*excel_data)def test_register(self, info):'''步骤:1.准备测试数据2.发送接口请求,得到实际结果3.预期结果和实际结果的断言'''# 1.准备测试数据log.info(f'正在测试{info}')# 要把配置文件的host跟取出来excel表中的url进行拼接url = config.host + info['url']method = info['method']# 将json格式字符串转化成字典,因为requests.request需要字典格式headers = json.loads(info['headers'])# json_data不需要反序列化,因为后面需要用str数据类型json_data = info['json']# 检测:如果json_data中存在某个标记,就说明需要我自动生成一个手机号码# 调用 mobile_phone()函数# 把替换后的新手机号再赋值给json_data,因为得到的新字符串需要变量接收if "#mobile_phone#" in json_data:mobile = mobile_phone()json_data = json_data.replace("#mobile_phone#", mobile)json_data = json.loads(json_data)expected = json.loads(info['expected'])# 2.发送接口请求,得到实际结果response = requests.request(method=method, url=url,headers=headers, json=json_data)actual = response.json()# 3.预期结果和实际结果的断言self.assertEqual(expected, actual)

从运行结果可以看到最后一条用例还是失败了,那是因为id,mobile_phone字段的预期结果与实际结果是不一致。对于一些动态的字段值,我们无法提前获得,所以这就是全量断言的缺点。解决此问题就需要使用部分断言

6.3全量断言和部分断言

全量断言:一个字都不能差,麻烦

总分断言:提取有用的关键字段进行断言。如code,msg等。实战当中使用部分断言

修改测试用例中的expected内容

部分断言多种方法可以使用:

修改test_register_ddt.py代码如下:

import unittest
import requests
import json
from common.excel import read_excel
from config import config
from ddt import ddt, data
from common.logger import log
from common.phone_number import mobile_phone# 得到测试数据
excel_data = read_excel(file_name=config.cases_dir, sheet_name='register')@ddt
class TestRegister(unittest.TestCase):@data(*excel_data)def test_register(self, info):'''步骤:1.准备测试数据2.发送接口请求,得到实际结果3.预期结果和实际结果的断言'''# 1.准备测试数据log.info(f'正在测试{info}')# 要把配置文件的host跟取出来excel表中的url进行拼接url = config.host + info['url']method = info['method']# 将json格式字符串转化成字典,因为requests.request需要字典格式headers = json.loads(info['headers'])# json_data不需要反序列化,因为后面需要用str数据类型json_data = info['json']# 检测:如果json_data中存在某个标记,就说明需要我自动生成一个手机号码# 调用 mobile_phone()函数# 把替换后的新手机号再赋值给json_data,因为得到的新字符串需要变量接收if "#mobile_phone#" in json_data:mobile = mobile_phone()json_data = json_data.replace("#mobile_phone#", mobile)json_data = json.loads(json_data)expected = json.loads(info['expected'])# 2.发送接口请求,得到实际结果response = requests.request(method=method, url=url, headers=headers, json=json_data)actual = response.json()# 3.预期结果和实际结果的断言# V1版本:一个字段断言# self.assertEqual(expected['msg'], actual['msg'])# V2版本:使用for循环遍历expected中的字段for key, value in expected.items():self.assertEqual(value, actual[key])# # V3版本:多个字段分别断言,V2版本不理解可以使用V3版本,好理解# self.assertEqual(expected['msg'], actual['msg'])# self.assertEqual(expected['code'], actual['code'])

 运行结果:

从结果可以看到解决了全量断言带来的用例失败问题

7.扩展内容

7.1测试金字塔

从上往下依次是单元测试,服务/接口测试(后端),UI测试(前端),系统测试(前端,后端通常都测了,也就是俗称的手工测试点点点)

左边的乌龟和兔子代表的意思是速度:越接近顶端,速度越慢,越接近低端,速度越快

右边代表的意思是成本:越接近顶端,成本越高,越接近低端,成本越低

7.2什么样的项目合适做自动化测试

  • 需求稳定,不会频繁变更(项目初期不太适合)
  • 研发和测试周期长,需要频繁执行回归测试(搞活动)
  • 需要在多种平台上重复运行相同测试的场景
  • 某些测试项目通过手工测试无法实现,或者手工成本太高
  • 被测软件的开发较为规范,能够保证系统的可测试行

7.3图片验证码

测试接口时,遇到图片验证码的问题,该怎么解决?

  • 找开发直接关掉验证码的功能
  • 找开发要万能的验证码
  • 对接第三方的平台(超级鹰)
  • 代码的方式去实现(字母识别(OCR)图像识别,图像处理,机器学习(AI))过程比较复杂。而且使用了这些功能也不一定能识别的出来,如12306登录页面的图片验证(专门的爬虫工程师都不好搞出来)

http://chatgpt.dhexx.cn/article/gk8pbnRB.shtml

相关文章

2023最全自动化测试框架讲解,不会真不行!

无论是在自动化测试实践,还是日常交流中,经常听到一个词:框架。之前学习自动化测试的过程中,一直对“框架”这个词知其然不知其所以然。 最近看了很多自动化相关的资料,加上自己的一些实践,算是对“框架”…

【测试开发】几种常见的自动化测试框架

几种常见的自动化测试框架 在软件测试领域,自动化测试框架有很多,这里主要介绍几种常用的自动化测试框架。 1.pytest pytest 是 Python 的一种单元测试框架,与 Python 自带的 unittest 测试框架类似,但是比 unittest 框架使用起…

【自动化框架】

自动化测试框架就是:为了对一个指定的系统做自动化测试而封装的一个半成品,自动化测试攻城狮可以调用这个半成品封装好的方法去实现一个指定系统的自动化测试。 根据驱动模式不同自动化测试框架分为四种模式: (1) 数据驱动框架 (2) 关键字…

常见的主流自动化测试框架,这5种能帮到你很多

今天我们要向大家介绍的是常见5种主流自动化测试框架,包括优缺点等内容,供大家参考学习。 1.ATF 自动化测试框架AutoTestFramework是B/S架构框架,可实现Selenium等多种自动化测试全流程、团队化管理的高级框架平台,通过集成自动化…

【自动化测试】自动化测试框架与工具

文章目录 1)什么是自动化测试框架?1.1 什么是框架?1.2 什么是自动化测试框架?1.2.1 优点:1.2.2 框架的基本组件1、需要配置文件管理:2、业务逻辑代码和测试脚本分离3、报告和日志文件输出4、自定义的库的封…

从零搭建完整python自动化测试框架(UI自动化和接口自动化 )——持续更新

本自动化测试框架采用python unittest 的基础来搭建,采用PO模式、数据驱动的思想,通过selenium来实现WEB UI自动化,通过request来实现接口自动化。移动终端的自动化也可在该框架基础上去构建补充。 目录 总体框架PO模式、DDT数据驱动、关键字…

Linux必备的小技巧——查看历史操作和屏显信息

通常在linux查看历史操作信息,都是查看日志文件,Linux的日志文件一般都保存在/var/log文件夹下: 用如下命令即可查看: cat filename 查看日志,会打开整个文件,直接跑到最后面tac filena…

linux下安装CUDA和cudnn

linux下安装CUDA和cudnn 2、安装CUDA10.1 在CUDA官网选择系统对应的版本下载CUDA 我的系统是Ubuntu18.04 64位,我选择下载最新版本的CUDA10.1: 输入以下命令安装CUDA sudo sh cuda_10.1.105_418.39_linux.run 显卡驱动已在上面安装了,这里一…

Linux和其他操作系统的区别

前言 这是我听老师讲课做的笔记,考试要看的。 这是视频地址 作者:RodmaChen 关注我的csdn博客,更多Linux笔记知识还在更新 为什么用Liunx系统 Linux和windows的区别Linux和Unix操作系统的区别 Linux和windows的区别 1.免费与收费 Windows 平台: Window…

linux下如何查看驱动?(CH341)

文章目录 背景命令 背景 Linux下有时候我们在接上串口后,在/dev/下找不到ttyUSB*,这时我们需要查看下本机是否安装了相应的驱动。 命令 lsmod | grep ch341 如上图,便是表示目前pc中存在ch341驱动,无需重新安装。

linux怎么查询数据库端口,linux下怎么查看数据库端口

满意答案 ai_yuming 2017.08.26 采纳率:50% 等级:8 已帮助:759人 如何查看mysql 默认端口号和修改端口号 1. 登录mysql [root@test /]# mysql -u root -p Enter password: 2. 使用命令show global variables like port;查看端口号 mysql> show global variables like …

Linux的历史背景和基本指令

众所周知,Linux和大家所熟悉的Windows一样,也是一款操作系统,不同的更多是在于Windows是闭源的,而Linux是开源的。现代生活中的比如飞机的控制系统、银行的系统、手机的系统等等,都和Linux操作系统相关,所以…

Linux安装围棋AI(q5go和katago)

最近一个多月开始学习围棋,因为平时常用的系统是Linux,所以想要在Linux上安装一个围棋AI,可以借助AI分析棋局。经过一番查找,决定使用q5go和katago,安装还是挺复杂的,特地记录(/摸鱼&#xff09…

Linux 常用命令 查看 CPU 信息

强力推荐-不要错过,万一能帮助到自己呢? 推荐一个网站,关于人工智能教程,教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家。点这里…

Linux命令查看Linux服务器内存、CPU、显卡、硬盘使用情况

查看内存使用情况 使用命令: free -m 大致结果类似下图: 内存占用情况 参数解释: Mem行(单位均为M): total:内存总数used:已使用内存数free:空闲内存数shared&…

Ai-WB2系列模组linux开发环境搭建

文章目录 一、Ubuntu安装1.1 安装VMware Workstation Pro1.2 安装Ubuntu 二、编译三、烧录固件到设备3.1 方式一:用命令行烧录3.2 方式二:用可视化软件烧录(windows) 三、自定义工程如何修改Makefile四、开发资料 一、Ubuntu安装 …

用js动态显示当前时间

用setTimeout动态显示当前时间&#xff1a; <div class"showTime"></div> <script>var t null;tsetTimeout(time,1000);//开始运行function time(){clearTimeout(t);//清除定时器dt new Date();var y dt.getFullYear();var mt dt.getMonth()1…

js 获取当前gmt时间_javascript怎么获取当前时间?

javascript怎么获取当前时间&#xff1f;下面本篇文章就来给大家介绍一下使用javascript获取当前时间的方法&#xff0c;希望对大家有所帮助。 在JavaScript中可以使用Date对象中的Date()方法来获取当前时间。Date 对象用于处理日期和时间&#xff0c;Date()方法可返回当天的日…

【JavaScript】动态显示当前时间

可以实现动态显示当前时间&#xff0c;年月日时分秒星期几等&#xff0c;用12小时制表示&#xff0c;并能根据时间显示am&#xff08;上午&#xff09;&#xff0c;pm&#xff08;下午&#xff09;。 文章目录 一、基础知识二、动态显示系统当前时间1.代码2.展现效果 一、基础知…

用js显示当前时间

目录 以下是我全部代码 其中&#xff0c;关键代码是js 效果如图所示 关键代码解释如下 setInterval: getElementById: innerHTML: 在初步学习js时&#xff0c;可能会有一些朋友能用上js来显示时间&#xff0c;因此我在此提供一种方法供大家参考。 以下是我全部代码 <…