python 接口自动化实战

项目框架:

安装pytest: pip install pytest

安装pytest-html :pip install pytest-html

安装pytest-allure :pip install pytest-allure

安装pytest-rerunfailures :pip install pytest-rerunfailures (执行失败后继续执行指定的次数 --reruns 2)

下载allure: https://www.cnblogs.com/desireyang/p/12517269.html

注意:用例保存为Microsoft excel 切勿保存为wps加密的,python读取时可能会报错

执行方式:pytest

send_request.py

import requests
import json
from utils.log_handle import logger
class SendRequest(object):
def __init__(self, case):
self.method = case["method"] if case else None
self.url = case["url"] if case else None
self.description = case["description"] if case["description"] else None
self.param = json.loads(case["param"], strict=False) if case["param"] else None
self.headers = json.loads(case["headers"], strict=False) if case["headers"] else None
self.data = json.loads(case["data"], strict=False) if case["data"] else None
self.except_result = json.loads(case["except_result"], strict=False) if case["except_result"] else None
self.Pass = True
self.row = case["number"] if case["number"] else None
# 处理是get还是post请求
def request_handle(self):
if self.method == "get":
return self.get_request()
else:
self.post_request()
# 发送get请求
def get_request(self):
rep = requests.get(url=self.url, headers=self.headers, params=self.param)
real_resutl = rep.json()
return self.assert_result(real_resutl)
# 发送post
def post_request(self):
rep = requests.post(url=self.url, headers=self.headers, data=self.param, )
real_result = rep.json()
return self.assert_result(real_result)
# 断言返回结果
def assert_result(self, real_result):
try:
assert real_result == self.except_result
logger().info("%s 断言成功" % self.description)
except:
self.Pass = False
logger().info("%s 断言失败,预计结果:%s,实际结果:%s" % (self.description,self.except_result,real_result))
raise AssertionError
finally:
from cases.bai_api import execel
# 将真实结果写入execel
execel.writeexecel(self.row, 9, str(real_result))
# 是否通过
execel.writeexecel(self.row, 10, self.Pass)
execel.saveexecel()
return real_result, self.Pass

bai_api.py

import json
import os
import pytest
from api.send_request import SendRequest
from config import caseexecel_name, ALLURE_COMMAND
from utils.email_handle import EmailHandler
from utils.excel_handle import ExecelHandle
from utils.log_handle import logger
execel = ExecelHandle(caseexecel_name)
class TestBaiDu():
@pytest.mark.parametrize("case", execel.readexecel())
def test_baidu(self, case):
logger().info("开始执行用例%s" % case["number"])
# 执行api 请求
SendRequest(case).request_handle()
# 生成allure报告
try:
# popen可以执行cmd命令
os.popen(ALLURE_COMMAND)
logger().warning("allure报告生成成功")
except:
logger().warning("输入报告错误")
#发送邮件
try:
EmailHandler().send_email()
logger().warning("邮件报告生成功")
except:
logger().warning("邮件报告生成失败")
if __name__ == '__main__':
pytest.main(["-s", "./bai_api.py"])

students.xls

这里建议保存为Microsoft excel 切勿保存为wps加密的,会报错

生成的allure 报告:

生成的pytest-html 报告:

将测试结果填入表格:

email_handle.py

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import formataddr
from config import PYTEST_HTML_PATH
from utils.log_handle import logger
class EmailHandler():
def __init__(self):
self.my_sender = 'kx113578@163.com' # 发件人邮箱账号
self.my_pass = '##########' # 发件人邮箱密码,此处为授权码
self.my_user = '1135790024@qq.com' # 收件人邮箱账号,我这边发送给自己
def email_content(self):
with open(PYTEST_HTML_PATH, "rb") as f:
return f.read()
def send_email(self):
f = self.email_content()
ret = True
try:
# 创建一个带附件的实例
message = MIMEMultipart()
msg = MIMEText('这是接口测试结果……', 'plain', 'utf-8') # 这里面写的是发送的是html
message['From'] = formataddr(["ke1", self.my_sender]) # 括号里的对应发件人邮箱昵称、发件人邮箱账号
message['To'] = formataddr(["ke2", self.my_user]) # 括号里的对应收件人邮箱昵称、收件人邮箱账号
message['Subject'] = "美丽商城接口测试" # 邮件的主题,也可以说是标题
message.attach(msg) # 邮件正文内容
# 添加附件
att1 = MIMEText(f, 'html', 'utf-8')
att1["Content-Type"] = 'application/octet-stream'
# 这里的filename可以任意写,写什么名字,邮件中显示什么名字
att1["Content-Disposition"] = 'attachment; filename="report.html"'
message.attach(att1)
# 发送邮件
server = smtplib.SMTP_SSL("smtp.163.com", 465) # 发件人邮箱中的SMTP服务器,端口是25
server.login(self.my_sender, self.my_pass) # 括号中对应的是发件人邮箱账号、邮箱密码
server.sendmail(self.my_sender, [self.my_user, ], message.as_string()) # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
server.quit() # 关闭连接
except Exception: # 如果 try 中的语句没有执行,则会执行下面的 ret=False
ret = False
logger().info("邮件发送失败")
logger().info("邮件发送成功")
return ret
if __name__ == '__main__':
EmailHandler().send_email()

