框架 pytest + allure + selenium 和 po设计思想–这个这个基类页面我还没写,所以没封装页面操作类方法,浏览器驱动的切换封装,小伙伴有兴趣可以自己研究一下顺便加一下!
目录
1.conftest.py - 进行浏览器驱动封装,以及各种回调函数
import os
import pytest
from selenium import webdriver
from py._xmlgen import html
import allure
from common import configPath
@pytest.fixture(scope='function',autouse=True)
def browser():
# 静默执行
option = webdriver.ChromeOptions()
option.add_argument('headless')
global _driver
_driver = None
if _driver is None:
_driver = webdriver.Chrome(chrome_options=option)
_driver.implicitly_wait(10)
_driver.get('https://mail.qq.com/')
_driver.maximize_window()
yield _driver
_driver.quit()
_driver = None
# 钩子函数 添加工作环境 environment.properities
def pytest_sessionfinish():
r = configPath.ROOT_DIR
with open(r + "/report/allure-raw/environment.properties", "w") as f:
f.write("browser=chrome\nautor=wanfeng\ndomain=https://mail.qq.com/")
# allure 失败用例自动截图
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
'''
获取每个用例状态的钩子函数
:param item:
:param call:
:return:
'''
# 获取钩子方法的调用结果
outcome = yield
rep = outcome.get_result()
# 仅仅获取用例call 执行结果是失败的情况, 不包含 setup/teardown
if rep.when == "call" and rep.failed:
mode = "a" if os.path.exists("failures") else "w"
with open("failures", mode) as f:
# let's also access a fixture for the fun of it
if "tmpdir" in item.fixturenames:
extra = " (%s)" % item.funcargs["tmpdir"]
else:
extra = ""
f.write(rep.nodeid + extra + "\n")
# 添加allure报告截图
if hasattr(_driver, "get_screenshot_as_png"):
with allure.step('添加失败截图'):
allure.attach(_driver.get_screenshot_as_png(), "失败截图", allure.attachment_type.PNG)
2.test_login.py - 调用封装方法
import time
from tools.setLog import Logger
from common.operateExcel import OperateExcel
import pytest
import allure
from selenium.webdriver.common.by import By
from page.loginPage import *
# 初始化日志
logger = Logger().getlog()
@allure.feature('登录功能')
@allure.testcase('https://mail.qq.com/', 'qq邮箱')
class Test_login():
if isCase1Execute:
@allure.severity(severity_level='normal')
@allure.story('用例1:{}'.format(case1))
@allure.title('#{}'.format(case1))
def test_correct_login(self, browser):
'''正确账号、密码'''
browser.switch_to.frame(id)
with allure.step("输入账号"):
ac = browser.find_element(account[0], account[1])
ac.clear()
ac.send_keys(case1Account[0])
with allure.step("输入密码"):
pw = browser.find_element(password[0], password[1])
pw.clear()
pw.send_keys(case1Account[1])
with allure.step("点击登录按钮"):
bt = browser.find_element(button[0], button[1])
bt.click()
with allure.step("校验结果"):
try:
time.sleep(1)
t1 = browser.title
assert "QQ邮箱" == t1, '没有登录进去'
OperateExcel().write_result(sheet_name='登录模块用例', id='DL-DLYM-001', value='pass')
logger.info('登录成功')
except Exception as e:
logger.info(e)
OperateExcel().write_result(sheet_name='登录模块用例', id='DL-DLYM-001', value='fail')
else:
logger.info('此用例IsExecute:{},不执行!'.format(isCase1Execute))
if isCase1Execute:
@allure.story('用例2:{}'.format(case2))
@allure.title('#{}'.format(case2))
# @pytest.mark.skip
def test_error_account(self, browser):
'''错误的账号'''
browser.switch_to.frame(id)
ac = browser.find_element(account[0], account[1])
ac.clear()
ac.send_keys(case2Account[0])
pw = browser.find_element(password[0], password[1])
pw.clear()
pw.send_keys(case2Account[1])
bt = browser.find_element(button[0], button[1])
bt.click()
time.sleep(3)
try:
err = browser.find_element(error_msg[0], error_msg[1]).text
logger.info(err)
time.sleep(1)
t1 = browser.title
assert "QQ邮箱" == t1, '没有登录进去'
except Exception as e:
OperateExcel().write_result(sheet_name='登录模块用例', id='DL-DLYM-002', value='fail')
logger.info(e)
else:
3.loginPage.py - 存放页面元素,存放excel提取login数据
from selenium.webdriver.common.by import By
from common.operateExcel import OperateExcel
# 账号元素
account = (By.XPATH, '//*[@id="u"]')
# 密码元素
password = (By.XPATH, '//*[@id="p"]')
# 登录按钮
button = (By.XPATH, '//*[@id="login_button"]')
# 错误信息提示
error_msg = (By.XPATH, '//*[@id="err_m"]')
# iframe
id = 'login_frame'
# 断言值:名字
name = (By.XPATH, '//*[@id="useralias"]')
# 测试用例名称
case1 = OperateExcel().get_test_case(sheet_name='登录模块用例', id='DL-DLYM-001')
case2 = OperateExcel().get_test_case(sheet_name='登录模块用例', id='DL-DLYM-002')
case3 = OperateExcel().get_test_case(sheet_name='登录模块用例', id='DL-DLYM-003')
case4 = OperateExcel().get_test_case(sheet_name='登录模块用例', id='DL-DLYM-004')
case5 = OperateExcel().get_test_case(sheet_name='登录模块用例', id='DL-DLYM-005')
# 账号密码
case1Account = OperateExcel().get_account_data(sheet_name='登录模块用例', id='DL-DLYM-001')
case2Account = OperateExcel().get_account_data(sheet_name='登录模块用例', id='DL-DLYM-002')
case3Account = OperateExcel().get_account_data(sheet_name='登录模块用例', id='DL-DLYM-003')
case4Account = OperateExcel().get_account_data(sheet_name='登录模块用例', id='DL-DLYM-004')
case5Account = OperateExcel().get_account_data(sheet_name='登录模块用例', id='DL-DLYM-005')
# 是否执行
isCase1Execute = OperateExcel().get_is_execute(sheet_name='登录模块用例', id='DL-DLYM-001')
isCase2Execute = OperateExcel().get_is_execute(sheet_name='登录模块用例', id='DL-DLYM-002')
isCase3Execute = OperateExcel().get_is_execute(sheet_name='登录模块用例', id='DL-DLYM-003')
isCase4Execute = OperateExcel().get_is_execute(sheet_name='登录模块用例', id='DL-DLYM-004')
isCase5Execute = OperateExcel().get_is_execute(sheet_name='登录模块用例', id='DL-DLYM-005')
4.Excel数据存放 - 密码打码了,嘿嘿
5.operateExcel.py - 对excel进行读写操作
import datetime
import os
import time
from datetime import date
import pytest
from openpyxl import load_workbook
from openpyxl.styles import Font, colors
from common import configPath
class Variable():
# excel中每列数据对应的索引
id = 1
testCase = 3
priority = 4
Account = 5
Password = 6
Expect = 7
isExecute = 8
TestResult = 9
# test_result = 2
#操作Excel数据
class OperateExcel:
def __init__(self):
self.file_path = configPath.excel_path
self.wb = load_workbook(self.file_path)
# 获取一列数据
def get_column_value(self, sheet_name, col_num):
sh = self.wb[sheet_name]
case = []
for i in range(1, sh.max_row + 1):
value = sh.cell(i, col_num).value
case.append(value)
return case
# 获取id的序列(从而确定这一行数据)
def get_rowId_index(self, sheet_name, id):
idx = Variable.id
allIdList = self.get_column_value(sheet_name, col_num=idx)
if id not in allIdList:
raise TypeError('编号:{},不存在!'.format(id))
else:
idIndex = allIdList.index(id) + 1
return idIndex
# 获取一行数据
def get_row_value(self, sheet_name, row_num):
sh = self.wb[sheet_name]
case = []
for i in range(1, sh.max_column + 1):
value = sh.cell(row_num, i).value
case.append(value)
return case
# 获取单元格数据
def get_cell_value(self, sheet_name, col_num, row_num):
sh = self.wb[sheet_name]
value = sh.cell(row_num, col_num).value
return value
# 获取是否执行用例字段
def get_is_execute(self,sheet_name,id):
sh = self.wb[sheet_name]
isExecute = sh.cell(self.get_rowId_index(sheet_name,id) + 1,Variable.isExecute).value
if isExecute.lower() == "no":
flag = False
elif isExecute.lower() == "yes":
flag = True
else:
raise TypeError("用户编号为:{} 的 ‘ IsExecute ’ 字段有误!允许类型:yes、no ".format(id))
return flag
# 获取测试用例字段
def get_test_case(self,sheet_name,id):
sh = self.wb[sheet_name]
testCase = sh.cell(self.get_rowId_index(sheet_name,id) + 1,Variable.testCase).value
return testCase
# 获取账号密码字段
def get_account_data(self,sheet_name,id):
sh = self.wb[sheet_name]
data = []
account = sh.cell(self.get_rowId_index(sheet_name,id) + 1,Variable.Account).value
data.append(account)
password = sh.cell(self.get_rowId_index(sheet_name,id) + 1,Variable.Password).value
data.append(password)
for i in range(len(data)):
if data[i] is None:
data[i] = ''
return data
# 写入单元格数据
def write_result(self, sheet_name, id, value):
"""
@param sheet_name: Sheet表名称
@param id:用例编号
@param value: fail or pass
"""
sh = self.wb[sheet_name]
# 设置时间格式
curTime = datetime.datetime.now().strftime('%Y%m%d %H:%M:%S')
# 横,纵坐标
y = self.get_rowId_index(sheet_name, id) + 1
x = Variable.TestResult
# 写入
sh.cell(y, x).value = curTime + "->" + value
# 设置字体样式
if value.lower() == 'fail':
v = sh.cell(y, x)
v.font = Font(name='Arial', color=colors.RED, size=10)
elif value.lower() == 'pass':
v = sh.cell(y, x)
v.font = Font(name='Arial', color="00B050",size=10)
else:
raise TypeError('请传入fail,pass,不区分大小写')
# 保存
print('保存数据,执行成功')
self.wb.save(self.file_path)
总结:下载pytest-html插件也是可以生成美丽的报告,这里我使用的是allure好看一点点嘿嘿,后期也能在jenkins上集成,然后验证码这一块暂时没深入研究,测试的时候让开发先注释掉就可以了,这里只是模拟一个项目的登录部分。
顺便展示一波Allure好看的报告