金融项目实战 05|Python实现接口自动化——登录接口
目录
一、代码实现自动化理论及流程
二、脚本实现的理论和准备工作
1、抽取功能转为自动化用例
2、搭建环境(测试工具)
3、搭建目录结构
三、登录接口脚本实现
1、代码编写
1️⃣api目录
2️⃣script目录
2、断言
3、参数化
1️⃣编写数据存储文件:json文件
2️⃣编写读取数据工具:read_json()
3️⃣参数化引用:parameterize
一、代码实现自动化理论及流程
🔴代码编写脚本和工具实现脚本区别是什么?
- 代码:
- 优点:代码灵活方便
- 缺点:学习成本高
- 工具:
- 优点:易上手
- 缺点:灵活度低,有局限性。
- 总结:
- 功能脚本:工具
- 自动化脚本:代码
🔴代码接口自动化怎么做的?
- 第一步:(概述)python+request+unittest;
- 第二步:(具体描述)封装、调用、数据驱动、日志、报告;
- 第三步:(举例)api\scripts\data\log\report\until\...;
二、脚本实现的理论和准备工作
使用代码编写自动化脚本的流程:
- 1、抽取功能用例转为自动化⽤例。
- 2、搭建环境(测试工具相关的)
- 3、搭建目录结构
- 4、编写脚本
- 5、执行脚本
- 6、配置持续集成
1、抽取功能转为自动化用例
去掉了有bug的用例、以及“请求后台投资响应失败(密码为空)”的用例(改用例需要借钱和投资双方私下协商密码)
2、搭建环境(测试工具)
①python、pycharm、requests、pymysql、parametrize
②jenkins、jdk
提示:由于编写的自动化脚本,而自动化脚本编写之前功能已测试完毕,所以不需要在单独搭建项目环境。
3、搭建目录结构
三、登录接口脚本实现
1、代码编写
1️⃣api目录
把需要测的接口放在该目录