execel_handle.py

import xlrd
from xlutils.copy import copy
from config import caseexecel_name, result_execel
class ExecelHandle():
# 读取excel用例
def __init__(self,name,sheet="Sheet1"):
self.name = name
self.rb = xlrd.open_workbook(self.name)
# 不能多次copy,否则只保存一次结果
self.wb = copy(self.rb)
self.ws = self.wb.get_sheet(0)
self.sheet=sheet
def readexecel(self):
self.rb = xlrd.open_workbook(self.name)
rt = self.rb.sheet_by_name(self.sheet)
self.list1=[]
for row in range(0,rt.nrows):
if row != 0:
self.list1.append(dict(zip(rt.row_values(0),rt.row_values(row))))
return self.list1
def writeexecel(self,row,col,content):
self.ws.write(row,col,content)
def saveexecel(self):
self.wb.save(result_execel)
if __name__ == '__main__':
ExecelHandle(caseexecel_name).readexecel()

log_handle.py

import logging
import config
class LoggerHandler:
""" 日志操作 """
_logger_level = {
'debug': logging.DEBUG,
'info': logging.INFO,
'warning': logging.WARNING,
'error': logging.ERROR,
'critical': logging.CRITICAL
}
def __init__(self, log_name, file_name, logger_level, stream_level='info', file_level='warning'):
self.log_name = log_name
self.file_name = file_name
self.logger_level = self._logger_level.get(logger_level, 'debug')
self.stream_level = self._logger_level.get(stream_level, 'info')
self.file_level = self._logger_level.get(file_level, 'warning')
# 创建日志对象
self.logger = logging.getLogger(self.log_name)
# 设置日志级别
self.logger.setLevel(self.logger_level)
if not self.logger.handlers:
# 设置日志输出流
f_stream = logging.StreamHandler()
f_file = logging.FileHandler(self.file_name, encoding="utf-8")
# 设置输出流级别
f_stream.setLevel(self.stream_level)
f_file.setLevel(self.file_level)
# 设置日志输出格式
formatter = logging.Formatter(
"%(asctime)s %(name)s %(levelname)s %(message)s"
)
f_stream.setFormatter(formatter)
f_file.setFormatter(formatter)
self.logger.addHandler(f_stream)
self.logger.addHandler(f_file)
@property
def get_logger(self):
return self.logger
def logger(log_name='接口测试'):
return LoggerHandler(
log_name=log_name,
logger_level=config.LOG_LEVEL,
file_name=config.LOG_FILE_NAME,
stream_level=config.LOG_STREAM_LEVEL,
file_level=config.LOG_FILE_LEVEL
).get_logger
if __name__ == '__main__':
logger().debug('aaaa')
logger().info('aaaa')
logger().warning('aaaa')

config.py

import os
import datetime
BASENAEM= os.path.dirname(os.path.abspath(__file__))
caseexecel_name = os.path.join(BASENAEM,"data","students.xls")
result_execel = os.path.join(BASENAEM,"results","students_result.xls")
result_path = os.path.join(BASENAEM, 'reports', 'result')
# ------------ allure 相关配置 -----------
allure_html_path = os.path.join(BASENAEM, 'reports', 'allure_html')
ALLURE_COMMAND = 'allure generate {} -o {} --clean'.format(result_path, allure_html_path)
#pytest-html 生成的报告
PYTEST_HTML_PATH = allure_html_path = os.path.join(BASENAEM, 'reports', 'report1.html')
#日志配置
LOG_LEVEL = 'debug'
LOG_STREAM_LEVEL = 'debug' # 屏幕输出流
LOG_FILE_LEVEL = 'info' # 文件输出流
# 日志文件命名
LOG_FILE_NAME = os.path.join(BASENAEM, 'log', datetime.datetime.now().strftime('%Y-%m-%d') + '.log')
pytest.ini
[pytest]
addopts = -s --html ./reports/report1.html --alluredir ./reports/result --reruns 2
test_paths = ./cases
python_classes = Test*
python_files = bai*.py
python_functions = test*
posted @   我是小菜鸡丫丫  阅读(486)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示