金融项目实战 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操作系统上…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