url设置成私有变量,只能在该类内部调用。
此处这样做只是因为url实际上只会在该登陆注册模块内部使用,外面没必须用到,设置私有,外部调用方法的时候。看着干净
from config import HOSTclass ApiRegisterLogin:# 有几个接口就封装几个方法#初始化def __init__(self, session):# 获取session对象self.session = session# 图片url# 图片验证码urlself.__url_img_code = HOST + "/common/public/verifycode1/{}"# 短信验证码urlself.__url_phone_code = HOST + "/member/public/sendSms"# 注册Lr1self.__url_register = HOST + "/member/public/reg"# 登录urlself.__url_login = HOST + "/member/public/login"# 登录状态urlself.__url_login_status = HOST + "/member/public/islogin"# url# 1、获取图⽚验证码接⼝ 封装def api_img_code(self,random):return self.session.get(url=self.__url_img_code.format(random))# 2、获取短信验证码接⼝ 封装def api_phone_code(self,phone,imgVerifyCode):data = {"phone": phone,"imgVerifyCode": imgVerifyCode,"type": "reg"}return self.session.post(url=self.__url_phone_code,data=data)# 3、注册接⼝ 封装def api_register(self,phone,password,verifycode,phone_code):data = {"phone": phone,"password": password,"verifycode": verifycode,"phone_code": phone_code,"dy_server": "on","invite_phone": ""}return self.session.post(url=self.__url_register,data=data)# 4、登录接⼝ 封装def api_login(self,keywords,password):data = {"keywords": keywords,"password": password}return self.session.post(url=self.__url_login, data=data)# 5、查询登录状态接⼝ 封装def api_login_status(self):return self.session.post(url=self.__url_login_status)
2️⃣script目录
调用封装的接口,开展测试工作
下面测试用例的内容目前只是测试一下api文件中封装的接口能不能用,后面还要改。
import unittestimport requestsfrom api.api_register_login import ApiRegisterLoginclass TestRegisterLogin(unittest.TestCase):# 初始化def setUp(self) -> None:# 获取session对象self.session =requests.Session()# 获取ApiRegisterLogin实例self.reg = ApiRegisterLogin(self.session)# 结束def tearDown(self) -> None:# 关闭session对象self.session.close()#1、获取图片验证码接口 测试def test01_img_code(self):# 调用图片验证码接口r = self.reg.api_img_code(234)# 查看响应状态码print(r.status_code)#2、获取短信验证码接口 测试def test02_phone_code(self,phone=17612341111,imgVerifyCode=8888):# 1、调用获取图片验证码接口 -- 目的:让session对象记录cookie# 调用接口后session会自动记录cookieself.reg.api_img_code(234)# 2、调用短信验证码接口r = self.reg.api_phone_code(phone=phone,imgVerifyCode=imgVerifyCode)# 3、查看响应结果print(r.json())#3、注册接口 测试def test03_register(self,phone=17612341111,imgVerifyCode=8888,password="win56",phone_code=666666):# 1、图片验证码接口self.reg.api_img_code(234)# 2、短信验证码接口self.reg.api_phone_code(phone=phone, imgVerifyCode=imgVerifyCode)# 3、注册接口r = self.reg.api_register(phone=phone,password=password,verifycode=imgVerifyCode,phone_code=phone_code)# 4、查看结果print(r.json())#4、登录接口 测试def test04_login(self,keywords=17612341111,password="win56"):# 1、调用登录r = self.reg.api_login(keywords=keywords,password=password)# 2、查看结果print(r.json())#5、查询登录状态接口 测试def test05_login_status(self):# 调用登录擦口self.reg.api_login(keywords=17612341111, password="win56")# 调用查询登录状态接口r = self.reg.api_login_status()# 看结果print(r.json())
2、断言
说明:判断程序执⾏实际结果是否符合预期结果
示例:
实际需要将api_register_login.py中的每个测试用例都做异常处理,下面只是以查询登录接口中的异常捕获为例。
中的完整代码后续补充。
try:# 调⽤登录接⼝self.reg.api_login(keywords="13600001111", password="test123")# 调⽤查询登录状态接⼝r = self.reg.api_login_status()# 看结果self.assertIn(expect_text, r.text)
except Exception as e:# ⽇志print(e)# 抛异常raise # 提示:捕获异常的⽬的是为了将错误信息记录下来,捕获信息完成后,必须抛出异常
【提示】:捕获异常的目的是为了将错误信息记录下来,捕获信息完成后,必须抛出异常
3、参数化
步骤:
- 1、编写数据存储⽂件 json
- 2、编写读取⼯具⽅法 read_json()
- 3、使⽤参数化组件进⾏引⽤ parametrize
1️⃣编写数据存储文件:json文件
心得:
1、根据模块来新建json文件(1个模块1个json⽂件)
2、最外侧使用{},模块下几个接口,编写几个key,值为列表
3、列表值中,有几组数据,就写几个{}
4、每组数据{}中,组成格式:说明+参数+预期结果
{"img_code": [{"desc": "获取图片验证码成功(随机小数)","random": 0.123,"expect_code": 200},{"desc": "获取图片验证码成功(随机整数)","random": 123,"expect_code": 200},{"desc": "获取图片验证码失败(随机数为空)","random": "","expect_code": 404},{"desc": "获取图片验证码失败(随机数为字符串)","random": "123hello","expect_code": 400}],"phone_code": [{"desc": "获取短信验证码成功","phone": "13600001111","imgVerifyCode": 8888,"expect_text": "发送成功"},{"desc": "获取短信验证码成功","phone": "13600001111","imgVerifyCode": 8889,"expect_text": "验证码错误"}],"register": [{"desc": "注册成功(必填参数)","phone": 13600001111,"password": "test123","verifycode": 8888,"phone_code": 666666,"expect_text": "注册成功"},{"desc": "注册失败(图片验证码错误)","phone": 13600001112,"password": "test123","verifycode": 8889,"phone_code": 666666,"expect_text": "验证码错误"},{"desc": "注册失败(短信验证码错误)","phone": 13600001112,"password": "test123","verifycode": 8888,"phone_code": 666667,"expect_text": "验证码错误"},{"desc": "注册失败(手机号已存在)","phone": 13600001111,"password": "test123","verifycode": 8888,"phone_code": 666666,"expect_text": "已存在"}],"login": [{"desc": "登录成功","keywords": 13600001111,"password": "test123","expect_text": "登录成功"},{"desc": "登录失败(密码为空)","keywords": 13600001111,"password": "","expect_text": "不能为空"},{"desc": "登录失败(解锁)","keywords": 13600001111,"password": "error123","expect_text": "登录成功"}],"login_status": [{"desc": "查询登录状态(已登录)","status": "已登录","expect_text": "OK"},{"desc": "查询登录状态(已登录)","status": "未登录","expect_text": "未登"}]
}
2️⃣编写读取数据工具:read_json()
import json
import osfrom config import DIR_PATHdef read_json(filename,key):# 拼接读取文件的完整路径# os.sep是动态获取/ \filepath = DIR_PATH + os.sep + "data" + os.sep +filenamearr = []with open(filepath,"r",encoding="utf-8") as f:for data in json.load(f).get(key):arr.append(list(data.values())[1:])return arrif __name__ == '__main__':# 测试一下能不能读取到数据print(read_json("register_login.json","img_code")) # 读取的数据为:[[0.123, 200], [123, 200], ['', 404], ['123hello', 400]]
3️⃣参数化引用:parameterize
难点1:错误次数锁定
难点2: 查询登录状态,不同结果。
【注意】由于parameterized的自身bug,运行测试用例必须是点击到测试用例所在的类名右键运行。如果想单独运行某个接口用例,则把其他接口代码先注释掉。
import unittest
from time import sleepimport requestsfrom api.api_register_login import ApiRegisterLoginfrom parameterized import parameterizedfrom util import read_jsonclass TestRegisterLogin(unittest.TestCase):# 初始化def setUp(self) -> None:# 获取session对象self.session =requests.Session()# 获取ApiRegisterLogin实例self.reg = ApiRegisterLogin(self.session)# 结束def tearDown(self) -> None:# 关闭session对象self.session.close()#1、获取图片验证码接口 测试@parameterized.expand(read_json("register_login.json","img_code"))def test01_img_code(self,random,expect_code):try:# 调用图片验证码接口r = self.reg.api_img_code(random)# 查看响应状态码# print(r.status_code)self.assertEqual(expect_code,r.status_code)except Exception as err:# 日志print(err)# 抛异常raise#2、获取短信验证码接口 测试@parameterized.expand(read_json("register_login.json", "phone_code"))def test02_phone_code(self,phone,imgVerifyCode,expec_text):try:# 1、调用获取图片验证码接口 -- 目的:让session对象记录cookie# 调用接口后session会自动记录cookieself.reg.api_img_code(234)# 2、调用短信验证码接口r = self.reg.api_phone_code(phone=phone,imgVerifyCode=imgVerifyCode)# 3、查看响应结果# print(r.json())self.assertIn(expec_text,r.text) # 使用text提取结果是更方便,json还要根据键找值except Exception as err:# 日志print(err)# 抛异常raise#3、注册接口 测试@parameterized.expand(read_json("register_login.json", "register"))def test03_register(self,phone,password,imgVerifyCode,phone_code,expec_text):try:# 1、图片验证码接口self.reg.api_img_code(234)# 2、短信验证码接口self.reg.api_phone_code(phone=phone, imgVerifyCode=imgVerifyCode)# 3、注册接口r = self.reg.api_register(phone=phone,password=password,verifycode=imgVerifyCode,phone_code=phone_code)# 4、查看结果# print(r.json())self.assertIn(expec_text,r.text)except Exception as err:# 日志print(err)# 抛异常raise#4、登录接口 测试@parameterized.expand(read_json("register_login.json", "login"))def test04_login(self,keywords,password,expec_text):try:i = 0r = Noneif "error" in password:while i <3:r=self.reg.api_login(keywords,password)i+=1# 锁定断言print("账号密码输错3次,账号锁定:",r.text)self.assertIn("锁定",r.text)# 暂停60秒sleep(60)r = self.reg.api_login(keywords=17612341111, password="win56")self.assertIn(expec_text,r.text)else:# 1、调用登录r = self.reg.api_login(keywords,password)# 2、查看结果# print(r.json())self.assertIn(expec_text, r.text)except Exception as err:# 日志print(err)# 抛异常raise#5、查询登录状态接口 测试@parameterized.expand(read_json("register_login.json", "login_status"))def test05_login_status(self,status,expec_text):try:if status == "已登录":# 调用登录擦口self.reg.api_login(keywords=17612341111, password="win56")# 调用查询登录状态接口r = self.reg.api_login_status()# 看结果# print(r.json())self.assertIn(expec_text, r.text)except Exception as err:# 日志print(err)# 抛异常raise
【总结】目前为止已经写的文件,文件内容上面均给出了代码
相关文章:

金融项目实战 05|Python实现接口自动化——登录接口
目录 一、代码实现自动化理论及流程 二、脚本实现的理论和准备工作 1、抽取功能转为自动化用例 2、搭建环境(测试工具) 3、搭建目录结构 三、登录接口脚本实现 1、代码编写 1️⃣api目录 2️⃣script目录 2、断言 3、参数化 1️⃣编写数据存储文件:jso…...

《HTML在网络安全中的多面应用:从防范攻击到安全审查》
Html基础 Html简介 HTML(HyperText Markup Language,超文本标记语言)是用于描述网页内容和结构的标准语言。以下是对HTML的简要介绍: 基本概念 定义: HTML不是一种编程语言,而是一种标记语言。 它使用标…...

Linux网络 | 学习传输层网络协议之UDP(短篇)
前言: 本节内容正式迈入传输层网络协议的知识殿堂, 之前的文章, 我们都是在应用层进行翻来覆去。 比如http就是应用层协议, 只不过使用了tcp的系统调用。 从本节开始, 友友们将会学习传输层两大协议: UDP和…...
iOS - 内存屏障的使用场景
内存屏障的使用是为了解决以下几个关键问题: 1. CPU 乱序执行 // 没有内存屏障时,CPU 可能乱序执行 void example() {// 这两行代码可能被 CPU 重排序a 1; // 操作1flag true; // 操作2 }// 使用内存屏障确保顺序 void safeExample() {a 1;…...
MySQL 8.0 新特性详解与实用示例
MySQL 8.0 新特性详解与实用示例 1. 引言 MySQL 8.0 是 MySQL 版本系列中具有里程碑意义的更新版本,带来了大量新功能和优化,极大地提升了数据库的性能和可用性。本文将深入介绍 MySQL 8.0 的主要新特性及其应用场景,帮助你在项目中更高效地…...

