python实现接口自动化

代码实现自动化相关理论

  • 代码编写脚本和工具实现脚本区别是啥?

    • 代码:
      • 优点:代码灵活方便
      • 缺点:学习成本高
    • 工具:
      • 优点:易上手
      • 缺点:灵活度低,有局限性。
    • 总结:
      • 功能脚本:工具
      • 自动化脚本:代码
  • 代码接口自动化怎么做的?

    第一步:python+request+unittest;
    具体描述?
    第二步:封装、调用、数据驱动、日志、报告;
    详细举例:
    第三步:api\scripts\data\log\report\until...
    

脚本实现

  • 使用代码编写自动化脚本的流程
1、抽取功能用例转为自动化用例
2、搭建环境(测试工具、)
3、搭建目录结构
4、编写脚本
5、执行脚本
6、配置持续集成

抽取功能转为自动化用例

image-20240629204617392

搭建环境(测试工具)

1、python、Pycharm、requests、pymysql、parametrize
2、jenkins、jdk
提示:由于编写的自动化脚本,而自动化脚本编写之前功能已测试完毕,所以不需要在单独搭建项目环境。

搭建目录结构

image-20240707204623861

代码编写

  • api(api_register_login.py)

    from config import Host
    class ApiRegisterLogin:#初始化def __init__(self,session):# 获取session对象self.session =session# 图片验证码urlself.__url_img_code=Host+"/common/public/verifycode1/{}"# 短信验证码urlself.__url_phone_code = Host + "/member/public/sendSms"# 注册urlself.__url_register= Host + "/member/public/reg"# 登录urlself.__url_login=Host + "/member/public/login"# 登录状态urlself.__url_login_status = Host + "/member/public/islogin"#1.获取图片验证码接口 封装def api_img_code(self):pass#2.获取短信验证码接口 封装def api_phone_code(self):pass#3.注册接口封装def api_register(self):pass#4.登录接口封装def api_login(self):pass#5.查询登录状态接口 封装def api_login_status(self):pass
    
  • 实现

    #1.获取图片验证码接口 封装def api_img_code(self,random):# 调用get方法,返回响应对象return self.session.get(url=self.__url_img_code.format(random))#2.获取短信验证码接口 封装def api_phone_code(self,phone,imgVerifyCode):#1.定义请求参数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,imgVerifyCode,phone_code):# 1.定义请求参数data = {"phone": phone,"password":password,"imgVerifyCode": imgVerifyCode,"phone_code":phone_code,"dy_server":"on","invite_phone": ""}# 调用请求方法return self.session.post(url=self.__url_register, data=data)#4.登录接口封装def api_login(self,phone,password):#1.定义请求参数data={"phone":phone,"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)
  • script(test01_register_login.py)

image-20240702085800075

import unittest
import requests
from api.api_register_login import ApiRegisterLogin
class TestRegisterLogin(unittest.TestCase):#初始化def setUp(self) -> None:# 获取session对象self.session=requests.session()#获取ApiRegisterLogin实例self.reg=ApiRegisterLogin(self.session)#结束def tearDownClass(cls) -> None:# 关闭session对象self.session.close()#1.获取图片验证码接口 测试def test01_img_code(self):pass#2.获取短信验证码接口 测试def test02_phone_code(self):pass#3.注册接口 测试def test03_register(self):pass#4.登录接口 测试def test04_login(self):pass#5.查询登录状态接口 测试def test05_login_status(self):pass
  • 封装
import unittest
import requests
from api.api_register_login import ApiRegisterLogin
class 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(123)#查看响应状态码print(r.status_code)#2.获取短信验证码接口 测试def test02_phone_code(self,phone=13312345678,imgVerifyCode=8888):#1.调用获取短信验证码接口--目的:让session对象记录cookieself.reg.api_img_code(123)#2.调用短信验证码接口r=self.reg.api_phone_code(phone=phone,imgVerifyCode=imgVerifyCode)print(r.json())#3.注册接口 测试def test03_register(self,phone=13312345678,imgVerifyCode=8888,password="test123",phone_code=666666):#1.图片验证码接口self.reg.api_img_code(123)#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="13312345678",password="test123"):#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="13312345678",password="test123")#调用查询登录接口状态r = self.reg.api_login_status()#看结果print(r.json())

断言

  • 说明:判断程序执行实际结果是否符合预期结果
  • 示例:
import unittest
import requests
from api.api_register_login import ApiRegisterLogin
class 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):try:# 调用图片验证码r= self.reg.api_img_code(123)#查看响应状态码self.assertEqual(200,r.status_code)except Exception as e:#日志print(e)#抛异常raise#2.获取短信验证码接口 测试def test02_phone_code(self,phone=13312345678,imgVerifyCode=8888,expect_text="发送成功"):try:#1.调用获取短信验证码接口--目的:让session对象记录cookieself.reg.api_img_code(123)#2.调用短信验证码接口r=self.reg.api_phone_code(phone=phone,imgVerifyCode=imgVerifyCode)#3.查看响应结果print(r.json())#self.assertIn("发送成功",r.json().get("description"))self.assertIn(expect_text,r.text)except Exception as e:#日志print(e)#抛异常raise#3.注册接口 测试def test03_register(self,phone=13312345679,imgVerifyCode=8888,password="test123",phone_code=666666,expect_text="注册成功"):try:#1.图片验证码接口self.reg.api_img_code(123)#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(expect_text, r.text)except Exception as e:#日志print(e)#抛异常raise#4.登录接口 测试def test04_login(self,keywords="13312345678",password="test123",expect_text="登录成功"):try:#1.调用登录接口r = self.reg.api_login(keywords=keywords, password=password)# 2.查看结果print(r.json())self.assertIn(expect_text, r.text)except Exception as e:#日志print(e)#抛异常raise#5.查询登录状态接口 测试def test05_login_status(self,expect_text="OK"):try:#调用登录接口self.reg.api_login(keywords="13312345678",password="test123")#调用查询登录接口状态r = self.reg.api_login_status()#看结果print(r.json())self.assertIn(expect_text, r.text)except Exception as e:#日志print(e)#抛异常raise

