pytest的配置相关流程包含日志功能:
1.把软件开发规范的相关目录建立起来
2、配置settings:
import os
import datetime
import shutil
import sys
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# print(base_dir) #D:\s27\day69\nb
# 定义文件名字:
file_name = "接口测试示例.xlsx"
# 路径拼接:
file_path = os.path.join(base_dir, "data", file_name)
# print(file_path) #D:\s27\day69\nb\data\接口测试示例.xlsx
# ---------------- 日志相关 --------------------
# 日志级别
LOG_LEVEL = 'debug'
# 屏幕输出流
LOG_STREAM_LEVEL = 'debug'
# 文件输出流
LOG_FILE_LEVEL = 'info'
# 日志文件命名
LOG_FILE_NAME = os.path.join(base_dir, 'logs', datetime.datetime.now().strftime('%Y-%m-%d') + '.log')
# allure报告相关:
report_path = os.path.join(base_dir, "report")
result_path = os.path.join(base_dir, "report", "result")
allure_html_path = os.path.join(base_dir, "report", "allure_html")
command = "allure generate {} -o {} --clean".format(result_path, allure_html_path)
# 要打包的根目录:
zip_case_result_path = allure_html_path
# 要打包的文件名:
zip_file_name = "allure_report.zip"
# 将打包文件存放哪去:
zip_save_path = report_path
# 邮箱相关:
# 第三方 SMTP 服务
# 设置服务器
mail_host = "smtp.qq.com"
# 用户名
mail_user = "1320685524@qq.com"
# 获取授权码
mail_pass = "mpaocydzpzfjidge"
# 发件人账号
sender = '1320685524@qq.com'
# 接收邮件,可设置为你的QQ邮箱或者其他邮箱和多个收件人
receivers = ['1320685524@qq.com']
# 邮件主题:
subject = 'Python发送带附件的邮件示例'
# 邮件正文内容
send_content = '这是今天的测试用例报告,请下载附件并使用pycharm打开'
# 邮件附件路径:
send_file_path = os.path.join(zip_save_path, zip_file_name)
send_file_name = zip_file_name
if __name__ == '__main__':
print(send_file_path)
# os.remove(report_path)
# shutil.rmtree(report_path)
#查看路径:
# print(sys.path)
#查看包:
# print(sys.modules)
3.配置pytest.ini
[pytest]
addopts = -s -v --alluredir ./report/result
testpaths = ./scripts
python_files = test_*.py
python_classes = Test*
python_functions = test_*
4.创建入口文件run.py
if __name__ == '__main__':
import pytest
pytest.main()
5.创建用例脚本文件test_case.py
import pytest
import allure
from utils.ExcelHandler import Excel
from utils.LogHandler import logger
from utils.RequestHandler import RequestHandler
from utils.AllureHandler import AllureHandler
@pytest.mark.parametrize("d", Excel().get_excel_data())
def test_case(d):
print(d)
result = RequestHandler(d).get_response()
# logger().info(d)
allure.dynamic.title(d["case_project"])
allure.dynamic.description("<font color='red'>请求的URL:</font>{}<hr />"
"<font color='red'>请求的类型:</font>{}<hr />"
"<font color='red'>实际值:</font>{}<hr />"
"<font color='red'>预期值:</font>{}<hr />"
"".format(d["case_url"],
d["case_method"],
result[1],
result[0],
))
assert result[0] == result[1]
# def teardown_module():
# allure_obj = AllureHandler()
"""生成allure测试报告"""
# allure_obj.execute_command()
"""打包文件"""
# allure_obj.zip()
"""发送邮件"""
# allure_obj.send_email()
6.调通它们
7.#参数化
1.使用参数化
2.获取Excel表格数据
AllureHandler.py
"""
执行allure命令生成报告
打包allure报告
发送压缩包
"""
import os
# 导入压缩文件用的模块
import zipfile
import smtplib
import shutil
import time
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from conf import settings
from utils.LogHandler import logger
from subprocess import call, Popen
class AllureHandler(object):
def __init__(self):
"""清空report目录,以便后续方便操作"""
# shutil.rmtree(settings.report_path)
pass
def execute_command(self):
"""执行allure命令"""
# time.sleep(5)
logger().info("执行生成allure报告:{}".format(settings.command))
# os.system(settings.command)
# shell=True是可以识别字符串的命令:
call(settings.command, shell=True)
def zip(self):
"""打包allure报告"""
# 日志:
logger().info("打包文件名:{},打包到:{}".format(settings.zip_file_name, settings.zip_save_path))
# 要压缩文件夹的根路径并拼接:
base_dir = settings.zip_case_result_path
zip_file_name = settings.zip_file_name
# 保存打包文件的路径:
f = zipfile.ZipFile(os.path.join(settings.zip_save_path, zip_file_name), 'w', zipfile.ZIP_DEFLATED)
for dir_path, dir_name, file_names in os.walk(base_dir):
# 要是不replace,就从根目录开始复制
file_path = dir_path.replace(base_dir, '')
# 实现当前文件夹以及包含的所有文件
file_path = file_path and file_path + os.sep or ''
for file_name in file_names:
f.write(os.path.join(dir_path, file_name), file_path + file_name)
f.close()
def send_email(self):
"""将打包的allure文件发送给指定邮箱"""
logger().info("正在向{}发送邮件,请稍后.......".format(settings.receivers))
# 第三方SMTP服务
# 设置服务器
mail_host = settings.mail_host
# 用户名
mail_user = settings.mail_user
# 获取授权码
mail_pass = settings.mail_pass
# 发件人账号
sender = settings.sender
# 接收邮件,可设置为你的QQ邮箱或者其他邮箱和多个收件人
receivers = settings.receivers
# 邮件主题:
subject = settings.subject
# 创建一个带附件的实例
message = MIMEMultipart()
# 发件人
message['From'] = Header("我是发件人", 'utf-8')
# 收件人
message['To'] = Header("我是收件人", 'utf-8')
# 邮件主题
subject = settings.subject
message['Subject'] = Header(subject, 'utf-8')
# 邮件正文内容
send_content = settings.send_content
content_obj = MIMEText(send_content, 'plain', 'utf-8')
message.attach(content_obj)
# 构造附件1,发送当前目录下的 t1.txt 文件
att1 = MIMEText(open(settings.send_file_path, 'rb').read(), "base64", "utf-8")
# 基于流的模式
att1["Content-Type"] = "application/octet-stream"
# 文件描述、filename是附件中显示的名字
att1["Content-Disposition"] = "attachment;filename = '{}'".format(settings.send_file_name)
message.attach(att1)
# 构造附件2,发送当前目录下的t2.py文件
# att2 = MIMEText(open("t2.py", "rb").read(), "base64", "utf-8")
#
# # 基于流的模式
# att2["Content-Type"] = "application/octet-stream"
#
# # 文件描述、filename是附件中显示的名字
# att2["Content-Disposition"] = "attachment;filename = 't2.py'"
# message.attach(att2)
try:
smtpObj = smtplib.SMTP()
# 25 为 SMTP 端口号
smtpObj.connect(mail_host, 25)
smtpObj.login(mail_user, mail_pass)
smtpObj.sendmail(sender, receivers, message.as_string())
logger().info("向{}发送邮件成功".format(settings.receivers))
except smtplib.SMTPException as e:
logger().error("向{}发送邮件失败,可能的原因:{}".format(settings.receivers, e))
ExcelHandler.py
import xlrd
from conf import settings
from utils.LogHandler import logger
class Excel(object):
def get_excel_data(self):
"""获取excel表格数据"""
logger().info("读取Excel表格{} {}".format(settings.file_name,settings.file_path))
book = xlrd.open_workbook(filename=settings.file_path)
sheet = book.sheet_by_index(0)
# print(sheet.nrows) #8
title = sheet.row_values(0)
l = []
for row in range(1, sheet.nrows):
# print(sheet.row_values(row))
l.append(dict(zip(title, sheet.row_values(row))))
# print(l)
return l
if __name__ == '__main__':
Excel().get_excel_data()
8.#配置日志信息记录相关
LogHandler.py
import logging
from conf import settings
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)
# 设置输出流级别
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):
"""伪装成属性返回logger对象"""
return self.logger
def logger(log_name='接口测试'):
return LoggerHandler(
log_name=log_name,
logger_level=settings.LOG_LEVEL,
file_name=settings.LOG_FILE_NAME,
stream_level=settings.LOG_STREAM_LEVEL,
file_level=settings.LOG_FILE_LEVEL
).get_logger
if __name__ == '__main__':
logger().debug('aaaa')
logger().info('aaaa')
logger().warning('aaaa')
9.#请求相关
1.从参数中获取相关数据发请求
2.做断言
3.断言结果返回
RequestHandler.py
import requests
import json
from utils.LogHandler import logger
from bs4 import BeautifulSoup
class RequestHandler(object):
def __init__(self, d):
self.d = d
def get_response(self):
"""获取请求结果"""
return self.send_msg()
def _response_application(self, response):
"""校验json类型的返回"""
response = response.json()
expect = json.loads(self.d.get("case_expect"))
for k in expect:
if expect[k] != response.get(k, "没有这个key:{}".format(k)):
return {k: expect[k]}, {k: response.get(k, "没有这个key:{}".format(k))}
return {k: expect[k]}, {k: response.get(k, "没有这个key:{}".format(k))}
def _response_text(self, response):
"""校验文本类型的返回"""
# response.title()
soup = BeautifulSoup(response.text, "html.parser")
title = soup.find(name="title").text
# print(title.text)
logger().info("文本类型的请求结果,预期值:{} | 实际值:{}".format(self.d.get("case_expect"), title))
return title, self.d.get("case_expect")
def send_msg(self):
"""发请求"""
logger().info("请求URL:{},类型:{}".format(self.d.get("case_url"), self.d.get("case_method")))
response = requests.request(
method=self.d.get("case_method"),
url=self.d.get("case_url"),
# params=self._check_params(),
# data=self._check_data()
)
header = response.headers["Content-Type"].split("/", 1)[0]
# header = _response_application
if hasattr(self, "_response_{}".format(header)):
a = getattr(self, "_response_{}".format(header))
result = a(response)
logger().info("预期值:{} 实际值:{}".format(result[0], result[1]))
return result
def _check_params(self):
"""检查请求参数"""
params = self.d.get("case_params")
if params:
return {}
else:
return {}
def _check_data(self):
pass
if __name__ == '__main__':
# r1 = requests.get("https://www.cnblogs.com/Neeo/articles/10951734.html")
# print(r1.text)
# print(r1.headers)
# print(r1.title)
pass
# r2 = requests.get("https://www.v2ex.com/api/site/info.json")
# print(r2.headers)
# r3 = requests.post("https://cnodejs.org/api/v1/message/mark_all")
# print(r3.headers)
10.#生成测试报告
使用 allure generate report/result -o report/allure_html --clean 生成allur报告
执行命令的方法:
os.system()
subprocess
11.#将allure测试报告打包
12.#将压缩包fayd
13.效果如下