python测试脚本编写规范_自动化测试脚本的编写

需求:

从Excel中读取记录行(每一行就是一个API(url,请求类型,名称,描述,参数,预期值))

使用参数化对每一次的请求,要使用requests发请求,获取请求结果,从结果中提取字段,跟预期值做断言,

使用allure生成测试报告

为每一个请求用例添加title和description

将测试报告发邮件

问题:发邮件的时候,能发文件夹吗?答案是不能,

解决办法是:将allure报告文件夹打包成zip

发送zip文件

在你认为的关键点添加上log日志

请求的时候

断言的时候

可选打包的时候

读Excel的时候

为了解耦合,需要遵循软件开发规范

数据文件夹

配置文件夹

脚本文件夹

等等

如果写的困难得,可以在一个文件中实现

用到的知识点:

requests

pytest

Excel表格操作

发邮件

日志功能

项目开发规范的目录应用

allure

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', 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 = "xxxx@qq.com"

# 获取授权码

mail_pass = "mpaocydzpzfjidge"

# 发件人账号

sender = 'xxxx@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)

pass

# os.remove(report_path)

# shutil.rmtree(report_path)

#查看路径:

# print(sys.path)

#查看包:

# print(sys.modules)

三、配置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("请求的URL:{}


"

"请求的类型:{}


"

"实际值:{}


"

"预期值:{}


"

"".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()

八、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

# 创建一个带附件的实例

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()

# 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()

十、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')

十一、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):

""" 检查请求参数 """

params = self.d.get("case_params")

if params:

return {}

else:

return {}

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)

十二、run.py程序执行入口:

import shutil

import pytest

from utils.AllureHandler import AllureHandler

from conf import settings

if __name__ == '__main__':

pytest.main()

# shutil.rmtree(r"D:\s27\day69包含log日志功能\nb\report")

a = AllureHandler()

a.execute_command()

a.zip()

a.send_email()

十三、效果展示:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值