提示:捕获异常的目的是为了将错误信息记录下来,捕获信息完成后,必须抛出异常。

参数化

  • 步骤
1.编写数据存储文件json
2.编写读取工具方法 read_json()
3.使用参数化组件进行引用 parametrize
  • 1.编写参数化文件(register_login.json)
心得:
1、根据模块来新建json文件(1个模块1个json文件)
2、最外侧使用{},模块下几个接口,编写几个key,值为列表
3、列表值中,有几组数据,就写几个{}
4、每组数据{}中,组成格式:说明+参数+预期结果
{"img_code": [{"desc": "获取图片验证码成功(随机小数)","random": 0.123,"expect_code": 200},{"desc": "获取图片验证码成功(随机整数)","random": 1,"expect_code": 200},{"desc": "获取图片验证码成功(随机为空)","random": " ","expect_code": 404},{"desc": "获取图片验证码成功(随机数为字符串)","random": "a123","expect_code": 400}],"phone_code": [{"desc":"获取短信验证码成功 ","phone":"16612345678","imgVerifyCode":8888,"expect_code": "发送成功"},{"desc":"获取短信验证码成功 ","phone":"16612345678","imgVerifyCode":8889,"expect_code": "验证码错误"}],"register": [{"desc":"注册成功(必填参数) ","phone":"16612341111","password":"test123","verifycode":8888,"phone_code": 666666,"expect_code": "注册成功"},{"desc":"注册失败(图片验证码错误)","phone":"16612341111","password":"test123","verifycode":8889,"phone_code": 666666,"expect_code": "验证码错误!"},{"desc":"注册失败(短信验证码错误)","phone":"16612341111","password":"test123","verifycode":8888,"phone_code": 666667,"expect_code": "验证码错误"},{"desc":"注册失败(手机号已存在)","phone":"13312345678","password":"test123","verifycode":8888,"phone_code": 666666,"expect_code": "已存在"}],"login": [{"desc": "登录成功","keywords": "13312345678","password":"test123","expect_code": "登录成功"},{"desc": "登录失败(密码为空)","keywords": "13312345678","password":"","expect_code": "不能为空"},{"desc": "登录失败(解锁)","keywords": "13312345678","password":"error123","expect_code": "登录成功"}],"login_status": [{"desc": "查询登录状态(已登录) ","status": "已登录","expect_code": "OK"},{"desc": "查询登录状态(未登录) ","status": "未登录","expect_code": "未登"}]
}
  • 编写读取数据工具(util.py)
#读取json工具
import os
import jsonfrom config import DIR_PATH
def read_json(filename,key):#拼接读取文件的完整路径 os.sep动态获取/\file_path=DIR_PATH+os.sep+"data"+os.sep+filenamearr=[]with open(file_path,"r",encoding="utf-8") as f:for data in json.load(f).get(key):arr.append(tuple(data.values())[1:])return  arrif __name__ == '__main__':print(read_json("register_login.json", "register"))
  • 参数化引用

    • 难点1:错误次数锁定
    # 如果 password=="error123":i= 1while i<=3:#调用登录r=self.xxxlogin()#改变计数器i+=1#断言锁定#暂停60秒#测试登录成功(注意:登录时必须给正确密码)r= self.reg.api_login(keywords="13312345678",password="test123")else:#调用登录(参数数据)#断言   
    
    • 难点2:查询登录状态,不同结果。
        #如果 status=="已登录":# 调用登录#调用查询登录状态接口#断言
    

断言代码示例:(test01_register_login.py)

import unittest
import requests
from  time import sleep
from parameterized import parameterized
from api.api_register_login import ApiRegisterLogin
from util import read_json
class 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)#查看响应状态码self.assertEqual(expect_code,r.status_code)except Exception as e:#日志print(e)#抛异常raise#2.获取短信验证码接口 测试@parameterized.expand(read_json("register_login.json", "phone_code"))def test02_phone_code(self,phone,imgVerifyCode,expect_text):try:#1.调用获取短信验证码接口--目的:让session对象记录cookieself.reg.api_img_code(123)#2.调用短信验证码接口r=self.reg.api_phone_code(phone=phone,imgVerifyCode=imgVerifyCode)#3.查看响应结果print(r.json())#self.assertIn("发送成功",r.json().get("description"))self.assertIn(expect_text,r.text)except Exception as e:#日志print(e)#抛异常raise#3.注册接口 测试@parameterized.expand(read_json("register_login.json", "register"))def test03_register(self,phone,password,imgVerifyCode,phone_code,expect_text):try:#1.图片验证码接口self.reg.api_img_code(123)#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(expect_text, r.text)except Exception as e:#日志print(e)#抛异常raise@parameterized.expand(read_json("register_login.json", "login"))#4.登录接口 测试def test04_login(self,keywords,password,expect_text):try:i=1r=Noneif "error" in  password:while i<=3:r=self.reg.api_login(keywords,password)i+=1#断言锁定print("测试锁定:",r.text)self.assertIn("锁定",r.text)#暂停60秒sleep(60)#测试登录成功r= self.reg.api_login(keywords="13312345678",password="test123")# 断言登录成功self.assertIn(expect_text,r.text)else:#1.调用登录接口r = self.reg.api_login(keywords=keywords, password=password)# 2.查看结果print(r.json())self.assertIn(expect_text, r.text)except Exception as e:#日志print(e)#抛异常raise@parameterized.expand(read_json("register_login.json", "login_status"))#5.查询登录状态接口 测试def test05_login_status(self,status,expect_text):try:if status=="已登录":#调用登录接口self.reg.api_login(keywords="13312345678",password="test123")#调用查询登录接口状态r = self.reg.api_login_status()#看结果print(r.json())self.assertIn(expect_text, r.text)except Exception as e:#日志print(e)#抛异常raise

