本次介绍的UI Test Framework 分为以下几层,UI自动化测试框架主要思想Page Object 的思想,即:将一个页面的元素封装成一个类,本文以禅道项目为例:详情如下:
分层介绍如下:
actions:动作层,封装每个页面的业务。
common:底层,封装一些工具包,以及对Selenium 3 里面的元素定位,鼠标,键盘等动作进行二次封装。
config:配置文件层,存放配置文件,一些主机地址信息,邮件地址,日志地址,驱动地址,日志级别设置,截图地址,一些账号信息等。
element_info:元素信息层,将每个页面的元素封装成类,类似的属性是元素,方法是元素的动作。
element_info_datas:元素信息表层,每个页面的元素信息都单独存放在对应的excel表格中
logs :日志层
reports:报告层
runner:运行层
sample:测试层,用于代码测试
screen_shot:存放截图图片层
test_data:测试数据层
testcases:测试用例集层
webdriver:存放浏览器驱动层
详细说明如下:
common层:
base_page.py对selenium 3框架基本引用进行二次放在都放在这个文件里面
# desc:页面基础类
import os, time
from common.log_utils import logs_obj
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from common.config_utils import config_obj
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.select import Select
from common import HTMLTestReportCN
class BasePage(object):
def __init__(self, driver):
# self.driver = webdriver.Chrome()
self.driver = driver
def open_url(self, url):
self.driver.get(url)
logs_obj.info('打开url地址:{}'.format(url))
def set_browser_max(self):
self.driver.maximize_window()
logs_obj.info('窗口最大化')
def set_browser_min(self):
self.driver.minimize_window()
logs_obj.info('窗口最小化')
def refresh(self):
self.driver.refresh()
logs_obj.info('刷新')
def close_tab(self):
self.wait(2)
self.driver.close()
logs_obj.info('------- 关闭当前tab页面 --------')
def quit_driver(self):
self.wait(1)
self.driver.quit()
logs_obj.info('------- 退出浏览器 --------')
def get_url(self):
value = self.driver.current_url
logs_obj.info('------- 获取网页url:{} --------'.format(value))
return value
def get_title(self):
value = self.driver.title
logs_obj.info('获取网页title:{}'.format(value))
return value
# 清空文本框的内容
def clear(self, element_info):
self.find_element(element_info).clear()
# self.username_inputbox = {'element_name': '用户名输入框',
# 'locator_type': 'ID',
# 'locator_value': 'account',
# 'timeout': '5'}
def find_element(self, element_info):
'''
通过 element_info (元素识别的数据,返回一个元素)
:param element_info:元素识别信息字典
:return: element
id,name,class,tag,linktext,plinktext,xpath,css
'''
try:
locator_type_name = element_info['locator_type']
locator_value_info = element_info['locator_value']
locator_timeout = element_info['timeout']
if locator_type_name == 'id':
locator_type = By.ID
elif locator_type_name == 'xpath':
locator_type = By.XPATH
elif locator_type_name == 'name':
locator_type = By.NAME
elif locator_type_name == 'class':
locator_type = By.CLASS_NAME
elif locator_type_name == 'css':
locator_type = By.CSS_SELECTOR
elif locator_type_name == 'tag':
locator_type = By.TAG_NAME
elif locator_type_name == 'linktext':
locator_type = By.LINK_TEXT
elif locator_type_name == 'plinktext':
locator_type = By.PARTIAL_LINK_TEXT
# self.driver.find_element(By.XPATH,'//li[@data-id="product"]')
# 显示等待识别元素
element = WebDriverWait(self.driver, locator_timeout).until(
lambda x: x.find_element(locator_type, locator_value_info)) # 最核心的代码
logs_obj.info('[{}] 识别成功'.format(element_info['element_name']))
except Exception as e:
logs_obj.info('[{}] 识别不成功,原因是:{}'.format(element_info['element_name'], e.__str__()))
self.screenshot_as_file()
return element
# 封装元素操作方法
def click(self, element_info):
element = self.find_element(element_info)
element.click()
logs_obj.info('点击:{}'.format(element_info['element_name']))
# 元素输入操作
def send_keys(self, element_info, content):
element = self.find_element(element_info)
element.send_keys(content)
logs_obj.info('[{}]中输入{}'.format(element_info['element_name'], content))
# 获取元素的某个属性值
def get_attribute(self, element_info):
title = self.find_element(element_info).get_attribute('title')
logs_obj.info('title是:{}'.format(title))
return title
# 获取元素的某个属性值
def get_text_value(self, element_info):
text = self.find_element(element_info).text
logs_obj.info('text是:{}'.format(text))
return text
# 切框架:思路1 通过元素是被数据字典,获取元素再切
def switch_to_frame_by_element(self, element_info):
element = self.driver.find_element(element_info)
self.driver.switch_to.frame(element)
logs_obj.info('通过元素切换框架,该元素为:{}'.format(element_info['locator_value']))
# 切框架:思路2 使用id或name切
def switch_to_frame_id_or_name(self, id_or_name):
self.driver.switch_to.frame(id_or_name)
logs_obj.info('通过id或name切换框架,id或name为:{}'.format(id_or_name))
# 切框架:思路3 把前面两种思路整合,封装成一个统一的方法
def switch_to_frame(self, **element_dict):
if 'id' in element_dict.keys():
self.driver.switch_to.frame(element_dict['id'])
logs_obj.info('通过id切换框架,id为:{}'.format(element_dict['id']))
elif 'name' in element_dict.keys():
self.driver.switch_to.frame(element_dict['name'])
logs_obj.info('通过name切换框架,name为:{}'.format(element_dict['name']))
elif 'element_info' in element_dict.keys():
element = self.find_element(element_dict['element_info'])
logs_obj.info('通过element_info切换框架,element_info为:{}'.format(element_dict['element_info']))
self.driver.switch_to.frame(element)
return element_dict
def switch_to_default_content(self):
self.driver.switch_to.default_content()
# 弹出框封装
# def switch_to_alert(self,action = 'accept',time_out = config_obj.time_out):
# self.wait(time_out)
# alert = self.driver.switch_to.alert
# alert_text = alert.text
# if action == 'accept':
# alert.accept() #确认
# else:
# alert.dismiss
# return alert_text
def switch_to_alert_2(self, action='accept', time_out=config_obj.time_out):
WebDriverWait(self.driver, time_out).until(EC.alert_is_present())
alert = self.driver.switch_to.alert
logs_obj.info('----------- 切换到弹框 -----------')
alert_text = alert.text
logs_obj.info('-------- 弹框的文本内容为:{} -------'.format(alert_text))
self.wait(3)
if action == 'accept':
alert.accept()
logs_obj.info('-------- 点击弹框的确定按钮! ---------')
else:
alert.dismiss()
logs_obj.info('---------- 点击弹框的取消按钮 -----------')
return alert_text
# 切句柄
# 获取当前页面的句柄
def get_window_handle(self):
logs_obj.info('---- 获取窗口的句柄:{} ---------'.format(self.driver.current_window_handle))
return self.driver.current_window_handle
# 切句柄
def switch_to_window_by_handle(self, window_handle):
self.driver.switch_to.window(window_handle)
logs_obj.info('-------- 进行切换句柄,句柄为:{} ----------'.format(window_handle))
# 通过title切
# def switch_to_window_by_title(self,title):
# window_handles = self.driver.window_handles
# for window_handle in window_handles:
# self.driver.switch_to.window(window_handle)
# if self.get_title() == title:
# break;
# 通过url切
# def switch_to_window_by_url(self,url):
# window_handles = self.driver.window_handles
# for window_handle in window_handles:
# self.driver.switch_to.window(window_handle)
# if self.get_url() == url:
# break;
# 切句柄继续封装 加等待时间,只检查标题标题,url的部分内容
def switch_to_window_by_title(self, title):
window_handles = self.driver.window_handles
for window_handle in window_handles:
self.driver.switch_to.window(window_handle)
if WebDriverWait(self.driver, config_obj.time_out).until(EC.title_contains(title)):
logs_obj.info('--------- 通过title({})切换窗口:-----------'.format(title))
break;
def switch_to_window_by_url(self, url):
window_handles = self.driver.window_handles
for window_handle in window_handles:
self.driver.switch_to.window(window_handle)
if WebDriverWait(self.driver, config_obj.time_out).until(EC.title_contains(url)):
logs_obj.info('--------- 通过url({})切换窗口:-----------'.format(url))
break;
# 修改某个元素的属性
def set_element_attribute(self, element_info, attribute_name, attribute_value):
js = 'arguments[0].setAttribute("%s","%s");' % (attribute_name, attribute_value)
el = self.find_element(element_info)
self.__execute_script(js, el)
logs_obj.info('[{}],正在执行修改[{}]属性操作,修改成:{}'.format(element_info['element_name'], attribute_value))
# 移除某个属性
def remove_element_attribute(self, element_info, attribute_name):
js = 'arguments[0].removeAttribute("%s");' % attribute_name
el = self.find_element(element_info)
self.__execute_script(js, el)
logs_obj.info('[{}],正在执行移除[{}]属性操作'.format(element_info['element_name'], attribute_name))
# 滚动条
def scroll(self, height):
self.wait(2)
js = 'window.scrollBy(0,{});'.format(height) # height:正数向下滚,负数向上滚
self.__execute_script(js)
logs_obj.info('正在执行页面滚动操作,滚动的高度为:{}'.format(height))
# 继续封装 selenium 执行 js 脚本 深入封装
def __execute_script(self, js, element=None):
if element:
self.driver.execute_script(js, element)
logs_obj.info('[{}]:正在进行js操作,js代码为'.format(element['element_name'], js))
else:
self.driver.execute_script(js)
logs_obj.info('正在执行js,js是{}'.format(js))
# 固定等待
def wait(self, s=config_obj.time_out):
time.sleep(s)
logs_obj.info('固定等待:%s' % s)
# 隐式等待
def implicitly_wait(self, seconds=config_obj.time_out):
self.driver.implicitly_wait(seconds)
logs_obj.info('------- 浏览器设置隐式等待:{} --------'.format(seconds))
# 显示等待
# 鼠标悬停
def move_to_element_by_mouse(self, element_info):
element = self.find_element(element_info)
ActionChains(self.driver).move_to_element(element)
logs_obj.info('[{}]:元素进行悬停'.format(element_info['element_name']))
# 长按不停
def long_press_element(self, element_info):
element = self.find_element(element_info)
ActionChains(self.driver).click_and_hold(element).perform()
logs_obj.info('[{}]:元素进行长按'.format(element_info['element_name']))
# 鼠标右击
def right_click_element(self, element_info):
element = self.find_element(element_info)
ActionChains(self.driver).context_click(element).perform()
logs_obj.info('[{}]:元素进行右击'.format(element_info['element_name']))
# 截图
# def screenshot_as_file(self, *screenshot_path):
# # 如果没有喘截图路径,则将截图放入默认路径,
# if len(screenshot_path) == 0:
# screenshot_filepath = config_obj.screen_shot_path
# else:
# screenshot_filepath = screenshot_path[0]
# now = time.strftime('%Y_%m_%d_%H_%M_%S')
# current_dir = os.path.dirname(__file__)
# screenshot_filepath = os.path.join(current_dir, '..', screenshot_filepath,
# 'UTest_%s.png' % now)
# self.driver.save_screenshot(screenshot_filepath)
# logs_obj.info(' 截图保存成功,图片位置:{}'.format(screenshot_filepath))
# 第二次讲截图
def screenshot_as_file(self):
'''
把错误截图放到HTML中
:return:
'''
report_path = os.path.join(os.path.abspath(__file__),'..',config_obj.report_path)
report_dir = HTMLTestReportCN.ReportDirectory('report_path')
report_dir.get_screenshot(self.driver)
# 下拉定位,一下分别通过Select类的索引
def select_by_element_info(self, element_info):
element = self.find_element(element_info)
self.click(element)
def select_by(self, element_info, **by_index_or_value_or_visible_text):
element = self.find_element(element_info)
select = Select(element)
if 'index' in by_index_or_value_or_visible_text.keys():
select.select_by_index(by_index_or_value_or_visible_text['index'])
logs_obj.info('通过select的index定位到该元素,index值为:{}'.format(by_index_or_value_or_visible_text['text']))
elif 'value' in by_index_or_value_or_visible_text.keys():
select.select_by_value(by_index_or_value_or_visible_text['value'])
logs_obj.info('通过select的value定位到该元素,value值为:{}'.format(by_index_or_value_or_visible_text['value']))
elif 'text' in by_index_or_value_or_visible_text.keys():
select.select_by_visible_text(by_index_or_value_or_visible_text['text'])
logs_obj.info('通过select的text定位到该元素,text值为:{}'.format(by_index_or_value_or_visible_text['text']))
if __name__ == '__main__':
from common.browser import Browser
driver = Browser().get_driver()
base_page = BasePage(driver)
base_page.open_url('https://www.baidu.com')
base_page.scroll(1000)
browser.py主要对Google、Firefox、msedge三大浏览器驱动进行封装:
浏览器驱动需要下载本地计算机浏览器对应的版本:
# @desc:浏览器封装
import os
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from common.config_utils import config_obj
from selenium.webdriver.chrome.options import Options
from common.log_utils import logs_obj
dri_path = os.path.join(os.path.dirname(__file__), '..', config_obj.get_driver_path)
class Browser():
def __init__(self, driver_path=dri_path):
self.__driver_path = driver_path
def __get_chrome_driver(self):
chrome_options = Options()
chrome_options.add_argument('--disable-gpu') # 谷歌文档提到需要加上这个属性来规避bug
chrome_options.add_argument('lang=zh_CN.UTF-8') # 设置默认编码为utf-8
chrome_options.add_experimental_option('useAutomationExtension', False) # 取消chrome受自动控制提示
chrome_options.add_experimental_option("excludeSwitches", ['enable-automation']) # 取消chrome受自动控制提示
driver_path = os.path.join(self.__driver_path, 'chromedriver.exe')
driver_server = Service(driver_path)
chrome_driver = webdriver.Chrome(service=driver_server, options=chrome_options)
logs_obj.info('----- 初始化google浏览器,并启动 -----')
return chrome_driver
def __get_firefox_driver(self):
firefox_driver_path = os.path.join(self.__driver_path, 'geckodriver.exe')
driver_server = Service(firefox_driver_path)
firefox_driver = webdriver.Firefox(service=driver_server)
logs_obj.info('----- 初始化firefox浏览器,并启动 -----')
return firefox_driver
def __get_edge_driver(self):
edge_driver_path = os.path.join(self.__driver_path, 'msedgedriver.exe')
driver_server = Service(edge_driver_path)
edge_driver = webdriver.Edge(service=driver_server)
logs_obj.info('----- 初始化edge浏览器,并启动 -----')
return edge_driver
def get_driver(self):
##设置默认驱动 chrome,firefox,msedge
if config_obj.get_driver_name == 'chrome':
driver = self.__get_chrome_driver()
logs_obj.info('------- 配置文件配置的浏览器驱动是:{} --------'.format(config_obj.get_driver_name))
elif config_obj.get_driver_name == 'firefox':
driver = self.__get_firefox_driver()
logs_obj.info('------- 配置文件配置的浏览器驱动是:{} --------'.format(config_obj.get_driver_name))
elif config_obj.get_driver_name == 'msedge':
driver = self.__get_edge_driver()
logs_obj.info('------- 配置文件配置的浏览器驱动是:{} --------'.format(config_obj.get_driver_name))
return driver
config_utils.py读取配置文件类:
config.ini文件内容为:
[name]
name1 = test
name2 = dev01
name3 = dev02
name4 = test01
name5 = test02
[password]
password1 = xxxx
password2 = xxxx
password3 = xxxx
password4 = xxxx
password5 = xxxx
[ZenTao_url]
url = http://xx.xxx.xxxx.xx/zentao/www/index.php?m=user&f=login
[default]
driver_path = webdriver
#日志路径
log_path = logs
#日志级别 0 NOTSET 10 DEBUG 20 INFO 30 WARNING 40 ERROR 50 CRITICAL
log_level = 20
#设置默认驱动 chrome,firefox,msedge
driver_name = chrome
#元素识别信息路径
element_info_path = element_info_datas
#默认等待时间
time_out = 30
#默认存放截图目录
screen_shot_path = screen_shot
#默认登录的账户名和密码
username = test01
password = xxxxxxx
#测试数据路径
test_data_path = test_data
#测试用例路径
case_path = testcases
#测试报告路径
report_path = reports/
[email]
#发送服务器
smtp_server = smtp.qq.com
#发送账户
smtp_sender = xxxxx@qq.com
#QQ第三方登录密码
smtp_password = xxxxx
#测接收人
smtp_receiver = xxxxx@qq.com
#抄送人
smtp_cc = 2656343994@qq.com
#邮件标题
smtp_subject = 禅道UI自动化测试报告
config_utils.py类:
# 读取配置文件
import configparser, os
config_path = os.path.join(os.path.dirname(__file__), '../config/config.ini')
class ConfigUtils:
def __init__(self, cof_path):
self.config_path = cof_path
self.conf = configparser.ConfigParser()
self.conf.read(self.config_path, encoding='utf-8')
@property
def get_zentao_url(self):
return self.conf.get('ZenTao_url', 'url')
@property
def get_name_01(self):
return self.conf.get('name', 'name1')
@property
def get_name_02(self):
return self.conf.get('name', 'name2')
@property
def get_password_01(self):
return self.conf.get('password', 'password1')
@property
def get_password_02(self):
return self.conf.get('password', 'password2')
@property
def get_driver_path(self):
return self.conf.get('default', 'driver_path')
@property
def get_log_path(self):
return self.conf.get('default', 'log_path')
@property
def get_log_level(self):
return int(self.conf.get('default', 'log_level'))
# 获取默认驱动名称
@property
def get_driver_name(self):
return self.conf.get('default', 'driver_name')
# 获取默认超时时间
@property
def time_out(self):
return float(self.conf.get('default', 'time_out'))
# 获取截图默认路径
@property
def screen_shot_path(self):
return self.conf.get('default', 'screen_shot_path')
@property
def user_name(self):
return self.conf.get('default', 'username')
@property
def pass_word(self):
return self.conf.get('default', 'password')
@property
def test_data_path(self):
return self.conf.get('default', 'test_data_path')
# 测试用例路径
@property
def case_path(self):
return self.conf.get('default', 'case_path')
# 测试报告路径
@property
def report_path(self):
return self.conf.get('default', 'report_path')
# 获取email的smtp_server
@property
def smtp_server(self):
return self.conf.get('email', 'smtp_server')
# 获取email的smtp_sender
@property
def smtp_sender(self):
return self.conf.get('email', 'smtp_sender')
# 获取email的smtp_password
@property
def smtp_password(self):
return self.conf.get('email', 'smtp_password')
# 获取email的smtp_receiver
@property
def smtp_receiver(self):
return self.conf.get('email', 'smtp_receiver')
# 获取email的smtp_cc
@property
def smtp_cc(self):
return self.conf.get('email', 'smtp_cc')
# 获取email的smtp_subject
@property
def smtp_subject(self):
return self.conf.get('email', 'smtp_subject')
#element_info_path
@property
def element_info_path(self):
return self.conf.get('default', 'element_info_path')
config_obj = ConfigUtils(config_path)
element_data_utils.py读取excel元素文件类,excel元素文件目录结构如下,文件内容如图:
登录页面元素信息如下图,其它页面元素类似:
element_data_utils.py类
# encoding: utf-8
# @author: newdream_daliu
# @file: element_data_utils.py
# @time: 2022-07-10 17:12
# @desc: 读取页面元素类
import os
import xlrd
from common.config_utils import config_obj
current_path = os.path.dirname(__file__)
excel_path = os.path.join(current_path, '..',config_obj.element_info_path)
#element_info_datas/login/login_page.xlsx
#固定元素的总路径/模块路径/页面名称.xlsx
class ElementDataUtils():
def __init__(self,module_name,page_name, element_path=excel_path): # 将页面名称定义
self.element_path = element_path
self.element_path = os.path.join(self.element_path,module_name,page_name+'.xlsx')
self.workbook = xlrd.open_workbook(self.element_path)
self.sheet = self.workbook.sheet_by_index(0) # 每次取第一个sheet
self.row_count = self.sheet.nrows
def get_element_info(self):
element_infos ={}
for i in range(1, self.row_count):
# if self.sheet.cell_value(i, 2) == page_name:
element_info = {}
element_info['element_name'] = self.sheet.cell_value(i, 1)
element_info['locator_type'] = self.sheet.cell_value(i,2)
element_info['locator_value'] = self.sheet.cell_value(i, 3)
timeout_value = self.sheet.cell_value(i,4)
#方法1:
# if timeout_value == '':
# timeout_value = config_obj.time_out #如果没有设置,就取config.ini设置的默认值
# else:
# timeout_value = float(timeout_value) #如果元素表设置了默认值则就转成浮点型
# element_info['timeout'] = timeout_value
# 方法2:
timeout_value = float(timeout_value) if isinstance(timeout_value,float) else config_obj.time_out
element_info['timeout'] = timeout_value
element_infos[self.sheet.cell_value(i, 0)] = element_info
return element_infos
if __name__ == '__main__':
elements = ElementDataUtils('login','login_page').get_element_info()
print(elements)
# elements = ElementDataUtils('main').get_element_info('main_page')
# print(elements)
# elements = ElementDataUtils('login').get_element_info('login_page')
# print(elements)
email_util.py 发送邮件类
import smtplib, os
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from common.log_utils import logs_obj
from email.mime.base import MIMEBase
from email import encoders
from common.config_utils import config_obj
from common import zip_utils
class EmailUtils:
def __init__(self, smtp_body, smtp_file_path=None):
self.smtp_server = config_obj.smtp_server
self.smtp_sender = config_obj.smtp_sender
self.smtp_password = config_obj.smtp_password
self.smtp_receiver = config_obj.smtp_receiver
self.smtp_cc = config_obj.smtp_cc
self.smtp_subject = config_obj.smtp_subject
self.smtp_body = smtp_body
self.smtp_file = smtp_file_path
def mail_content(self):
if self.smtp_file != None:
if self.smtp_file.split('.')[-1].__eq__('zip'):
return self.__mail_zip_content()
# elif扩展
else:
return self.__mail_text_content()
def mail_content_by_zip(self):
report_zip_path = self.smtp_file + '/../禅道UI自动化测试报告.zip'
zip_utils.zip_dir(self.smtp_file, report_zip_path)
self.smtp_file = report_zip_path
message = self.mail_content()
return message
def __mail_text_content(self):
message = MIMEText(self.smtp_body, 'html', 'utf-8')
message['From'] = self.smtp_sender
message['To'] = self.smtp_receiver
message['Cc'] = self.smtp_cc
message['Subject'] = self.smtp_subject
return message
def __mail_zip_content(self):
message = MIMEMultipart()
with open(self.smtp_file, 'rb') as f:
mime = MIMEBase('zip', 'zip', filename=self.smtp_file.split('/')[-1])
mime.add_header('Content-Disposition', 'attachment',
filename=('gb2312', '', self.smtp_file.split('/')[-1]))
mime.add_header('Content-ID', '<0>')
mime.add_header('X-Attachment-Id', '0')
mime.set_payload(f.read())
encoders.encode_base64(mime)
message.attach(mime)
message.attach(MIMEText(self.smtp_body, 'html', 'utf-8'))
message['From'] = self.smtp_sender
message['To'] = self.smtp_receiver
message['Cc'] = self.smtp_cc
message['Subject'] = self.smtp_subject
return message
def zip_send_mail(self):
try:
smtp = smtplib.SMTP()
smtp.connect(self.smtp_server, 25) # 25 为 SMTP 端口号
smtp.login(self.smtp_sender, self.smtp_password)
except:
smtp = smtplib.SMTP_SSL()
smtp.login(self.smtp_sender, self.smtp_password)
mail_content = self.mail_content_by_zip()
try:
smtp.sendmail(self.smtp_sender, self.smtp_receiver.split(',') + self.smtp_cc.split(','),
mail_content.as_string())
logs_obj.info('邮件发送人是:{},邮件接收人是;{},邮件抄送人是:{}'.format(self.smtp_sender,
self.smtp_receiver.split(',')
,self.smtp_cc.split(',')))
print("邮件发送成功")
except smtplib.SMTPException:
logs_obj.info('邮件发送失败,失败原因:{}'.format(smtplib.SMTPException))
smtp.close()
logs_obj.info('发送邮件结束')
excel_util.py读取excel工具包:
# encoding:utf-8
# @author:yangshhiyu
# @file:excel_utils.py
# @time:2022/7/2415:29
# @desc:底层读取excel底层封装
import xlrd, os
from common.config_utils import config_obj
# current_path = os.path.dirname(__file__)
# el_path = os.path.join(current_path, '../element_info_datas/element_info_datas.xlsx')
# test_data_path = os.path.join(current_path,'..',config_obj.test_data_path)
class ExcelUtils():
def __init__(self, excel_path, sheet_name=None):
self.excel_path = excel_path
self.sheet_name = sheet_name
self.sheet_data = self.__get_sheet_data()
def __get_sheet_data(self):
'''
通过sheet_name 获取一个sheet,如果没有就返回第一个sheet
:return: sheet data
'''
workbook = xlrd.open_workbook(self.excel_path)
if self.sheet_name:
sheet = workbook.sheet_by_name(self.sheet_name)
else:
sheet = workbook.sheet_by_index(0)
return sheet
@property
def __get_row_count(self):
'''获取总的行数'''
row_count = self.__get_sheet_data().nrows
return row_count
@property
def __get_col_count(self):
'''获取总的列数 '''
rol_count = self.__get_sheet_data().ncols
return rol_count
def get_sheet_data_by_list(self):
'''
通过读取excel中数据
:return: [[],[],[]....]
'''
all_excel_data = [] # 总的数据
for rownum in range(self.__get_row_count):
row_excel_data = [] # 一行的数据
for colnum in range(self.__get_col_count):
cell_value = self.__get_sheet_data().cell_value(rownum, colnum)
row_excel_data.append(cell_value)
all_excel_data.append(row_excel_data)
return all_excel_data
if __name__ == '__main__':
current_path = os.path.dirname(__file__)
el_path = os.path.join(current_path, '../element_info_datas/element_info_datas.xlsx')
test_data_path = os.path.join(current_path, '..', config_obj.test_data_path)
datas = ExcelUtils(test_data_path,'login_suit').get_sheet_data_by_list()
for data in datas:
print(data)
HTMLTestReportCN.py生产测试报告类,可以自行网上下载:
log_util.py日志文件类:
日志文件目录:
import logging, os,time
from common.config_utils import config_obj
logs_path = os.path.join(os.path.dirname(__file__), '..',config_obj.get_log_path)
class LogUtils(object):
def __init__(self, logger=None):
self.log_name = os.path.join(logs_path,'UITest_%s.log'%time.strftime('%Y_%m_%d'))
self.logger = logging.getLogger(logger)
self.logger.setLevel(config_obj.get_log_level) #日志级别,info 级别
self.fh = logging.FileHandler(self.log_name, encoding='utf-8')
self.fh.setLevel(config_obj.get_log_level)
self.ch = logging.StreamHandler() #写控制带
self.ch.setLevel(config_obj.get_log_level)
formatter = logging.Formatter("[%(asctime)s] - %(filename)s - [line:%(lineno)d] - %(levelname)s: %(message)s")
self.fh.setFormatter(formatter)
self.ch.setFormatter(formatter)
self.logger.addHandler(self.fh)
self.logger.addHandler(self.ch)
self.fh.close()
self.ch.close()
def info(self, message):
return self.logger.info(message)
def error(self, message):
return self.logger.error(message)
def debug(self, message):
return self.logger.debug(message)
def critical(self, message):
return self.logger.critical(message)
def warning(self, message):
return self.logger.warning(message)
logs_obj = LogUtils()
selenium_base_case.py 测试用例初始化,清理工作封装:
# @desc:unittest 的二次封装
import unittest
from common.config_utils import config_obj
from common.browser import Browser
from common.base_page import BasePage
from common.log_utils import logs_obj
class SeleniumBaseCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.url = config_obj.get_zentao_url
def setUp(self):
self.driver = Browser().get_driver()
self.base_page = BasePage(self.driver)
self.base_page.set_browser_max()
self.base_page.implicitly_wait()
self.base_page.open_url(self.url)
def tearDown(self):
errors = self._outcome.errors
for test,exc_info in errors:
if exc_info:
self.base_page.wait(3)
self.base_page.screenshot_as_file()
logs_obj.info('----------- 测试用例执行完毕 --------')
self.base_page.quit_driver()
test_data_utils.py读取测试用例测试数据封装:
# encoding:utf-8
# @author:yangshhiyu
# @file:test_data_utils.py
# @time:2022/7/2720:54
# @desc:读取测试用例数据
import os
from common.excel_utils import ExcelUtils
from common.config_utils import config_obj
class TestDataUtils:
def __init__(self,test_suit_name,test_file_name,test_class_name):
current_path = os.path.dirname(__file__)
test_data_path = os.path.join(current_path, '..', config_obj.test_data_path)
test_data_path = os.path.join(test_data_path,test_suit_name,test_file_name+'.xlsx')
self.test_class_name = test_class_name
self.excel_data = ExcelUtils(test_data_path,test_class_name).get_sheet_data_by_list()
self.excel_row = len(self.excel_data)
def convert_exceldata_to_testdata(self):
'''把excel表中的数据转换成用例的字典数据'''
test_data_infos = {}
for i in range(1,self.excel_row):
test_data_info = {}
# if self.excel_data[i][2].__eq__(self.test_class_name):
test_data_info['test_name'] = self.excel_data[i][1]
test_data_info['isnot'] = self.excel_data[i][2]
test_data_info['isnot'] = False if self.excel_data[i][2].__eq__('是') else True
test_data_info['expected_result'] = self.excel_data[i][3]
test_parameter = {}
for j in range(4,len(self.excel_data[i])):
if self.excel_data[i][j].__contains__('=') and len(self.excel_data[i][j])>2:
parameter_info = self.excel_data[i][j].split('=')
test_parameter[parameter_info[0]] = parameter_info[1]
test_data_info['test_parameter'] = test_parameter
test_data_infos[self.excel_data[i][0]] = test_data_info
return test_data_infos
if __name__ == '__main__':
infos = TestDataUtils('qa_suit','qa_case', 'CreateBugSuit').convert_exceldata_to_testdata()
for info in infos.values():
print(info)
zip_utils.py 将测试报告压缩成zip文件,进行封装:
# encoding:utf-8
# @author:yangshhiyu
# @file:test_data_utils.py
# @time:2022/7/2720:54
# @desc:读取测试用例数据
import os
from common.excel_utils import ExcelUtils
from common.config_utils import config_obj
class TestDataUtils:
def __init__(self,test_suit_name,test_file_name,test_class_name):
current_path = os.path.dirname(__file__)
test_data_path = os.path.join(current_path, '..', config_obj.test_data_path)
test_data_path = os.path.join(test_data_path,test_suit_name,test_file_name+'.xlsx')
self.test_class_name = test_class_name
self.excel_data = ExcelUtils(test_data_path,test_class_name).get_sheet_data_by_list()
self.excel_row = len(self.excel_data)
def convert_exceldata_to_testdata(self):
'''把excel表中的数据转换成用例的字典数据'''
test_data_infos = {}
for i in range(1,self.excel_row):
test_data_info = {}
# if self.excel_data[i][2].__eq__(self.test_class_name):
test_data_info['test_name'] = self.excel_data[i][1]
test_data_info['isnot'] = self.excel_data[i][2]
test_data_info['isnot'] = False if self.excel_data[i][2].__eq__('是') else True
test_data_info['expected_result'] = self.excel_data[i][3]
test_parameter = {}
for j in range(4,len(self.excel_data[i])):
if self.excel_data[i][j].__contains__('=') and len(self.excel_data[i][j])>2:
parameter_info = self.excel_data[i][j].split('=')
test_parameter[parameter_info[0]] = parameter_info[1]
test_data_info['test_parameter'] = test_parameter
test_data_infos[self.excel_data[i][0]] = test_data_info
return test_data_infos
if __name__ == '__main__':
infos = TestDataUtils('qa_suit','qa_case', 'CreateBugSuit').convert_exceldata_to_testdata()
for info in infos.values():
print(info)
元素信息层:
登录页面元素信息类,login_page.py:
# desc:登录页面
from common.base_page import BasePage
from common.browser import Browser
from common.element_data_utils import ElementDataUtils
from common.log_utils import logs_obj
elements = ElementDataUtils('login','login_page').get_element_info()
class LoginPage(BasePage):
def __init__(self,driver):
# 元素识别分离
super().__init__(driver) # 初始化父类构建函授
logs_obj.info('------- 启动浏览器 -------')
self.username_input_box = elements['username_input_box']
self.password_input_box = elements['password_input_box']
self.login_button = elements['login_button']
self.keepLogin_checkbox = elements['keepLogin_checkbox']
def input_username(self, name):
self.send_keys(self.username_input_box, name)
def input_password(self, password):
self.send_keys(self.password_input_box, password)
def click_login(self):
self.click(self.login_button)
def click_keep_login(self):
self.click(self.keepLogin_checkbox)
#封装一个登录失败,弹出的提示框中点确认,并返回提示框中的内容
def get_login_fail_alert_content(self):
return self.switch_to_alert_2()
if __name__ == '__main__':
# 驱动处理
login_page = LoginPage(Browser().get_driver())
login_page.open_url('http://47.107.178.45/zentao/www/index.php?m=user&f=loginz')
login_page.set_browser_max()
login_page.input_username('test01')
login_page.input_password('newdream13')
login_page.click_login()
login_page.get_login_fail_alert_content()
login_page.quit_driver()
主页面元素信息类,main_page.py
# desc主页面类
from common.browser import Browser
from element_info.login.login_page import LoginPage
from common.element_data_utils import ElementDataUtils
from common.base_page import BasePage
from common.log_utils import logs_obj
class MainPage(BasePage):
def __init__(self, driver):
# 元素识别分离
super().__init__(driver) # 初始化父类构建函授
logs_obj.info('------- 启动浏览器 -------')
# 难点,页面衔接
elements = ElementDataUtils('main', 'main_page').get_element_info()
self.company_name_show_box = elements['company_name_show_box']
self.my_zone_menu = elements['my_zone_menu']
self.my_product_menu = elements['my_product_menu']
self.my_project_menu = elements['my_project_menu']
self.my_qa_menu = elements['my_qa_menu']
self.username_show_box = elements['username_show_box']
self.quit_button = elements['quit_button']
def get_company_name(self):
self.get_attribute(self.company_name_show_box)
def goto_myzone(self):
self.click(self.my_zone_menu)
def goto_product(self):
self.click(self.my_product_menu)
def goto_project(self):
self.click(self.my_project_menu)
def goto_qa(self):
self.click(self.my_qa_menu)
def get_username(self):
text = self.get_text_value(self.username_show_box)
return text
def click_username_button(self):
self.click(self.username_show_box)
def click_quit_button(self):
self.click(self.quit_button)
if __name__ == '__main__':
driver = Browser().get_driver()
LoginPage_obj = LoginPage(driver)
main_page_obj = MainPage(driver)
main_page_obj.open_url('http://47.107.178.45/zentao/www/index.php?m=user&f=loginz')
main_page_obj.set_browser_max()
# 登录
LoginPage_obj.input_username('test01')
LoginPage_obj.input_password('newdream123')
LoginPage_obj.click_login()
# 点击我的,项目,产品,
main_page_obj.get_company_name()
main_page_obj.get_username()
main_page_obj.goto_myzone()
main_page_obj.goto_project()
main_page_obj.goto_product()
main_page_obj.goto_qa()
main_page_obj.click_username_button()
main_page_obj.click_quit_button()
LoginPage_obj.quit_driver()
产品信息元素类,product_page.py暂未补充代码。
qa页面元素类,create_bug_page.py
# @desc 提bug元素和动作页面
from common.base_page import BasePage
from common.browser import Browser
from common.log_utils import logs_obj
from common.element_data_utils import ElementDataUtils
from element_info.login.login_page import LoginPage
from element_info.main.main_page import MainPage
class CreateBUGPage(BasePage):
def __init__(self,driver):
# 元素识别分离
super().__init__(driver) # 初始化父类构建函授
logs_obj.info('------- 启动浏览器 -------')
# 难点,页面衔接
elements = ElementDataUtils('qa', 'create_bug_page').get_element_info()
self.bug_module_link = elements['bug_module_link']
self.commit_bug_link = elements['commit_bug_link']
self.product_selects = elements['product_selects']
self.Ecommerce_projects_select = elements['Ecommerce_projects_select']
self.module_box_selects = elements['module_box_selects']
self.customer_center_select = elements['customer_center_select']
self.bug_errors_selects = elements['bug_errors_selects']
self.page_error_select = elements['page_error_select']
self.bug_os_selects = elements['bug_os_selects']
self.windows_select = elements['windows_select']
self.bug_browser_selects = elements['bug_browser_selects']
self.chrome_select = elements['chrome_select']
self.edition_selects = elements['edition_selects']
self.v1_0_select = elements['v1_0_select']
self.loadAllUsers_button = elements['loadAllUsers_button']
self.assignedTo_selects = elements['assignedTo_selects']
self.LanShu_select = elements['LanShu_select']
self.deadline_input = elements['deadline_input']
self.bug_title_input = elements['bug_title_input']
self.severity_selects = elements['severity_selects']
self.two_severity_select = elements['two_severity_select']
self.pri_selects = elements['pri_selects']
self.two_pri_select = elements['two_pri_select']
self.report_steps_iframe = elements['report_steps_iframe']
self.report_steps_body = elements['report_steps_body']
self.storyIdBox_span = elements['storyIdBox_span']
self.upload_file_button = elements['upload_file_button']
self.submit_button = elements['submit_button']
# 点击主页面测试 --->
def click_bug_module_link(self):
self.click(self.bug_module_link)
# 点击提bug按钮
def click_commit_bug_link(self):
self.click(self.commit_bug_link)
def get_commit_bug_text(self):
bug_text = self.get_text_value(self.commit_bug_link)
return bug_text
# 激活系统存在的产品
def click_product_selects(self):
self.click(self.product_selects)
# 选择电商项目产品项
def click_Ecommerce_projects_select(self):
self.click(self.Ecommerce_projects_select)
# 激活产品模块
def click_module_selects(self):
self.click(self.module_box_selects)
# 选择/后台-客户中心模块
def click_customer_center_select(self):
self.click(self.customer_center_select)
# 激活bug错误类型下拉框
def click_bug_selects(self):
self.click(self.bug_errors_selects)
# 点击界面错误项
def click_page_error_select(self):
self.click(self.page_error_select)
# 激活bug系统错误类型
def click_bug_os_selects(self):
self.click(self.bug_os_selects)
# 选择bug错误类型:windows
def click_bug_windows_select(self):
self.click(self.windows_select)
# 激活bug属于什么浏览器错误
def click_bug_browser_selects(self):
self.click(self.bug_browser_selects)
# 选择属于chrome 浏览器
def click_chrome_select(self):
self.click(self.chrome_select)
# 点击版本下拉框
def click_edition_selects(self):
self.click(self.edition_selects)
# 选择v1.0版本
def click_v1_0_select(self):
self.click(self.v1_0_select)
# 点击加载所有用户按钮
def click_loadAllUsers(self):
self.click(self.loadAllUsers_button)
# 激活指派人下拉列表
def click_assignedTo_selects(self):
self.click(self.assignedTo_selects)
# 选择指派人兰输
def click_LanShu_select(self):
self.click(self.LanShu_select)
# 输入截至日期:'2022-08-08'
def input_deadline(self,deadline):
self.send_keys(self.deadline_input,deadline )
# 输入bug标题:'人才中心-新增接口404'
def input_bug_title(self,bug_title):
self.send_keys(self.bug_title_input, bug_title)
# 激活严重等级下拉框
def click_severity_selects(self):
self.click(self.severity_selects)
# 选择严重程度2选项
def click_two_severity_select(self):
self.click(self.two_severity_select)
# 激活优先级下拉框
def click_pri_selects(self):
self.click(self.pri_selects)
# 选择严重程度2选项
def click_two_pri_select(self):
self.click(self.two_pri_select)
# 切入重现步骤框架中
def enter_report_steps_iframe(self):
self.switch_to_frame(element_info=self.report_steps_iframe)
# 清空重现步骤内容
def clear_report_steps_body(self):
self.clear(self.report_steps_body)
# 输入重现步骤内容:'[步骤]:1.登录成功后。2.点击人才中心。3.点击新增按钮。4.输入内容,点击保存按钮。.\n\n'
# '[结果]:点击保存提示:"system error".\n\n'
# '[期望]:点击保存提示:"保存成功"'
def input_report_steps_body(self,report_steps_content):
self.send_keys(self.report_steps_body,report_steps_content)
# 激活相关需求
def click_storyBox_span(self):
self.click(self.storyIdBox_span)
# 点击上传文件按钮
def click_upload_file_button(self):
self.click(self.upload_file_button)
# 点击提交按钮
def click_submit_button(self):
self.click(self.submit_button)
if __name__ == '__main__':
driver = Browser().get_driver()
LoginPage_obj = LoginPage(driver)
main_page_obj = MainPage(driver)
create_bug_page_obj = CreateBUGPage(driver)
main_page_obj.open_url('http://47.107.178.45/zentao/www/index.php?m=user&f=loginz')
main_page_obj.set_browser_max()
# 登录
LoginPage_obj.input_username('test01')
LoginPage_obj.input_password('newdream123')
LoginPage_obj.click_login()
main_page_obj.goto_qa()
create_bug_page_obj.click_bug_module_link()
# create_bug_page_obj.click_commit_bug_link()
print(create_bug_page_obj.get_commit_bug_text())
动作层,目录结构如下图:
login_action.py
# -- coding: utf-8 --
# @Time : 2022/7/22 17:13
# @Author : siyu.yang
# @File : login_action.py
# @Software: PyCharm
# @desc: 功能层
from element_info.login.login_page import LoginPage
from element_info.main.main_page import MainPage
from common.config_utils import config_obj
class LoginAction():
def __init__(self, driver):
self.login_page = LoginPage(driver)
# 登录操作
def login_action(self, username, password):
self.login_page.input_username(username)
self.login_page.input_password(password)
self.login_page.click_login()
def login_success(self, username, password):
self.login_action(username, password)
return MainPage(self.login_page.driver)
def login_fail(self, username, password):
self.login_action(username, password)
return self.login_page.get_login_fail_alert_content()
# 默认登录
def default_login(self):
self.login_action(config_obj.user_name, config_obj.pass_word)
return MainPage(self.login_page.driver)
# 扩展:
def login_by_cookie(self):
pass
main_action.py
# @desc: 主页面业务类
from element_info.login.login_page import LoginPage
from element_info.main.main_page import MainPage
class MainPageAction():
def __init__(self, driver):
self.main_page = MainPage(driver)
# 登录-进入我的地盘-退出
def goto_myzone_quit(self):
self.main_page.goto_myzone()
self.main_page.click_username_button()
self.main_page.click_quit_button()
return LoginPage(self.main_page.driver) # 退出操作返回主页面
# 登录-点击我的项目-退出
def goto_project_quit(self):
self.main_page.goto_project()
self.main_page.click_username_button()
self.main_page.click_quit_button()
return LoginPage(self.main_page.driver) # 退出操作返回主页面
# 登录-点击我的产品-退出
def goto_product_quit(self):
self.main_page.goto_product()
self.main_page.click_username_button()
self.main_page.click_quit_button()
return LoginPage(self.main_page.driver) # 退出操作返回主页面
#登录-获取当前登录的用户-退出
def get_username_quit(self):
self.main_page.get_username()
self.main_page.click_username_button()
self.main_page.click_quit_button()
return LoginPage(self.main_page.driver) # 退出操作返回主页面
quit_action.py
from element_info.main.main_page import MainPage
from element_info.login.login_page import LoginPage
class QuitAction():
def __init__(self, driver):
self.main_page = MainPage(driver)
def quit_action(self):
self.main_page.click_username_button()
self.main_page.click_quit_button()
return LoginPage(self.main_page.driver)
create_bug_action.py
# -- coding: utf-8 --
# @Time : 2022/7/22 17:54
# @Author : siyu.yang
# @File : create_bug_action.py
# 可以把操作封装成功能函数也行
from element_info.qa.create_bug_page import CreateBUGPage
from actions.main_action import MainPage
import os
class CreateBugAction():
def __init__(self, driver):
self.bug_page = CreateBUGPage(driver)
def commit_bug_action(self, deadline, bug_title, report_steps_content):
'''
提bug
:param deadline: 截至日期
:param bug_title: bug的标题
:param report_steps_content: 重现步骤
:return:
'''
self.bug_page.click_bug_module_link()
self.bug_page.click_commit_bug_link()
self.bug_page.click_product_selects()
self.bug_page.click_Ecommerce_projects_select()
self.bug_page.wait(1)
self.bug_page.click_module_selects()
self.bug_page.click_customer_center_select()
self.bug_page.wait(1)
self.bug_page.click_bug_selects()
self.bug_page.click_page_error_select()
self.bug_page.click_bug_os_selects()
self.bug_page.click_bug_windows_select()
self.bug_page.click_bug_browser_selects()
self.bug_page.click_chrome_select()
self.bug_page.click_edition_selects()
self.bug_page.click_v1_0_select()
self.bug_page.wait(1)
self.bug_page.click_loadAllUsers()
self.bug_page.wait(1)
self.bug_page.click_assignedTo_selects()
self.bug_page.wait(1)
self.bug_page.click_LanShu_select()
self.bug_page.wait(1)
self.bug_page.input_deadline(deadline)
self.bug_page.input_bug_title(bug_title)
self.bug_page.click_severity_selects()
self.bug_page.click_two_severity_select()
self.bug_page.click_pri_selects()
self.bug_page.click_two_pri_select()
self.bug_page.enter_report_steps_iframe()
self.bug_page.clear_report_steps_body()
self.bug_page.input_report_steps_body(report_steps_content)
self.bug_page.switch_to_frame()
self.bug_page.switch_to_default_content()
self.bug_page.scroll(150)
self.bug_page.click_storyBox_span()
self.bug_page.click_upload_file_button()
os.system('E:/auto3_script/up.exe')
self.bug_page.scroll(100)
self.bug_page.click_submit_button()
return MainPage(self.bug_page.driver)
testcase层,目录结果如下图:
login_case.py
# -- coding: utf-8 --
# @Time : 2022/7/22 17:57
# @Author : siyu.yang
# @File : login_case.py
# @Software: PyCharm
import unittest
from actions.login_action import LoginAction
from common.selenium_base_case import SeleniumBaseCase
from common.test_data_utils import TestDataUtils
class LoginCase(SeleniumBaseCase):
test_class_data = TestDataUtils('login_suit', 'login_case', 'LoginCase').convert_exceldata_to_testdata()
def setUp(self):
super().setUp()
print('LoginCase 测试类初始化父类')
# self.test_class_data = TestDataUtils('login_suit', 'LoginCase').convert_exceldata_to_testdata()
#
@unittest.skipIf(test_class_data['test_login_success'].get('isnot'), reason='如果条件为真,就执行改用例')
def test_login_success(self):
test_function_data = self.test_class_data['test_login_success']
login_action = LoginAction(self.base_page.driver)
login_action = login_action.login_success(test_function_data['test_parameter'].get('username'),
test_function_data['test_parameter'].get('password'))
actual = login_action.get_username()
self.assertEqual(actual, test_function_data['expected_result'], 'test01,登录失败')
@unittest.skipIf(test_class_data['test_login_fail_case'].get('isnot'), reason='如果条件为真,就执行改用例')
def test_login_fail(self):
test_function_data = self.test_class_data['test_login_fail_case']
login_action = LoginAction(self.base_page.driver)
actual = login_action.login_fail(test_function_data['test_parameter'].get('username'),
test_function_data['test_parameter'].get('password'))
self.assertEqual(actual, test_function_data['expected_result'])
if __name__ == '__main__':
unittest.main()
quit_case.py
import unittest
from actions.login_action import LoginAction
from actions.quit_action import QuitAction
from common.selenium_base_case import SeleniumBaseCase
from common.test_data_utils import TestDataUtils
class QuitCase(SeleniumBaseCase):
test_class_data = TestDataUtils('main_suit', 'quit_case', 'QuitCase').convert_exceldata_to_testdata()
def setUp(self):
super().setUp()
print('LoginCase 测试类初始化父类')
@unittest.skipIf(test_class_data['test_quit_success'].get('isnot'), reason='如果条件为真,就执行改用例')
def test_quit_success(self):
test_function_data = self.test_class_data['test_quit_success']
"""正常退出操作"""
login_action = LoginAction(self.driver)
main_page = login_action.default_login()
quit_action = QuitAction(main_page.driver)
login_page = quit_action.quit_action() # 退出后返回主页面
actual = login_page.get_title()
self.assertEqual(actual.__contains__('用户登录'), True)
if __name__ == '__main__':
unittest.main()
commit_bug_case.py
import unittest
from actions.login_action import LoginAction
from actions.create_bug_action import CreateBugAction
from common.selenium_base_case import SeleniumBaseCase
from common.test_data_utils import TestDataUtils
class CreateBugSuit(SeleniumBaseCase):
test_bug_class_data = TestDataUtils('qa_suit', 'qa_case', 'CreateBugSuit').convert_exceldata_to_testdata()
def setUp(self):
super().setUp()
print('LoginCase 测试类初始化父类')
# self.test_bug_class_data = TestDataUtils('bug_suit', 'CreateBugSuit').convert_exceldata_to_testdata()
@unittest.skipIf(test_bug_class_data['test_commit_bug_success'].get('isnot'), reason='如果条件为真,就执行改用例')
def test_commit_bug_success(self):
"""正常提交bug操作"""
test_function_data = self.test_bug_class_data['test_commit_bug_success']
login_action = LoginAction(self.base_page.driver)
main_page = login_action.default_login()
main_page.goto_qa()
bug_page = CreateBugAction(main_page.driver)
bug_page.commit_bug_action(test_function_data['test_parameter'].get('deadline'),
test_function_data['test_parameter'].get('bug_title'),
test_function_data['test_parameter'].get('report_steps_content'))
actual_result = main_page.get_title()
self.assertEqual(actual_result.__contains__(test_function_data['expected_result']), True)
if __name__ == '__main__':
unittest.main()
screen_shot 截图图片层
test_data测试数据层,目录结构如下图;
其中login_case.xlsx内容为,其它页面内容相似:
runner 运行层,run_all_case.py
import os, unittest
import shutil
import sys
sys.path.append('C:\\Users\\kcadmin\\Desktop\\python code\\PO_UI_Test_Framework')
from common import HTMLTestReportCN
from common.config_utils import config_obj
from common.email_utils import EmailUtils
current_path = os.path.dirname(__file__)
case_path = os.path.join(current_path, '..', config_obj.case_path)
report_path = os.path.join(current_path, '..', config_obj.report_path)
class RunAllCase:
def __init__(self):
self.test_case = case_path
self.report_path = report_path
self.title = "禅道UI自动化测试报告"
self.description = "禅道UI自动化测试报告"
def run(self):
discover = unittest.defaultTestLoader.discover(start_dir=self.test_case,
pattern='*_case.py',
top_level_dir=self.test_case)
all_suit = unittest.TestSuite()
all_suit.addTest(discover)
report_dir = HTMLTestReportCN.ReportDirectory(self.report_path)
report_dir.create_dir(self.title)
dir_path = HTMLTestReportCN.GlobalMsg.get_value('dir_path')
report_path = HTMLTestReportCN.GlobalMsg.get_value('report_path')
fp = open(report_path, 'wb')
runner = HTMLTestReportCN.HTMLTestRunner(stream=fp,
title=self.title,
description=self.description,
tester='YangShiYu')
runner.run(all_suit)
fp.close()
return dir_path
if __name__ == '__main__':
dir_path = RunAllCase().run() #运行所有用例
#将生成的测试报告打包成zip文件,并发送邮件
# shutil.copytree(dir_path,sys.argv[1])
smtp_body = '禅道UI自动化测试报告,请注意查收!'
send_email_obj = EmailUtils(smtp_body, dir_path).zip_send_mail()
最后运行run_all_case.py,会自动生产测试报告和产生日志文件,且对应的邮件也会收到运行的测试报告
本文暂时没有评论,来添加一个吧(●'◡'●)