【STM32-学习笔记-5-】ADC
文章目录 ADCADC函数Ⅰ、ADC_InitTypeDef结构体参数①、ADC_Mode②、ADC_DataAlign③、ADC_ExternalTrigConv④、ADC_ContinuousConvMode⑤、ADC_ScanConvMode⑥、ADC_NbrOfChannel Ⅱ、ADC配置示例1、单次转换,非扫描单次转换非扫描模式下,获取多通道的…...

TY1801 反激变换器PWM GaN功率开关
TY1801 是一款针对离线式反激变换器的多模式 PWM GaN 功率开关。TY1801 内置 GaN 功率管,它具备超宽 的 VCC 工作范围,非常适用于 PD 快充等要求宽输出电压的应用场合,系统不需要使用额外的绕组或外围降压电路,节省系统 BOM 成本。TY1801 支持 Burst&…...

Jenkins安装、插件下载及构建环境配置详解
Jenkins简介 1.1 简介 Jenkins 是一个基于Java开发的开源持续集成工具,它提供了一个开放且易用的软件平台,主要用于自动化构建、测试和部署软件项目,以实现持续集成(CI)和持续交付/部署(CD)。…...
ESP32,uart安装驱动uart_driver_install函数剖析,以及intr_alloc_flags 参数的意义
在 uart_driver_install 函数中,参数 RX_BUF_SIZE * 2 指定了接收缓冲区(RX buffer)的大小。这个参数对于 UART 驱动程序来说非常重要,因为它决定了可以存储多少接收到的数据,直到应用程序读取它们为止。下面是对该函数…...
Ubuntu把应用程序放到桌面
有时候我们下载的软件是一个文件夹,通常需要进入进入指定文件夹下去执行.sh 文件来启动,下面来个实例如何把idea放到桌面 打开文件目录/usr/share/applications/或者~/.local/share/applications/目录。第一个目录是全局的,所有用户都可以使…...
什么是端口映射
端口映射 端口映射(Port Mapping)是一种网络技术,用于将外部网络请求转发到内部网络的特定设备或服务。它通常用于以下场景: 外部访问内部服务:允许外部用户通过公网IP访问内网中的设备或服务。多设备共享IP…...