日志

  • 日志的作用?

    记录程序运行的步骤和错误。
    

    日志的场景

  • 1、调试bug
    2、查看程序运行轨迹
    
  • 日志的基本应用

    #1、导包
    import logging
    #2、调用日志入口
    logging.error("出错啦,错误原因:{}".format(e))
    
    import logging
    #设置日志级别及保存文件名
    logging.basicConfig(level=logging.DEBUG,filename="../log/p2p.log")
    #调用日志
    logging.debug("调试信息")
    logging.info("信息级别")
    logging.warning("警告")
    logging.error(("断言错误!"))
    logging.critical("严重错误")
    
  • 测试人员使用的日志的入口

    info:记录运行步骤
    error:记录运行错误
    
  • 日志底层组成介绍

    说明:logging库底层有4大组件(日志器、处理器、格式器、过滤器)
    1、日志器:接受日志信息,设置日志显示级别
    2、处理器:控制日志显示位置或文件
    3、格式器:控制日志输出的显示样式
    关系:
    格式器必须关联处理器
    处理器必须关联日志器
    
  • 日志封装应用

重组封装的目的:解决日志显示的样式、存储方式
import logging.handlers
# 日志工具
class GetLog:@classmethoddef get_log(cls):cls.log = Noneif cls.log is None:#1.获取日志器cls.log =logging.getLogger()#设置日志级别infocls.log.setLevel(logging.INFO)file_path = DIR_PATH + os.sep + "log" + os.sep + "p2p.log"#2.获取处理器TimedRotatingFileHandler:日志保存到文件且根据时间去分隔tf =  logging.handlers.TimedRotatingFileHandler(filename=file_path,when="midnight",interval=1,backupCount=3,encoding="utf-8")#3.获取格式器fmt ="%(asctime)s %(levelname)s[%(filename)s(%(funcName)s:%(lineno)d)]-%(message)s"fm = logging.Formatter(fmt)#4.将格式器添加到处理器中tf.setFormatter(fm)#5.将处理器添加到日志器中cls.log.addHandler(tf)#返回日志器return cls.logif __name__ == '__main__':GetLog.get_log().info("信息级别测试")
  • 应用(init.py)

image-20240705090348003

应用的级别:info、error
info:info记录程序运行的步骤
error:记录程序错误
from api import log
from config import Hostclass ApiRegisterLogin:#初始化def __init__(self,session):# 获取session对象self.session =session# 图片验证码urlself.__url_img_code=Host+"/common/public/verifycode1/{}"# 短信验证码urlself.__url_phone_code = Host + "/member/public/sendSms"# 注册urlself.__url_register= Host + "/member/public/reg"# 登录urlself.__url_login=Host + "/member/public/login"# 登录状态urlself.__url_login_status = Host + "/member/public/islogin"#1.获取图片验证码接口 封装def api_img_code(self,random):log.info("正在调用获取图片验证码接口,请求方法:{},请求url:{}".format("get",self.__url_img_code.format(random)))# 调用get方法,返回响应对象return self.session.get(url=self.__url_img_code.format(random))#2.获取短信验证码接口 封装def api_phone_code(self,phone,imgVerifyCode):#1.定义请求参数data={"phone":phone,"imgVerifyCode":imgVerifyCode,"type":"reg"}log.info("正在调用短信验证码接口,请求方法:{},请求url:{},请求参数:{}".format("post",self.__url_phone_code,data=data))# 调用请求方法return self.session.post(url=self.__url_phone_code,data=data)#3.注册接口封装def api_register(self,phone,password,verifycode,phone_code):# 1.定义请求参数data = {"phone": phone,"password":password,"verifycode": verifycode,"phone_code":phone_code,"dy_server":"on","invite_phone": ""}log.info("正在调用注册接口,请求方法:{},请求url:{},请求参数:{}".format("post",self.__url_register, data=data))# 调用请求方法return self.session.post(url=self.__url_register, data=data)#4.登录接口封装def api_login(self,keywords,password):#1.定义请求参数data={"keywords":keywords,"password":password,}log.info("正在调用登录接口,请求方法:{},请求url:{},请求参数:{}".format("post",self.__url_login,data=data))# 调用请求方法return self.session.post(url=self.__url_login,data=data)#5.查询登录状态接口 封装def api_login_status(self):log.info("正在调用查询登录状态接口,请求方法:{},请求url:{}".format("post",self.__url_login_status))return self.session.post(url=self.__url_login_status)
import unittest
import requests
import logging
from api import log
from  time import sleep
from parameterized import parameterized
from api.api_register_login import ApiRegisterLogin
from util import read_json
class TestRegisterLogin(unittest.TestCase):#初始化def setUp(self) -> None:# 获取session对象self.session=requests.session()log.info("正在初始化session对象:{}".format(self.session))#获取ApiRegisterLogin实例self.reg=ApiRegisterLogin(self.session)#结束def tearDown(self) -> None:# 关闭session对象self.session.close()log.info("正在关闭session对象:{}".format(self.session))#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)log.info("执行图片验证码响应状态码:{}".format(r.status_code))#查看响应状态码self.assertEqual(expect_code,r.status_code)log.info("执行图片验证码断言通过")except Exception as e:#日志log.error("断言失败,原因:{}".format(e))#抛异常raise#2.获取短信验证码接口 测试@parameterized.expand(read_json("register_login.json", "phone_code"))def test02_phone_code(self,phone,imgVerifyCode,expect_text):try:#1.调用获取短信验证码接口--目的:让session对象记录cookieself.reg.api_img_code(123)#2.调用短信验证码接口r=self.reg.api_phone_code(phone=phone,imgVerifyCode=imgVerifyCode)log.info("执行结果接口为:{}".format(r.text))#3.查看响应结果print(r.json())#self.assertIn("发送成功",r.json().get("description"))self.assertIn(expect_text,r.text)log.info("执行断言通过")except Exception as e:#日志log.error("断言失败,原因:{}".format(e))#抛异常raise#3.注册接口 测试@parameterized.expand(read_json("register_login.json", "register"))def test03_register(self,phone,password,imgVerifyCode,phone_code,expect_text):try:#1.图片验证码接口self.reg.api_img_code(123)#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)log.info("执行结果接口为:{}".format(r.text))#4.查看结果print(r.json())self.assertIn(expect_text, r.text)log.info("执行断言通过")except Exception as e:#日志log.error("断言失败,原因:{}".format(e))#抛异常raise@parameterized.expand(read_json("register_login.json", "login"))#4.登录接口 测试def test04_login(self,keywords,password,expect_text):try:i=1r=Noneif "error" in  password:while i<=3:r=self.reg.api_login(keywords,password)i+=1#断言锁定print("测试锁定:",r.text)self.assertIn("锁定",r.text)#暂停60秒sleep(60)#测试登录成功r= self.reg.api_login(keywords="13312345678",password="test123")# 断言登录成功self.assertIn(expect_text,r.text)else:#1.调用登录接口r = self.reg.api_login(keywords=keywords, password=password)log.info("执行结果接口为:{}".format(r.text))# 2.查看结果print(r.json())self.assertIn(expect_text, r.text)log.info("执行断言通过")except Exception as e:#日志log.error("断言失败,原因:{}".format(e))#抛异常raise@parameterized.expand(read_json("register_login.json", "login_status"))#5.查询登录状态接口 测试def test05_login_status(self,status,expect_text):try:if status=="已登录":#调用登录接口self.reg.api_login(keywords="13312345678",password="test123")#调用查询登录接口状态r = self.reg.api_login_status()log.info("执行结果接口为:{}".format(r.text))#看结果print(r.json())self.assertIn(expect_text, r.text)log.info("执行断言通过")except Exception as e:#日志log.error("断言失败,原因:{}".format(e))#抛异常raise

