python实现接口自动化
- 代码实现自动化相关理论
- 代码编写脚本和工具实现脚本区别是啥?
- 代码:
- 优点:代码灵活方便
- 缺点:学习成本高
- 工具:
- 优点:易上手
- 缺点:灵活度低,有局限性。
- 总结:
- 功能脚本:工具
- 自动化脚本:代码
- 代码接口自动化怎么做的?
第一步:python+request+unittest;
具体描述?
第二步:封装、调用、数据驱动、日志、报告;
详细举例:
第三步:api\scripts\data\log\report\until…
- 脚本实现
- 使用代码编写自动化脚本的流程
1、抽取功能用例转为自动化用例
2、搭建环境(测试工具、)
3、搭建目录结构
4、编写脚本
5、执行脚本
6、配置持续集成
-
抽取功能转为自动化用例
-
搭建环境(测试工具)
1、python、Pycharm、requests、pymysql、parametrize
2、jenkins、jdk
提示:由于编写的自动化脚本,而自动化脚本编写之前功能已测试完毕,所以不需要在单独搭建项目环境。
- 搭建目录结构
- 代码编写
- config.py
import os
# 服务器地址
HPST = "http://user-p2p-test.itheima.net"
# 项目目录路径
dir_path = os.path.dirname(__file__)
- api(api_register_login.py)
from config import HOST
class ApiRegisterLogin:
# 初始化
def __init__(self, session):
# 获取session对象
self.session = session # 实例化session,类下面的其他接口就能使用自己的session
# 图片验证码url
self.__url_img_code = HOST + "/common/public/verifycode1/{}" # {}是随机变量,用{}占用
# 短信验证码url
self.__url_phone_code = HOST + "/member/public/sendSms"
# 注册url
self.__url_register = HOST + "/member/public/reg"
# 登录url
self.__url_login = HOST + "/member/public/login"
# 登录状态url
self.__url_login_status = HOST + "/member/public/islogin"
# 获取图片验证码接口 封装
def api_img_code(self):
pass
# 获取短信验证码接口 封装
def api_phone_code(self):
pass
# 注册接口 封装
def api_register(self):
pass
# 登录接口 封装
def api_login(self):
pass
# 查询登录状态接口 封装
def api_login_status(self):
pass
加上__,只能在当千模块里调用,其他py文件调用不了
- 接口封装 实现
# 获取图片验证码接口 封装
def api_img_code(self, random):
# 调用get方法,返回响应对象
res = self.session.get(url=self.__url_img_code.format(random))
return res
# 获取短信验证码接口 封装
def api_phone_code(self, phone, imgVerifyCode):
# 1、定义请求参数
data = {
"phone": phone,
"imgVerifyCode": imgVerifyCode,
"type": "reg"
}
# 2、调用请求方法
res = self.session.post(url=self.__url_phone_code, data=data)
return res
# 注册接口 封装
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": ""
}
# 2、调用请求方法
res = self.session.post(url=self.__url_register, data=data)
return res
# 登录接口 封装
def api_login(self, keywords, password):
# 1、定义请求参数
data = {
"keywords": keywords,
"password": password
}
# 2、调用请求方法
res = self.session.post(url=self.__url_login, data=data)
return res
# 查询登录状态接口 封装
def api_login_status(self):
res = self.session.post(self.__url_login_status)
- script(test01_register_login.py)
import unittest
import requests
from api.api_register_login import ApiRegisterLogin
class TestRegisterLogin(unittest.TestCase):
# 初始化
def setUp(self):
# 获取session对象
self.session = requests.session()
# 获取ApiRegisterLogin实例
self.reg = ApiRegisterLogin(self.session)
# 结束
def tearDown(self):
# 关闭session对象
self.session.close()
# 获取图片验证码接口 测试
def test01_img_code(self):
pass
# 获取短信验证码接口 测试
def test02_phone_code(self):
pass
# 注册接口测试
def test03_register(self):
pass
# 登录接口 测试
def test04_login(self):
pass
# 查询登录状态 测试
def test05_login_status(self):
pass
- 注册登录接口调试测试
import unittest
import requests
from api.api_register_login import ApiRegisterLogin
class TestRegisterLogin(unittest.TestCase):
# 初始化
def setUp(self):
# 获取session对象
self.session = requests.session()
# 获取ApiRegisterLogin实例
self.reg = ApiRegisterLogin(self.session)
# 结束
def tearDown(self):
# 关闭session对象
self.session.close()
# 获取图片验证码接口 测试
def test01_img_code(self):
# 1、调用图片验证码接口
r = self.reg.api_img_code(123)
# 2、查看响应状态码
print(r.status_code)
# 获取短信验证码接口 测试
def test02_phone_code(self, phone=13600001111, imgVerifyCode=8888):
# 1、调用获取图片验证码接口----目的:让session记住cookie
self.reg.api_img_code(123)
# 2、调用短信验证码接口
r = self.reg.api_phone_code(phone=phone, imgVerifyCode=imgVerifyCode)
# 3、查看响应结果
print(r.json())
# 注册接口测试
def test03_register(self, phone=13600001111, 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())
# 登录接口 测试
def test04_login(self, keywords=13600001111, password="test123"):
# 1、登录接口
r = self.reg.api_login(keywords=keywords, password=password)
# 2、查询结果
print(r.json())
# 查询登录状态 测试
def test05_login_status(self, keywords=13600001111, password="test123"):
# 1、调用登录接口
self.reg.api_login(keywords=keywords, password=password)
# 2、调用查询登录结果接口
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):
# 获取session对象
self.session = requests.session()
# 获取ApiRegisterLogin实例
self.reg = ApiRegisterLogin(self.session)
# 结束
def tearDown(self):
# 关闭session对象
self.session.close()
# 获取图片验证码接口 测试
def test01_img_code(self):
try:
# 1、调用图片验证码接口
r = self.reg.api_img_code(123)
# 2、查看响应状态码
self.assertEqual(200, r.status_code)
except Exception as e:
# 日志
print(e)
# 抛出异常
raise
# 获取短信验证码接口 测试
def test02_phone_code(self, phone=13600001111, imgVerifyCode=8888, expect_text="发送成功"):
try:
# 1、调用获取图片验证码接口----目的:让session记住cookie
self.reg.api_img_code(123)
# 2、调用短信验证码接口
r = self.reg.api_phone_code(phone=phone, imgVerifyCode=imgVerifyCode)
# 3、查看响应结果
self.assertIn(expect_text, r.text)
except Exception as e:
# 日志
print(e)
# 抛出异常
raise
# 注册接口测试
def test03_register(self, phone=13600001111, 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、查看结果
self.assertIn(expect_text, r.text)
except Exception as e:
# 日志
print(e)
# 抛出异常
raise
# 登录接口 测试
def test04_login(self, keywords=13600001111, password="test123", expect_text="登录成功"):
try:
# 1、登录接口
r = self.reg.api_login(keywords=keywords, password=password)
# 2、查询结果
self.assertIn(expect_text, r.text)
except Exception as e:
# 日志
print(e)
# 抛异常
raise
# 查询登录状态 测试
def test05_login_status(self, keywords=13600001111, password="test123", expect_text="OK"):
try:
# 1、调用登录接口
self.reg.api_login(keywords=keywords, password=password)
# 2、调用查询登录结果接口
r = self.reg.api_login_status()
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、每组数据{}中
,组成格式:说明+参数+预期结果
- 几个接口几个key,这里有五个接口(图片验证码、短信验证码、注册、登录、登录状态接口)
- 每组数据组成格式:说明+参数+预期结果
{
"img_code": [
{
"desc": "获取图片验证码成功(随机小数)",
"random": "0.123",
"expect_code": 200
},
{
"desc": "获取图片验证码成功(随机整数)",
"random": "123",
"expect_code": 200
},
{
"desc": "获取图片验证码成功(随机数为空)",
"random": "",
"expect_code": 404
},
{
"desc": "获取图片验证码成功(随机数为字符串)",
"random": "heloo123",
"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,
"dy_server": "on",
"expect_text": "注册成功"
},{
"desc": "注册失败(图片验证码错误)",
"phone": "13600001112",
"password": "test123",
"verifycode": 8889,
"phone_code": 666666,
"dy_server": "on",
"expect_text": "验证码错误"
},{
"desc": "注册失败(短信验证码错误)",
"phone": "13600001112",
"password": "test123",
"verifycode": 8888,
"phone_code": 666667,
"dy_server": "on",
"expect_text": "验证码错误"
},{
"desc": "注册失败(手机号已存在)",
"phone": "13600001111",
"password": "test123",
"verifycode": 8888,
"phone_code": 666666,
"dy_server": "on",
"expect_text": "已存在"
}
],
"login": [
{
"desc": "登录成功",
"keywords": "13600001111",
"password": "test123",
"expect_text": "登录成功"
}, {
"desc": "登录失败(密码为空)",
"keywords": "13600001111",
"password": "",
"expect_text": "不能为空"
}, {
"desc": "登录失败(解锁)",
"keywords": "13600001111",
"password": "errror123",
"expect_text": "登录成功"
}
],
"login_status": [
{
"desc": "查询登录状态(已登录)",
"status": "已登录",
"expect_text": "OK"
}, {
"desc": "查询登录状态(未登录)",
"status": "未登录",
"expect_text": "未登"
}
]
}
- 2、编写读取数据工具(util.py)
from config import DIR_PATH
def read_json(filename, key):
# 拼接读取文件的完整路径 os.sep动态获取/ 还是 \ ,根据电脑的操作系统
file_path = DIR_PATH + os.sep + "data" + os.sep + filename
arr = []
with open(file_path, 'r', encoding="utf-8") as f:
# print(json.load(f))
# print(json.load(f).get(key)) [{},{},{}]----->[(),(),()]
for data in json.load(f).get(key):
arr.append(tuple(data.values())[1:])
print(arr)
if __name__ == '__main__':
read_json("register_login.json", "img_code")
# [('0.123', 200), ('123', 200), ('', 404), ('heloo123', 400)]
- 参数化引用
- 难点1:错误次数锁定
# 登录接口 测试
@parameterized.expand(read_json("register_login.json", "login"))
def test04_login(self, keywords, password, expect_text):
try:
i = 1
if "error" in password:
while i <= 3:
r = self.reg.api_login(keywords=keywords, password=password)
i += 1
# 断言锁定
print("测试锁定:", r.text)
self.assertIn("锁定", r.text)
# 暂停60s
sleep(60)
# 测试登录成功
r = self.reg.api_login(keywords="13600001111", password="test123")
self.assertIn(expect_text, r.text)
# 1、登录接口
r = self.reg.api_login(keywords=keywords, password=password)
# 2、查询结果
self.assertIn(expect_text, r.text)
except Exception as e:
# 日志
print(e)
# 抛异常
raise
- 查询登录状态,不同结果。
# 查询登录状态 测试
@parameterized.expand(read_json("register_login.json", "login_status"))
def test05_login_status(self, status, expect_text):
try:
if status == "已登录":
# 1、调用登录接口
self.reg.api_login(keywords="13600001111", password="test123")
# 2、调用查询登录结果接口
r = self.reg.api_login_status()
self.assertIn(expect_text, r.text)
except Exception as e:
# 日志
print(e)
# 抛出异常
raise
- 断言代码示例:(test01_register_login.py)
import unittest
import requests
from api.api_register_login import ApiRegisterLogin
from parameterized import parameterized
from util import read_json
from time import sleep
class TestRegisterLogin(unittest.TestCase):
# 初始化
def setUp(self):
# 获取session对象
self.session = requests.session()
# 获取ApiRegisterLogin实例
self.reg = ApiRegisterLogin(self.session)
# 结束
def tearDown(self):
# 关闭session对象
self.session.close()
# 获取图片验证码接口 测试
@parameterized.expand(read_json("register_login.json", "img_code"))
def test01_img_code(self, random, expect_code):
try:
# 1、调用图片验证码接口
r = self.reg.api_img_code(random)
# 2、查看响应状态码
self.assertEqual(expect_code, r.status_code)
except Exception as e:
# 日志
print(e)
# 抛出异常
raise
# 获取短信验证码接口 测试
@parameterized.expand(read_json("register_login.json", "phone_code"))
def test02_phone_code(self, phone, imgVerifyCode, expect_text):
try:
# 1、调用获取图片验证码接口----目的:让session记住cookie
self.reg.api_img_code(123)
# 2、调用短信验证码接口
r = self.reg.api_phone_code(phone=phone, imgVerifyCode=imgVerifyCode)
# 3、查看响应结果
self.assertIn(expect_text, r.text)
except Exception as e:
# 日志
print(e)
# 抛出异常
raise
# 注册接口测试
@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、查看结果
self.assertIn(expect_text, r.text)
except Exception as e:
# 日志
print(e)
# 抛出异常
raise
# 登录接口 测试
@parameterized.expand(read_json("register_login.json", "login"))
def test04_login(self, keywords, password, expect_text):
try:
i = 1
if "error" in password:
while i <= 3:
r = self.reg.api_login(keywords=keywords, password=password)
i += 1
# 断言锁定
print("测试锁定:", r.text)
self.assertIn("锁定", r.text)
# 暂停60s
sleep(60)
# 测试登录成功
r = self.reg.api_login(keywords="13600001111", password="test123")
self.assertIn(expect_text, r.text)
# 1、登录接口
r = self.reg.api_login(keywords=keywords, password=password)
# 2、查询结果
self.assertIn(expect_text, r.text)
except Exception as e:
# 日志
print(e)
# 抛异常
raise
# 查询登录状态 测试
@parameterized.expand(read_json("register_login.json", "login_status"))
def test05_login_status(self, status, expect_text):
try:
if status == "已登录":
# 1、调用登录接口
self.reg.api_login(keywords="13600001111", password="test123")
# 2、调用查询登录结果接口
r = self.reg.api_login_status()
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
# 设置级别,level=logging.DEBUG制定日志级别,filename存储日志文件,不会打印在控制台
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
import logging.handlers
import os
class GetLog:
__logger = None # 类变量,确保日志器单例
@classmethod
def get_log(cls):
if cls.__logger is None: # 只初始化一次
cls.__logger = logging.getLogger("MyLogger") # 指定日志器名称
cls.__logger.setLevel(logging.INFO) # 设置日志级别
# 确保日志目录存在
log_dir = os.path.join(os.getcwd(), "log")
if not os.path.exists(log_dir):
os.makedirs(log_dir)
file_path = os.path.join(log_dir, "p2p.log")
# 创建处理器(定时滚动日志)
tf = logging.handlers.TimedRotatingFileHandler(
filename=file_path,
when="midnight",
interval=1,
backupCount=3,
encoding="utf-8"
)
# 设置日志格式
fmt = "%(asctime)s %(levelname)s [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s"
fm = logging.Formatter(fmt)
tf.setFormatter(fm)
# 只添加一次处理器
cls.__logger.addHandler(tf)
return cls.__logger # 返回日志器
if __name__ == '__main__':
logger = GetLog.get_log()
logger.info("信息级别测试")