自动化测试脚本的编写
⾃动化测试脚本的编写需求:
1. 从Excel中读取记录⾏(每⼀⾏就是⼀个API(url,请求类型,名称,描述,参数,预期值))
2. 使⽤参数化对每⼀次的请求,要使⽤requests发请求,获取请求结果,从结果中提取字段,跟预期值做断⾔,
3. 使⽤allure⽣成测试报告
1. 为每⼀个请求⽤例添加title和description
4. 将测试报告发邮件
1. 问题:发邮件的时候,能发⽂件夹吗?答案是不能,
2. 解决办法是:将allure报告⽂件夹打包成zip
3. 发送zip⽂件
5. 在你认为的关键点添加上log⽇志
1. 请求的时候
2. 断⾔的时候
3. 可选打包的时候
4. 读Excel的时候
6. 为了解耦合,需要遵循软件开发规范
1. 数据⽂件夹
2. 配置⽂件夹
3. 脚本⽂件夹
4. 等等
7. 如果写的困难得,可以在⼀个⽂件中实现
⽤到的知识点:
1. requests
2. pytest
3. Excel表格操作
4. 发邮件
5. ⽇志功能
6. 项⽬开发规范的⽬录应⽤
7. allure
1. title知识点
      2.description知识点
⼀、1.把软件开发规范的相关⽬录建⽴起来:
⼆、配置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', w().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"
# ⽤户名
mail_user = "xxxx@qq"
# 获取授权码
mail_pass = "mpaocydzpzfjidge"
# 发件⼈账号
sender = 'xxxx@qq'
# 接收邮件,可设置为你的QQ邮箱或者其他邮箱和多个收件⼈
receivers = ['1320685524@qq']
# 邮件主题:
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)
pass
# os.remove(report_path)
# (report_path)
#查看路径:
# print(sys.path)
#查看包:
# dules)
三、配置pytest.ini:
[pytest]
addopts = -s -v --alluredir ./report/result
testpaths = ./scripts
python_files = test_*.py
python_classes = Test*
python_functions = test_*
四、data数据⽂件接⼝测试⽰例.xlsx:
五、logs⽇志⽂件:
六、report报告:
七、scripts测试⽤例:
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测试报告"""
# ute_command()
"""打包⽂件"""
# allure_obj.zip()
"""发送邮件"""
# allure_obj.send_email()
⼋、AllureHandler.py报告功能:
"""
执⾏allure命令⽣成报告
打包allure报告
发送压缩包
"""
import os
# 导⼊压缩⽂件⽤的模块
import zipfile
import smtplib
import shutil
import time
from 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⽬录,以便后续⽅便操作"""
# (port_path)
pass
def execute_command(self):
"""执⾏allure命令"""
# time.sleep(5)
logger().info("执⾏⽣成allure报告:{}".format(settingsmand))
# os.system(settingsmand)
# shell=True是可以识别字符串的命令:
call(settingsmand, 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 = place(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("正在向{}发送邮件,请稍后.......".ivers))
# 第三⽅SMTP服务
# 设置服务器
mail_host = settings.mail_host
# ⽤户名
mail_user = settings.mail_user
# 获取授权码
mail_pass = settings.mail_pass
# 发件⼈账号
sender = settings.sender
# 接收邮件,可设置为你的QQ邮箱或者其他邮箱和多个收件⼈
receivers = ivers
# 创建⼀个带附件的实例
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,发送当前⽬录下的⽂件
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()
a45 amg# 25 为 SMTP 端⼝号
smtpObj.login(mail_user, mail_pass)
smtpObj.sendmail(sender, receivers, message.as_string())
logger().info("向{}发送邮件成功".ivers))
except smtplib.SMTPException as e:
logger().error("向{}发送邮件失败,可能的原因:{}".ivers, 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)
# ws)  #8
title = w_values(0)
l = []
for row in range(1, ws):
# w_values(row))
l.append(dict(zip(title, w_values(row))))
# print(l)
return l
if __name__ == '__main__':
Excel().get_excel_data()
⼗、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, 'debug')
self.stream_level = self._(stream_level, 'info')
self.file_level = self._(file_level, 'warning')
# 创建⽇志对象
self.logger = Logger(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')
360无法卸载⼗⼀、RequestHandler.py请求功能:
import requests
import json
from utils.LogHandler import logger
from bs4 import BeautifulSoup
class RequestHandler(object):
betterdef __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(("case_expect"))
for k in expect:
if expect[k] != (k, "没有这个key:{}".format(k)):
return {k: expect[k]}, {k: (k, "没有这个key:{}".format(k))}
return {k: expect[k]}, {k: (k, "没有这个key:{}".format(k))}
def _response_text(self, response):
"""校验⽂本类型的返回"""
# response.title()
soup = , "html.parser")
title = soup.find(name="title").text
# )
logger().info("⽂本类型的请求结果,预期值:{} | 实际值:{}".format(("case_expect"), title))        return title, ("case_expect")
def send_msg(self):
"""发请求"""
海贼王之空气果实logger().info("请求URL:{},类型:{}".format(("case_url"), ("case_method")))
response = quest(
method=("case_method"),
url=("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 = ("case_params")
if params:
return {}
else:
return {}
def _check_data(self):
""" 检查请求参数 """
params = ("case_params")
if params:
return {}
else:
return {}
if __name__ == '__main__':
# r1 = ("wwwblogs/Neeo/articles/10951734.html")
# )
# print(r1.headers)
# print(r1.title)
pass
# r2 = ("www.v2ex/api/site/info.json")
# print(r2.headers)
# r3 = requests.post("/api/v1/message/mark_all")
# print(r3.headers)
⼗⼆、run.py程序执⾏⼊⼝:
import shutil
import pytest
from utils.AllureHandler import AllureHandler
from conf import settings
if __name__ == '__main__':
pytest.main()
# (r"D:\s27\day69包含log⽇志功能\nb\report")
a = AllureHandler()
a.zip()
a.send_email()
⼗三、效果展⽰:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。