image-20240705091122205

认证开户

封装(api_approve_trust.py)

from config import Host
class ApiApproveTrust:# 初始化def __init__(self,session):#获取session对象self.session=session# 认证urlself.__url_approve = Host+"/member/realname/approverealname"# 查询认证状态urlself.__url_approve_status = Host+"/member/member/getapprove"#开户urlself.__url_trust = Host + "/trust/trust/register"#图片验证码urlself.__url_img_code = Host + "/common/public/verifycode1/{}"#充值urlself.__url_recharge = Host + "/trust/trust/recharge"# 1.认证接口 封装def api_approve(self):pass#2.查询认证状态接口 封装def api_approve_status(self):pass#3.开户接口 封装def api_trust(self):pass#4.获取图片验证码接口 封装def api_img_code(self):pass#5.充值接口 封装def api_recharge(self):pass
  • 难点:认证接口请求参数类型为:multipart/form-data多消息类型,如何实现?
解决:请求使用data+files两种参数格式,消息头会自动切换到multipart接口
示例:self.session.post(url=self.__url_approve,data=data,files={"x":"y"})
from config import Host
class ApiApproveTrust:# 初始化def __init__(self,session):#获取session对象self.session=session# 认证urlself.__url_approve = Host+"/member/realname/approverealname"# 查询认证状态urlself.__url_approve_status = Host+"/member/member/getapprove"#开户urlself.__url_trust = Host + "/trust/trust/register"#图片验证码urlself.__url_img_code = Host + "/common/public/verifycode1/{}"#充值urlself.__url_recharge = Host + "/trust/trust/recharge"# 1.认证接口 封装def api_approve(self):#1.请求参数data={"realname":"华仔","card_id":"110101200007289809"}#2.调用请求方法 难题:multipart/form-data使用:data+files来实现多消息体类型return self.session.post(url=self.__url_approve,data=data,files={"x":"y"})#2.查询认证状态接口 封装def api_approve_status(self):return self.session.post(url=self.__url_approve_status)#3.开户接口 封装def api_trust(self):return self.session.post(url=self.__url_trust)#4.获取图片验证码接口 封装def api_img_code(self,random):return self.session.get(url=self.__url_img_code.format(random))#5.充值接口 封装def api_recharge(self,valicode):# 1.请求参数data = {"paymentType": "chinapnrTrust","amount": "10000","formStr":"reForm","valicode":valicode}# 2.调用请求方法return self.session.post(url=self.__url_recharge, data=data)

调用(test02_approve_trust.py)

  • 结构
import unittest
import requests
from api.api_approve_trust import ApiApproveTrust
from api.api_register_login import ApiRegisterLogin
class TestApproveTrust(unittest.TestCase):#初始化def setUp(self) -> None:#1. 获取sessionself.session=requests.session()#2.获取ApiApproveTrust对象self.ApiApproveTrust=ApiApproveTrust(self.session)#3.调用登录成功ApiRegisterLogin(self.session).api_login()# 结束def tearDown(self) -> None:self.session.close()#1、认证接口 测试def test01_approve(self):pass#2、查询认证状态接口 测试def test_02_status(self):pass#3、开户接口 测试def test03_trust(self):pass#4、获取图片验证码 测试def test04_img_code(self):pass#5、充值接口 测试def test05_recharge(self):pass
  • 实现
