用例示范
目錄結構
1.demo
demo1.py
'''
pip install xlrd
pip install xlwt
'''
import xlrd
import json
import requests
from bs4 import BeautifulSoup
import xlrd
# row 是行
# col 是列
file_path = r'接口測試示例.xlsx'
# 拿到book對象 xlrd.open_workbook方法
book = xlrd.open_workbook(file_path)
print(book)
# 拿到表格中對象 按索引獲取
sheet = book.sheet_by_index(0)
print(sheet)
# 按名字獲取
sheet1 = book.sheet_by_name('接口自動化用例')
print(sheet1)
# 行,列 獲取到所有的行和列 sheet.nrows方法, sheet.ncols方法
rows, cols = sheet.nrows, sheet.ncols
print(rows, cols)
# for循環出每一行
for row in range(rows):
print(sheet.row_values(row))
# for循環出每一列
for col in range(cols):
print(sheet.col_values(col))
# 按索引取出行列
print(sheet.row_values(2))
print(sheet.col_values(0))
print(sheet.cell(0, 0))
# 將行和列的值拼接在一起 組合成[{},{}]的樣式 zip拉在一起 dict轉一下
l = []
title = sheet.row_values(0)
for i in range(1, rows):
l.append(dict(zip(title, sheet.row_values(i))))
print(l)
def get_excel_data():
file_path = r'接口測試示例.xlsx'
# 獲取到book對象
book = xlrd.open_workbook(file_path)
# print(book)
# 獲取sheet對象
sheet = book.sheet_by_index(0)
# sheet = book.sheet_by_name('接口自動化用例')
# sheets = book.sheets() # 獲取所有的sheet對象
rows, cols = sheet.nrows, sheet.ncols
l = []
# print(sheet.row_values(0))
title = sheet.row_values(0)
# print(title)
# 獲取其他行
for i in range(1, rows):
# print(sheet.row_values(i))
l.append(dict(zip(title, sheet.row_values(i))))
return l
r = requests.get('https://www.cnblogs.com/Neeo/articles/11667962.html')
s = BeautifulSoup(r.text, 'html.parser')
print(s.find('title').text)
2.uti
ExcelHandler
'''
關於Excel表的操作
'''
import xlrd
from settings import conf
class ExcelHandler(object):
@property
def get_excel_data(self):
# 獲取到book對象
book = xlrd.open_workbook(conf.TEST_CASE_PATH)
# print(book)
# 獲取sheet對象
sheet = book.sheet_by_index(0)
# sheet = book.sheet_by_name('接口自動化用例')
# sheets = book.sheets() # 獲取所有的sheet對象
rows, cols = sheet.nrows, sheet.ncols
l = []
# print(sheet.row_values(0))
title = sheet.row_values(0)
# print(title)
# 獲取其他行
for i in range(1, rows):
# print(sheet.row_values(i))
l.append(dict(zip(title, sheet.row_values(i))))
return l
RequestsHandler.py
'''
請求相關
'''
import json
import requests
from bs4 import BeautifulSoup
from uti.LoggerHandler import logger
class RequestHandler(object):
def __init__(self, case):
self.case = case
try:
self.case_expect = json.loads(self.case['case_expect'])
except:
self.case_expect = self.case['case_expect']
@property
def get_response(self):
""" 獲取請求結果 """
response = self.send_request()
return response
def send_request(self):
""" 發請求 """
try:
response = requests.request(
method=self.case['case_method'],
url=self.case['case_url'],
params=self._check_params()
)
content_type = response.headers['Content-Type']
content_type = content_type.split(";")[0].split('/')[-1] if ';' in content_type else \
content_type.split("/")[-1]
if hasattr(self, '_check_{}_response'.format(content_type)):
response = getattr(self, '_check_{}_response'.format(content_type))(response)
else:
raise '返回類型為: {}, 無法解析'.format(content_type)
except:
logger().error({'response': "請求發送失敗,詳細信息: url={}".format(self.case['case_url'])})
return {'response': "請求發送失敗,詳細信息: url={}".format(self.case['case_url'])}, self.case['case_expect']
return response
def _check_json_response(self, response):
""" 處理json類型的返回值 """
response = response.json() # {'success': True}
for key in self.case_expect:
if self.case_expect[key] != response[key]: # 用例執行失敗的
return {key: self.case_expect[key]}, {key: response[key]}
else: # 執行成功
logger("發送請求").info('{} 執行成功'.format(self.case['case_url']))
return {key: self.case_expect[key]}, {key: response[key]}
def _check_html_response(self, response):
""" 校驗html類型的數據"""
soup_obj = BeautifulSoup(response.text, 'html.parser')
title = soup_obj.find('title').text
return title, self.case_expect
def _check_params(self):
""" 整理參數 """
if self.case['case_params']:
"""
做擴展
"""
pass
else:
return {}
AllureHandler
import subprocess
from settings import conf
class AllureHandler(object):
def execute_command(self):
import time
time.sleep(1)
subprocess.call(conf.ALLURE_COMMAND, shell=True)
EmailHandler
'''
發郵件
'''
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from settings import conf
from uti.LoggerHandler import logger
class EmailHandler(object):
def read_report(self):
f = open(conf.TEST_CASE_REPORT_PATH, 'rb')
return f.read()
def send_email(self):
""" 發送郵件 """
# 第三方 SMTP 服務
mail_host = "smtp.qq.com" # 設置服務器
mail_user = "xxx@qq.com" # 用戶名
mail_pass = "xxx" # 口令
# 獲取口令地址 https://www.cnblogs.com/zhangshan33/p/11943755.html
# 設置收件人和發件人
sender = 'xxx@qq.com'
receivers = ['xxx@qq.com', ] # 接收郵件,可設置為你的QQ郵箱或者其他郵箱
# 創建一個帶附件的實例對象
message = MIMEMultipart()
# 郵件主題、收件人、發件人
subject = '請查閱--測試報告' # 郵件主題
message['Subject'] = Header(subject, 'utf-8')
message['From'] = Header("{}".format(sender), 'utf-8') # 發件人
message['To'] = Header("{}".format(';'.join(receivers)), 'utf-8') # 收件人
# 郵件正文內容 html 形式郵件
send_content = self.read_report() # 獲取測試報告
html = MIMEText(_text=send_content, _subtype='html', _charset='utf-8') # 第一個參數為郵件內容
# 構造附件
att = MIMEText(_text=send_content, _subtype='base64', _charset='utf-8')
att["Content-Type"] = 'application/octet-stream'
file_name = 'report.html'
att["Content-Disposition"] = 'attachment; filename="{}"'.format(file_name) # # filename 為郵件附件中顯示什么名字
message.attach(html)
message.attach(att)
try:
smtp_obj = smtplib.SMTP()
smtp_obj.connect(mail_host, 25) # 25 為 SMTP 端口號
smtp_obj.login(mail_user, mail_pass)
smtp_obj.sendmail(sender, receivers, message.as_string())
smtp_obj.quit()
logger().info("郵件發送成功")
except smtplib.SMTPException:
logger().error("Error: 無法發送郵件")
LoggerHandler
import logging
from settings import conf
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):
return self.logger
def logger(log_name='接口測試'):
return LoggerHandler(
log_name=log_name,
logger_level=conf.LOG_LEVEL,
file_name=conf.LOG_FILE_NAME,
stream_level=conf.LOG_STREAM_LEVEL,
file_level=conf.LOG_FILE_LEVEL
).get_logger
if __name__ == '__main__':
logger().debug('aaaa')
logger().info('aaaa')
logger().warning('aaaa')
3.scripts
test_case
import pytest
import allure
from uti.ExcelHandler import ExcelHandler
from uti.RequestHandler import RequestHandler
from uti.AllureHandler import AllureHandler
from uti.EmailHandler import EmailHandler
'''
1. 拿到Excel數據
2. 發請求
3. 生成測試用例報告
4. 發郵件
5. 斷言
'''
class Test_case(object):
@pytest.mark.parametrize('case', ExcelHandler().get_excel_data)
def test_case(self, case):
""" 執行斷言 """
# print(case)
# 發請求
response = RequestHandler(case).get_response
# 制作 allure 報告
allure.dynamic.title(case['case_project'])
allure.dynamic.description('<font color="red">請求URL:</font>{}<br />'
'<font color="red">期望值:</font>{}'.format(case['case_url'], case['case_description']))
allure.dynamic.feature(case['case_project'])
allure.dynamic.story(case['case_method'])
assert response[0] == response[1]
def teardown_class(self):
""" 執行alllure命令 """
AllureHandler().execute_command()
# 發郵件
EmailHandler().send_email()
4.settings
conf.py
import os
import datetime
BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 腳本路徑
file_path = '接口測試示例.xlsx'
TEST_CASE_PATH = os.path.join(BASE_PATH, 'data', file_path)
# 報告路徑
TEST_CASE_REPORT_PATH = os.path.join(BASE_PATH, 'report', 'report.html')
# CASE_METHOD = 'case_method'
# ------------ allure 相關配置 -----------
result_path = os.path.join(BASE_PATH, 'report', 'result')
allure_html_path = os.path.join(BASE_PATH, 'report', 'allure_html')
ALLURE_COMMAND = 'allure generate {} -o {} --clean'.format(result_path, allure_html_path)
# ---------------- 日志相關 --------------------
# 日志級別
LOG_LEVEL = 'debug'
LOG_STREAM_LEVEL = 'debug' # 屏幕輸出流
LOG_FILE_LEVEL = 'info' # 文件輸出流
# 日志文件命名
LOG_FILE_NAME = os.path.join(BASE_PATH, 'logs', datetime.datetime.now().strftime('%Y-%m-%d') + '.log')
if __name__ == '__main__':
print(TEST_CASE_PATH)
5.pytest.ini
[pytest]
addopts = -s -v --html=report/report.html --alluredir ./report/result
testpaths = ./scripts
python_files = test_*.py
python_classes = Test*
python_functions = test_*
6.run.py
import pytest
if __name__ == '__main__':
pytest.main()
7.直接右擊運行run.py文件
8.終端運行allure
allure generate report/result -o report/allure_html --clean
生成的測試報告
用瀏覽器打開
要發送的報告
用瀏覽器打開
9.郵箱收到的文件