pythonUi自动化框架 po-unittest+yaml+HTMLTestRunner
po自动化框架简介
page object层
1.对webDriver对象进行二次封装,简化操作
2.针对不同页面 封装对于的元素(包含断言要用的元素) 和 行为
WebDriver封装-base基础
"""
bese页面,用于driver的方法封装
操作方法封装:
打开网页
关闭驱动
获得driver对象
find_element
find_elements
send_keys
click
选择菜单
"""
import time
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from setting import driver_path, imp_wait
from selenium.webdriver.chrome.service import Service
class Base:
def __init__(self, path=driver_path, wait=imp_wait, driver=None):
# 初始化时判断是否传入driver对象,不传默认创建一个
if driver is None:
self.driver = webdriver.Chrome(service=Service(path))
self.driver.maximize_window()
else:
self.driver = driver
self.driver.implicitly_wait(wait)
def get_driver(self):
return self.driver
def open(self, url):
self.driver.get(url)
def close(self):
self.driver.close()
@classmethod
def speed(cls, wait_name):
time.sleep(wait_name)
def find_ele(self, locator: tuple):
return self.driver.find_element(*locator)
def find_eles(self, locator):
return self.driver.find_elements(*locator)
def send(self, locator, value):
self.find_ele(locator).send_keys(value)
def click(self, locator):
self.find_ele(locator).click()
# 显示等待
def find_ele_display(self, locator, wait=5):
ele = WebDriverWait(self.driver, wait).until(EC.presence_of_element_located(locator))
return ele
# 根据文本选择菜单
def menu(self, parent_loc, locator, text):
self.click(parent_loc)
for ele in self.find_eles(locator):
if text == ele.text:
ele.click()
if __name__ == '__main__':
pass
登录页面封装
"""
登录页面 http://127.0.0.1:8000/login/
属性:
用户名
密码
验证码
登录按钮
行为:
登录操作
断言元素:
登出按钮
登录错误提示
"""
from po.base import Base
class Login(Base):
# 用户名-密码-验证码-登录按钮
ele_name = ('id', 'LAY-user-login-username')
ele_pwd = ('id', 'LAY-user-login-password')
ele_verif = ('id', 'LAY-user-login-vercode')
ele_button = ('id', 'loginButton')
# 登出按钮-错误信息(登录失败时)
ele_logout = ('css selector', 'a[href="/logout/"]')
ele_error = ('css selector', 'div[class = "layui-layer-content layui-layer-padding"]')
def do_login(self, url='http://127.0.0.1:8000/login/',
name='admin', pwd='123456', verif='0'):
self.open(url)
if name:
self.send(self.ele_name, name)
if pwd:
self.send(self.ele_pwd, pwd)
if verif:
self.send(self.ele_verif, verif)
self.click(self.ele_button)
self.speed(0.5)
def assert_success(self):
try:
info = self.find_ele(self.ele_logout).text
self.close()
return True
except:
self.close()
print('登录成功断言--失败')
def assert_fails(self, expect):
try:
info = self.find_ele(self.ele_error).text
if expect in info:
print('登录失败测试--成功')
self.close()
return True
else:
print(f'期望:{expect} 实际:{info}')
print('登录失败测试--失败')
self.close()
return False
except:
print('登录失败测试获取异常信息--失败')
self.close()
return False
if __name__ == '__main__':
url = 'http://127.0.0.1:8000/login/'
login1 = Login()
login1.do_login(url, "qqq", "1", "1")
login1.assert_fails('用户名或密码错误')
# login2 = Login()
# login2.do_login(url, "qqq", "1", "")
# login2.assert_success()
# # login2.assert_fails('请输入验证码')
需求申请页面封装
"""page object
需求申请页面:http://127.0.0.1:8000/mainpage/
属性:
主菜单
子菜单
部门
日期
名称
管理系统
需求类型
需求描述
方法:
提交需求描述
"""
from po.base import Base
from po.login import Login
class Application(Base):
# 菜单栏选择-需求管理-需求申请
ele_menu_parent = ('css selector', 'li.layui-nav-item cite')
ele_menus = ('css selector', 'a[action$="_order/"]')
# 第一个输入框文字(用于选时间后点击)
ele_titles = ('css selector', 'label.layui-form-label')
# 所有 输入框的元素列表
ele_inputs = ('css selector', 'input.layui-input')
# 部门下拉框下的选项-单选框-描述-提交/重置
ele_dd = ('css selector', 'dd[lay-value^="00"]')
ele_radios = ('css selector', 'div[class^="layui-unselect layui-form-radio"]')
ele_descript = ('css selector', 'textarea.layui-textarea')
ele_buttons = ('css selector', 'button[class^="layui-btn"]')
# 提交信息提示
# ele_erro = ('css selector', 'div[class="layui-layer-content layui-layer-padding"]')
ele_info = ('css selector', 'div[class="layui-layer-content layui-layer-padding"]')
# 提示信息-确然按钮
button = ('css selector', 'a.layui-layer-btn0')
def select_menu(self):
# 选择菜单
self.menu(self.ele_menu_parent, self.ele_menus, '需求申请')
# 切换frame
self.driver.switch_to.frame('mainframe')
def __click_button(self, button):
for element in self.find_eles(self.ele_buttons):
if element.text in button:
element.click()
def application(self, department=None, date=None, title=None, server=None, radio=None, descript=None):
# 需求部门
elements = self.find_eles(self.ele_inputs)
if department:
elements[0].click()
self.speed(0.5)
dep_li = self.find_eles(self.ele_dd)
# 部门下的下拉框,按文字选择
for ele in dep_li:
# print('下拉框:', ele.text)
if department in ele.text:
ele.click()
break
# 申请时间
if date:
elements[1].send_keys(date)
self.find_eles(self.ele_titles)[0].click()
# 需求名字
if title:
elements[2].send_keys(title)
# 关联系统
if server:
elements[3].send_keys(server)
# 单选框
if radio:
for ele in self.find_eles(self.ele_radios):
if ele.text == radio:
ele.click()
break
# 描述
if descript:
self.send(self.ele_descript, descript)
# 点击按钮
self.__click_button('提交')
def assert_success(self, msg='需求登记成功'):
self.speed(0.5)
info = self.find_ele_display(self.ele_info).text
print(info)
self.speed(0.5)
self.__click_button('重置')
if msg in info:
return True
return False
def assert_fails(self, msg='日期不在允许范围内'):
self.speed(0.5)
# 填错 报提示信息
info = self.find_ele_display(self.ele_info).text
print('错误提示:', info, ' 实际:', msg)
try:
self.driver.implicitly_wait(0.2)
self.find_ele_display(self.button, 0.2).click()
except:
# print('错误提示无确认按钮')
pass
self.speed(0.5)
# 防止日期弹框
self.find_eles(self.ele_titles)[0].click()
self.__click_button('重置')
if msg in info:
return True
return False
if __name__ == '__main__':
url = 'http://127.0.0.1:8000/login/'
page = Login()
page.do_login(url, 'admin', '123456', '1')
dr = page.get_driver()
app=Application(driver=dr)
app.select_menu()
app.application()
print(app.assert_fails(msg="选择部门"))
app.close()
test层
登录测试用例
import unittest
import ddt
import yaml
from po.login import Login
from setting import login_success_file, login_url, login_fails_file
import warnings
"""
测试用例
登录页面 http://127.0.0.1:8000/login/
"""
@ddt.ddt
class TestLogin(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
warnings.simplefilter("ignore", ResourceWarning)
cls.url = login_url
def setUp(self) -> None:
self.login = Login()
@ddt.file_data(login_success_file)
def test_login_success(self, name, pwd, verif):
self.login.do_login(self.url, name, pwd, verif)
flag = self.login.assert_success()
self.assertTrue(flag)
@ddt.file_data(login_fails_file)
def test_login_fails(self, name, pwd, verif, error):
self.login.do_login(self.url, name, pwd, verif)
flag = self.login.assert_fails(error)
self.assertTrue(flag)
if __name__ == '__main__':
unittest.main()
需申请测试用例
import time
import unittest
import ddt
from common.util import exec_code
from po.application import Application
from po.login import Login
from setting import application_fails_file as file_fail, application_success_file as file_suc
"""
测试用例
需求申请页面:http://127.0.0.1:8000/mainpage/
"""
@ddt.ddt
class TestApplication(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
login = Login()
login.do_login()
dr = login.driver
cls.app = Application(driver=dr)
cls.app.select_menu()
@classmethod
def tearDownClass(cls) -> None:
cls.app.close()
@ddt.file_data(file_suc)
def test_require_success(self, **kwargs):
time.sleep(0.5)
# 执行yaml中的 时间代码
kwargs['date'] = exec_code(kwargs['date'])
print('入参',kwargs)
self.app.application(kwargs['department'],
kwargs['date'],
kwargs['title'],
kwargs['server'],
kwargs['radis'],
kwargs['descript'])
flag = self.app.assert_success()
self.assertTrue(flag)
@ddt.file_data(file_fail)
def test_require_fails(self, **kwargs):
time.sleep(0.5)
# 执行yaml中的 时间代码
kwargs['date'] = exec_code(kwargs['date'])
print('入参', kwargs)
self.app.application(kwargs['department'],
kwargs['date'],
kwargs['title'],
kwargs['server'],
kwargs['radis'],
kwargs['descript'])
flag = self.app.assert_fails(kwargs['msg'])
self.assertTrue(flag)
if __name__ == '__main__':
unittest.main()
common公共层
公共方法
import datetime
import os
from setting import sql_file
def exec_code(info: str):
"""
用于执行yaml文件中的代码---比如下方时间
<datetime.date.today().strftime('%Y-%m-%d')>
"""
if info:
if info.startswith('<') and info.endswith('>'):
print(info[1:-1])
exec_info = eval(info[1:-1])
return exec_info
return info
def init_mysql(path, host='localhost'):
os.system(f'mysql -h{host} -P3306 -uroot -p123456 -Dtestproject<{path}')
print('--mysql初始化成功--')
if __name__ == '__main__':
# info = "<datetime.date.today().strftime('%Y-%m-%d')>"
# new_inf = exec_code(info)
# print(new_inf)
# init_mysql(sql_file)
主执行方法main.py
"""
启动入口--测试套件suite启动
"""
import unittest
from common.util import init_mysql
from setting import sql_file
from common.HTMLTestRunner import HTMLTestRunner
if __name__ == '__main__':
# 创建套件
suite = unittest.TestSuite()
# 加入目录下测试单元
discover = unittest.defaultTestLoader.discover(start_dir='tests', pattern='test*.py')
suite.addTests(discover)
# 执行并生成报告
with open('./report.html', 'wb') as f:
runner = HTMLTestRunner(f, verbosity=2)
runner.run(suite)
# 初始化mysql数据
init_mysql(sql_file)
数据层
每个po页对于的成功和失败用例数据,分别放置
--其他页面也是同样--
需求申请页,成功数据
-
department: 人力部门
date: <datetime.date.today().strftime('%Y-%m-%d')>
title: 一号需求测试
server: 小程序
radis: 新增需求
descript: 人力资源部人手不够需要开发一个自动筛选简历的web网页
-
department: 保卫部
date: <datetime.date.today().strftime('%Y-%m-%d')>
title: 二号需求测试
server: 小程序
radis: 新增需求
descript: 人保资源部人手不够需要开发一个自动筛选地图的功能
需求申请页,失败数据
-
department:
date:
title:
server:
radis:
descript:
msg: 选择部门
-
department: 人力部门
date: "2022-04-01"
title: 一号需求测试
server: 小程序
radis: 新增需求
descript: 人力资源部人手不够需要开发一个自动筛选简历的web网页
msg: 日期不在允许范围内
公共变量Setting
import os
# 登录url
login_url = 'http://127.0.0.1:8000/login/'
PATH = os.path.dirname(__file__)
# ----------浏览器驱动----------
driver_path = os.path.join(PATH, 'datas', 'chromedriver.exe')
imp_wait = 5
# ---------数据库初始化文件----------
sql_file = os.path.join(PATH, 'datas', 'init_testproject.sql')
# ---------测试数据文件-------------
login_success_file = os.path.join(PATH, 'datas', 'loginSuccess.yaml')
login_fails_file = os.path.join(PATH, 'datas', 'loginFails.yaml')
application_success_file = os.path.join(PATH, 'datas', 'applicationSuccess.yaml')
application_fails_file = os.path.join(PATH, 'datas', 'applicationFails.yaml')
management_success_file = os.path.join(PATH, 'datas', 'managementSuccess.yaml')