import unittest
import requests
from api import log
from api.api_approve_trust import ApiApproveTrust
from api.api_register_login import ApiRegisterLogin
class TestApproveTrust(unittest.TestCase):#初始化def setUp(self) -> None:#1. 获取sessionself.session=requests.session()#2.获取ApiApproveTrust对象self.approve=ApiApproveTrust(self.session)#3.调用登录成功ApiRegisterLogin(self.session).api_login()# 结束def tearDown(self) -> None:self.session.close()#1、认证接口 测试def test01_approve(self):#调用认证接口try:r=self.approve.api_approve()log.info("接口执行结果为:{}".format(r.text))#断言self.assertIn("提交成功",r.text)log.info("断言通过")except Exception as e:# 日志log.error("断言错误!原因:{}".format(e))# 抛异常raise#2、查询认证状态接口 测试def test_02_status(self):# 调用查询认证状态接口try:r = self.approve.api_approve_status()log.info("接口执行结果为:{}".format(r.text))# 断言self.assertIn("华", r.text)log.info("断言通过")except Exception as e:# 日志log.error("断言错误!原因:{}".format(e))# 抛异常raise#3、开户接口 测试def test03_trust(self):# 调用开户接口try:r = self.approve.api_trust()log.info("接口执行结果为:{}".format(r.json()))# 断言self.assertIn("form", r.text)print("请求后台开户结果为:", r.json())log.info("断言通过!")#三方开户except Exception as e:# 日志log.error("断言错误!原因:{}".format(e))# 抛异常raise#4、获取图片验证码 测试def test04_img_code(self,random=123):# 调用获取图片验证码接口try:r = self.approve.api_img_code(random)log.info("接口执行结果为:{}".format(r.status_code))# 断言self.assertEqual(200, r.status_code)log.info("断言通过")except Exception as e:# 日志log.error("断言错误!原因:{}".format(e))# 抛异常raise#5、充值接口 测试def test05_recharge(self,valicode=8888):# 调用充值接口try:#调用图片验证码 获取cookieself.approve.api_img_code(123)r = self.approve.api_recharge(valicode)log.info("接口执行结果为:{}".format(r.json()))print("请求后台充值结果为:{}".format(r.json()))# 断言self.assertIn("form", r.text)log.info("断言通过")# 三方充值except Exception as e:# 日志log.error("断言错误!原因:{}".format(e))# 抛异常raise

问题:

三方开户、三方充值如何操作?--从响应数据中提取input标签name属性值和value属性,在python中如何提取?

BeautifSoup库

  • 一个python解析html/xml的三方库

  • 安装pip install beautifulsoup4

  • 应用步骤:

    1、导包
    2、实例化
    3、调用方法
    
  • 示例:

#1、导包
from bs4 import BeautifulSoup
html="""<html><head><title>某马程序员</title></head><body><p id ="test01">软件测试</p><p id ="test02">2024年</p><a href="/api.html">接口测试</a><a href="/web.html">Web自动化测试</a><a href="/app.html">App自动化测试</a></body></html>
"""
#2、获取bs对象 告诉BeautifulSoup类 你要解析的是html格式
bs=BeautifulSoup(html,"html.parser")
#3、调用方法
"""重点:
1、查找所有标签  bs.find_all("标签名")==元素的集合==("元素1","元素2")
2、查找属性 元素.get("属性名")
"""
for a in bs.find_all('a'):print(a.get("href"))#4、扩展其他方法
#获取单个元素
print(bs.a)
#获取文本
print(bs.a.string)
#获取属性
print(bs.a.get("href"))
#获取标签名
print(bs.a.name)
  • 重点
1、查找所有标签  bs.find_all("标签名")==元素的集合==("元素1","元素2")
2、查找属性 元素.get("属性名")
  • 其他方法
#4、扩展其他方法
#获取单个元素
print(bs.a)
#获取文本
print(bs.a.string)
#获取属性
print(bs.a.get("href"))
#获取标签名
print(bs.a.name)

提取html数据根据封装

  • 思路
# 提取html
# 获取BeautifulSoup对象
# 提取url
# 遍历查找所有的input标签
# 提取name和value的值,并组装到新的字典中
# 返回url和字段
  • 示例
# 提取html数据
def parser_html(result):#1、提取htmlhtml =result.json().get("description").get("form")#2、获取bs对象bs=BeautifulSoup(html,"html.parser")#3、提取urlurl= bs.form.get("action")print("提取的url:",url)#4、查找所有的input标签data={}for input in bs.find_all("input"):data[input.get("name")]=input.get("value")return url,data
    #3、开户接口 测试def test03_trust(self):# 调用开户接口try:r = self.approve.api_trust()log.info("接口执行结果为:{}".format(r.json()))# 断言self.assertIn("form", r.text)print("请求后台开户结果为:", r.json())log.info("断言通过!")#三方开户result = parser_html(r)#期望 http://xxx,{"version":10}r=self.session.post(url=result[0],data=result[1])print("三方开户的结果为:",r.text)self.assertIn("OK",r.text)log.info("接口执行结果为:{}".format(r.text))except Exception as e:# 日志log.error("断言错误!原因:{}".format(e))# 抛异常raise