数据结构《MapSet哈希表》
文章目录 一、搜索树1.1 定义1.2 模拟实现搜索 二、Map2.1 定义2.2 Map.Entry2.3 TreeMap的使用2.4 Map的常用方法 三、Set3.1 定义3.2 TreeSet的使用3.3 Set的常用方法 四、哈希表4.1 哈希表的概念4.2 冲突4.2.1 冲突的概念4.2.2 冲突的避免1. 选择合适的哈希函数2. 负载因子调…...
【QT】QComboBox:activated信号和currentIndexChanged信号的区别
目录 1、activated1.1 原型1.2 触发机制1.3 使用场景1.4 连接信号和槽的方法1.4.1 方式一1.4.2 方式二 2、currentIndexChanged2.1 原型2.2 触发机制2.3 使用场景2.4 连接信号和槽的方法 1、activated 1.1 原型 [signal] void QComboBox::activated(int index) [signal] void…...

【Block总结】ELGCA模块,池化-转置(PT)注意力和深度卷积有效聚合局部和全局上下文信息
ELGCA结构 论文题目:ELGC-Net: Efficient Local-Global Context Aggregation for Remote Sensing Change Detection 论文链接:https://arxiv.org/pdf/2403.17909 官方github:https://github.com/techmn/elgcnet 高效局部-全局上下文聚合器&…...
MERN全栈脚手架(MongoDB、Express、React、Node)与Yeoman详解
MERN 全栈脚手架是一种用于快速构建基于 MongoDB、Express、React 和 Node.js 的全栈应用的框架或模板。它帮助开发者快速启动项目,减少了从零开始配置的时间。以下是关于 MERN 全栈脚手架的详细解析。 一、MERN 技术栈简介 MongoDB: 文档型数据库,用于…...

基于springboot+vue+微信小程序的宠物领养系统
基于springbootvue微信小程序的宠物领养系统 一、介绍 本项目利用SpringBoot、Vue和微信小程序技术,构建了一个宠物领养系统。 本系统的设计分为两个层面,分别为管理层面与用户层面,也就是管理者与用户,管理权限与用户权限是不…...
如何使用策略模式并让spring管理
1、策略模式公共接口类 BankFileStrategy public interface BankFileStrategy {String getBankFile(String bankType) throws Exception; } 2、策略模式业务实现类 Slf4j Component public class ConcreteStrategy implements BankFileStrategy {Overridepublic String ge…...
react中hooks之useRef 用法总结
1. 基本概念 useRef 是 React 的一个 Hook,返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数。这个对象在组件的整个生命周期内保持不变。 2. 主要用途和特性 2.1 获取 DOM 元素实例 function TextInputWithFocusButton() {const inpu…...

使用 Docker 部署 Java 项目(通俗易懂)
目录 1、下载与配置 Docker 1.1 docker下载(这里使用的是Ubuntu,Centos命令可能有不同) 1.2 配置 Docker 代理对象 2、打包当前 Java 项目 3、进行编写 DockerFile,并将对应文件传输到 Linux 中 3.1 编写 dockerfile 文件 …...
如何在Ubuntu上安装和配置Git
版本控制系统(VCS)是软件开发过程中不可或缺的工具之一,它帮助开发者跟踪代码变更、协作开发以及管理不同版本的项目。Git作为当前最流行的分布式版本控制系统,因其高效性和灵活性而广受青睐。本文将指导你如何在Ubuntu操作系统上…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...

C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...