认证开户参数化

  • 参数化文件(approve_trust.json)
{"img_code": [ {"desc": "获取图片验证码成功(随机小数)","random": 0.123,"expect_code": 200},{"desc": "获取图片验证码成功(随机整数)","random": 1,"expect_code": 200},{"desc": "获取图片验证码成功(随机为空)","random": " ","expect_code": 404},{"desc": "获取图片验证码成功(随机数为字符串)","random": "a123","expect_code": 400}],"recharge": [{"desc":"后台充值响应成功","valicode": 8888,"expect": "OK"},{"desc":"后台充值响应失败","valicode": 8889,"expect": "验证码错误"}]
}
  • 实现难点:
1、充值需要判断验证码不同,执行步骤和结果不同
思路:
1、调用图片验证码-->记录cookie
2、调用充值接口(验证码)
3、判断验证码为8888# 1、提取响应数据# 2、三方充值# 3、断言 
4、否则# 直接断言 验证码错误
 #4、获取图片验证码 测试@parameterized.expand(read_json("approve_trust.json", "img_code"))def test04_img_code(self,random,expect_text):# 调用获取图片验证码接口try:r = self.approve.api_img_code(random)log.info("接口执行结果为:{}".format(r.status_code))# 断言self.assertEqual(expect_text, r.status_code)log.info("断言通过")except Exception as e:# 日志log.error("断言错误!原因:{}".format(e))# 抛异常raise@parameterized.expand(read_json("approve_trust.json", "recharge"))#5、充值接口 测试def test05_recharge(self,valicode,expect_text):# 调用充值接口try:#调用图片验证码 获取cookieself.approve.api_img_code(123)r = self.approve.api_recharge(valicode)log.info("接口执行结果为:{}".format(r.json()))if valicode==8888:# 断言self.assertIn("form", r.text)log.info("断言通过")# 三方充值result = parser_html(r)# 期望 http://xxx,{"version":10}r = self.session.post(url=result[0], data=result[1])print("三方充值的结果为:", r.text)self.assertIn(expect_text, r.text)log.info("接口执行结果为:{}".format(r.text))else:self.assertIn(expect_text,r.text)print("验证码错误响应结果为:",r.text)except Exception as e:# 日志log.error("断言错误!原因:{}".format(e))# 抛异常raise

投资模块

封装(api_tender.py)

from config import Host
class ApiTender:#初始化def __init__(self,session):#sessionself.session=session#urlself.__url_tender = Host + "/trust/trust/tender"#1、投资方法def api_tender(self,amount):#1、参数data={"id":8071,"depositCertificate":-1,"amount":amount}#2、调用请求方法return self.session.post(url=self.__url_tender,data=data)

调用(test03_tender.py)

import unittest
import requests
from util import parser_html
from api import log
from api.api_tender import ApiTender
from api.api_register_login import ApiRegisterLogin
class TestTender(unittest.TestCase):#初始化def setUp(self) -> None:#获取session对象self.session=requests.session()#获取ApiTender对象self.tender=ApiTender(self.session)#调用登录ApiRegisterLogin(self.session).api_login()#结束def tearDown(self) -> None:self.session.close()#测试方法def test01_tender(self,amount=100,expect_text="OK"):try:#调用投资方法r=self.tender.api_tender(amount)#调用三方投资result = parser_html(r)# 期望 http://xxx,{"version":10}r = self.session.post(url=result[0], data=result[1])print("三方投资的结果为:", r.text)self.assertIn("OK", r.text)log.info("接口执行结果为:{}".format(r.text))#断言self.assertIn(expect_text,r.text)except Exception as e:# 日志log.error(e)# 抛异常raise

参数化

  • 文件(tender.json)
{"tender": [{"desc": "请求后台投资响应成功","amount": 100,"expect_text": "OK"},{"desc": "请求后台投资响应失败(金额为空)","amount": " ","expect_text": "不是正确的金额"}]
}
  • 调用(test03_tender.py)
import unittest
import requests
from util import parser_html
from api import log
from api.api_tender import ApiTender
from api.api_register_login import ApiRegisterLogin
from util import read_json
from parameterized import parameterized
class TestTender(unittest.TestCase):#初始化def setUp(self) -> None:#获取session对象self.session=requests.session()#获取ApiTender对象self.tender=ApiTender(self.session)#调用登录ApiRegisterLogin(self.session).api_login()#结束def tearDown(self) -> None:self.session.close()#测试方法@parameterized.expand(read_json("tender.json", "tender"))def test01_tender(self,amount,expect_text):try:#调用投资方法r=self.tender.api_tender(amount)if amount==100:#调用三方投资result = parser_html(r)# 期望 http://xxx,{"version":10}r = self.session.post(url=result[0], data=result[1])print("三方投资的结果为:", r.text)self.assertIn("OK", r.text)log.info("接口执行结果为:{}".format(r.text))#断言self.assertIn(expect_text,r.text)else:self.assertIn(expect_text, r.text)except Exception as e:# 日志log.error(e)# 抛异常raise

投资业务

import unittest,requests
from util import parser_html
from api import log
from api.api_tender import ApiTender
from api.api_register_login import ApiRegisterLogin
from api.api_approve_trust import ApiApproveTrustclass TestTenderList(unittest.TestCase):def setUp(self) -> None:#获取session对象self.session = requests.session()#获取ApiRegisterLogin对象self.reg = ApiRegisterLogin(self.session)#获取ApiApproveTrust对象self.approve = ApiApproveTrust(self.session)#获取ApiTender对象self.tender = ApiTender(self.session)def tearDown(self) -> None:#关闭sessionself.session.close()def test01_tender_list(self):phone="18822228888"img_code=8888pwd="test123"phone_code=666666card_id="120101200007288410"#1、获取图片验证码self.reg.api_img_code(123123)#2、获取短信验证码self.reg.api_phone_code(phone,img_code)#3、注册self.reg.api_register(phone,pwd,img_code,phone_code)#4、登录self.reg.api_login(phone,pwd)#5、认证self.approve.api_approve(card_id)#6、后台开户r = self.approve.api_trust()#7、三方开户result = parser_html(r)r = self.session.post(url=result[0], data=result[1])print("三方开户的结果为:", r.text)self.assertIn("OK", r.text)log.info("接口执行结果为:{}".format(r.text))#8、获取充值验证码self.approve.api_img_code(123123)#9、后台充值r= self.approve.api_recharge(img_code)#10、三方充值result = parser_html(r)r = self.session.post(url=result[0], data=result[1])print("三方充值的结果为:", r.text)self.assertIn("OK", r.text)log.info("接口执行结果为:{}".format(r.text))#11、后台投资r=self.tender.api_tender(100)#12、三方投资result = parser_html(r)r = self.session.post(url=result[0], data=result[1])print("三方投资的结果为:", r.text)self.assertIn("OK", r.text)log.info("接口执行结果为:{}".format(r.text))

连接数据库工具封装

  • util.py
#连接数据库工具
def conn_pymsql(sql):conn= Nonecursor=Nonetry:#1、获取连接对象conn=pymysql.connect(host="121.43.169.97",user="root",password="123456",database="czbk_member",port=3306,charset="utf8",autocommit=True)#2、获取游标对象cursor=conn.cursor()#3、执行sql语句cursor.execute(sql)#判断sql语句是否为查询if sql.split()[0].lower()=="select":#返回所有结果return cursor.fetchall()#否则else:#返回受影响的行数return "受影响的行数为:{}".format(cursor.rowcount)except Exception as e:GetLog.get_log().error(e)raisefinally:#4、关闭游标cursor.close()#5、关闭连接conn.close()

清除测试数据应用

  • util.py
def clear_data():sql1="""delete i.* from mb_member_info i INNER JOIN mb_member m on
i.member_id=m.id where m.phone in
("16612345671","16612345672","16612345673","16612345674");
"""conn_pymsql(sql1)sql2 = """delete l.* from mb_member_login_log l INNER JOIN mb_member m on
l.member_id=m.id where m.phone in
("16612345671","16612345672","16612345673","16612345674");"""conn_pymsql(sql2)sql3= """delete from mb_member_register_log where phone in
("16612345671","16612345672","16612345673","16612345674");"""conn_pymsql(sql3)sql4 = """delete from mb_member where phone in
("16612345671","16612345672","16612345673","16612345674");"""conn_pymsql(sql4)
  • 调用(test01_register_login.py)
    @classmethoddef setUpClass(cls) -> None:#清除数据clear_data()#提示:必须在test01_xxx.py中类方法调用

运行

  • 测试报告

image-20240707200848902

  • run_suite.py
"""
报告:htmltestreport
"""
#1、导包
from htmltestreport import HTMLTestReport
import unittest
import os
from config import DIR_PATH
#组合测试套件
suite=unittest.defaultTestLoader.discover("./script")
#指定测试报告存储目录
report_path=DIR_PATH+os.sep+"report"+os.sep+"p2p.html"
#执行测试套件
HTMLTestReport(report_path,title="p2p接口自动化测试报告").run(suite)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/868535.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++】BMP图片结构深度解析及其在C++中的操作与应用

引言 BMP&#xff08;Bitmap Image File&#xff09;是一种与设备无关的图像文件格式&#xff0c;它采用了一种非常直接的方式来存储图像数据&#xff0c;即按照图像的行和列顺序&#xff0c;逐像素地存储颜色值。由于其简单性和可移植性&#xff0c;BMP文件在图像处理、图像分…

windows电脑桌面便签在哪里找?

在忙碌的工作中&#xff0c;我们经常会有很多事情需要记住。这时&#xff0c;电脑桌面便签就成为了我们的好帮手。那么&#xff0c;在Windows电脑上&#xff0c;我们该如何找到桌面便签呢&#xff1f;下面&#xff0c;就让我来为大家详细介绍一下。 其实&#xff0c;Windows电…

Failed building wheel for pyaudio Running setup.py clean for pyaudio

从错误信息来看&#xff0c;问题出在 pyaudio 包的构建过程中。具体来说&#xff0c;缺少 portaudio.h 头文件&#xff0c;这通常是因为系统上没有安装 portaudio 库。 以下是解决此问题的步骤&#xff1a; 安装系统依赖&#xff1a; 在大多数基于 Debian 的系统&#xff08;如…

elementui的table的@selection-change阻止事件改变

说明&#xff1a; 最近有个不想说的&#xff08;xxx&#xff09;业务&#xff0c;在表格勾选每一行的时候要触发一系列查询功能&#xff0c;查询失败还要把那个勾勾回退。真实蛋疼&#xff01;表格勾选的默认selection-change是change事件&#xff0c;一般change事件是在完成之…

数据库的操作

【一】库的增删改查 【0】导入数据文件 source D:\bjpowernode.sql 【1】创建数据库 语法&#xff1a; create database [if not exists] 数据库名 [character set 编码字符集]; create databases db1; # 设置库的默认编码 create databases db1 charsetgbk; 【2】查看数据…

Argo怎么使用?

Argo是一款基于Kubernetes的开源工作流引擎&#xff0c;用于创建、调度和监控容器化工作流。以下是关于Argo使用的基本步骤和要点&#xff1a; 1. **安装Argo** - 首先&#xff0c;确保已经安装了Kubernetes集群&#xff0c;并且拥有kubectl命令行工具的访问权限。 - 使用kubec…

告别盲目跟风!1688竞品数据分析实战指南(图文解析)

不管是哪个行业&#xff0c;想把这个做起来&#xff0c;做下去&#xff0c;第一就要学会模仿&#xff0c;不要自己盲目瞎做&#xff0c;因为别人的数据&#xff0c;都是得到了认可的&#xff0c;先模仿后超越&#xff0c;1688运营里面模仿就是要学会看竞品&#xff0c;店雷达总…

【spring boot项目】统一返回结果封装

ResultCode.java package cn.clz.rental.utils; /*** 定义HTTP状态码常量* 这些常量用于表示不同类型的HTTP响应状态。*/ public class ResultCode {// 表示请求成功的状态码public static final Integer SUCCESS 200;// 表示服务器内部错误的状态码public static final Inte…

基于AD8232的心电图套件的测试

基于AD8232的心电图套件的测试 1、测试设备2、电源的选择3、 用于测试心电图套件的模拟心电图电路基本4017B的电路基于multisim的电路仿真基于STM32F103RCT6 参考测试数据 1、测试设备 1、AD8232心电模块 2、手持示波器 3、心电信号模拟发生器 4、NI multisim 14.3 5、实物待补…

django后台定制

Django 后台&#xff08;Admin&#xff09;是一个强大的工具&#xff0c;用于管理 Django 项目中的数据模型。然而&#xff0c;默认的 Django Admin 可能无法满足所有项目的需求&#xff0c;因此经常需要进行定制。以下是一些关于 Django 后台定制的推荐、介绍以及技术实现的建…

基于BERT的大规模文本处理实战

1. 引言 ChatGPT4相比于ChatGPT3.5,有着诸多不可比拟的优势&#xff0c;比如图片生成、图片内容解析、GPTS开发、更智能的语言理解能力等&#xff0c;但是在国内使用GPT4存在网络及充值障碍等问题&#xff0c;如果您对ChatGPT4.0感兴趣&#xff0c;可以私信博主为您解决账号和环…

英语口语中just的各种含义用法解析

文章目录 英语口语中"Just"的各种含义与用法解析1. 表示时间的近义1.1 刚刚完成的动作1.2 紧接着要发生的动作 2. 用于强调2.1 强调事实2.2 强调公正或合理性 3. 用作限定词3.1 限定数量或范围3.2 限定意见或观点 4. 表示简单或纯粹4.1 表达无关紧要的事4.2 描述纯粹…

达梦数据库系列—23. DSC集群搭建

目录 DSC搭建 1、环境准备 1.硬件 2.存储设备 3.操作系统 4.网络配置 5.防火墙 6.Selinux检查 7.用户准备 8.目录规划 9.软件安装 10.磁盘准备 2、搭建两节点 DMDSC 1.准备配置文件 dmdcr_cfg.ini 2.使用 DMASMCMD 工具初始化所有磁盘 3.使用 dmdcr_cfg.ini 配…

全卷积网络之FCN图像语义分割

前言 FCN是一种用于图像语义分割的全卷积网络&#xff0c;可以端到端进行像素级预测。 语义分割 图像语义分割是图像处理和机器视觉技术中的重要一环&#xff0c;旨在对图像中的每个像素进行分类。与普通的分类任务不同&#xff0c;语义分割任务输出与输入大小相同的图像&…

C#跨线程访问控件以及方法

在C#中,如果需要跨线程访问控件或调用方法,通常需要考虑到UI线程和后台线程之间的调度问题。以下是一些常见的方法: 1. 使用 Control.Invoke 或 Control.BeginInvoke 在WinForms或WPF应用程序中,如果在非UI线程中访问控件或调用UI相关方法,可以使用 Control.Invoke 或 C…

鸿蒙语言基础类库:【@ohos.uri (URI字符串解析)】

URI字符串解析 说明&#xff1a; 本模块首批接口从API version 8开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。开发前请熟悉鸿蒙开发指导文档&#xff1a;gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。 导入…

亿康源精英盛宴暨亿康源启动成功举办

&#xff08;本台记者报&#xff09;2024年7月7日下午&#xff0c;亿康源精英盛宴暨启动仪式在杭州市中维歌德大酒店盛大举行。此次盛会不仅吸引了行业内的专业人才、著名投资界大咖和科技领域的杰出企业家&#xff0c;还汇聚了众多关注大健康产业的各界人士&#xff0c;共同见…

软件设计之Java入门视频(13)

软件设计之Java入门视频(13) 视频教程来自B站尚硅谷&#xff1a; 尚硅谷Java入门视频教程&#xff0c;宋红康java基础视频 相关文件资料&#xff08;百度网盘&#xff09; 提取密码&#xff1a;8op3 idea 下载可以关注 软件管家 公众号 学习内容&#xff1a; 该视频共分为1-7…

【在线词典】项目实现

15_Dictionary 在线词典 搭建客户端-服务器架构 准备必要的资源 整理原始数据 整理英汉双语对照表&#xff0c;将XLSX格式转换成CSV格式&#xff0c;准备好vocabulary_list.csv文件备用 注意&#xff1a;CSV格式的文件必须使用UTF-8的字符集&#xff1b; 建立mydatabase.…

# 深入解析C/C++中的关键运算符:i++, ++i, a=i++, a=++i 及复杂表达式的运算顺序

原因 有没有人跟我一样&#xff0c;根本记不住那么多的运算符优先级,凭感觉猜的运算 顺序&#xff0c;导致代码出错&#xff0c;调试半天&#xff0c;最后发现是优先级的问题有没有跟我一样&#xff0c;看到复杂表达式就头大看到一些复杂的表达式&#xff0c;不知道怎么去分析…