一个基于POM模式的Web自动化测试框架
程序员文章站
2022-07-14 08:39:10
...
基于最近可能工作要求,和自动化脚本效率的问题上,对设计模式进行了一些了解
所以参考性的编写了一个这样的POM模式的Web自动化测试框架
如果大家有需要,可以看看,指导探讨一下
整体的文件目录
设置了公共文档的读出,在config.ini
可以把一下公共的东西,如url,账号等放进去
- 对公共类进行了封装 为Common中basePage包
class BasePage:
"""测试基类"""
def __init__(self, driver):
self.driver = driver
def get_img(self):
"""截图"""
# img文件夹路径
img_path = os.path.join(test_123.getcwd.get_cwd(), 'img/')
# img文件夹不存在,新建该文件夹
if not os.path.exists(img_path):
os.makedirs(img_path)
# 获取当前日期
local_date = time.strftime('%Y-%m-%d', time.localtime(time.time()))
# 日期文件夹路径
date_file_path = os.path.join(img_path,local_date)
# 日期文件夹不存在,新建该文件夹
if not os.path.exists(date_file_path):
os.makedirs(date_file_path)
# 截图存放路径
local_time = time.strftime('%Y-%m-%d %H%M%S', time.localtime(time.time()))
jt_name = local_time+'.png'
jt_path = os.path.join(date_file_path, jt_name)
try:
self.driver.get_screenshot_as_file(jt_path)
log1.info('截图保存成功')
except BaseException:
log1.error('截图失败', exc_info=1)
print('Screenshot_Path:', jt_path)
def open_browser(self):
"""打开浏览器,访问url"""
browser = config.config_read('environment', 'browser')
log1.info('读取浏览器配置,值为%s' % browser)
url = config.config_read('environment', 'url')
log1.info('读取url,值为%s' % url)
# noinspection PyBroadException
try:
if browser == 'chrome':
option = webdriver.ChromeOptions()
option.add_argument('disable-infobars')
self.driver = webdriver.Chrome(chrome_options=option)
log1.info('打开chrome浏览器')
elif browser == 'firefox':
self.driver = webdriver.Firefox()
log1.info('打开firefox浏览器')
else:
log1.error('浏览器配置有误,应为chrome或firefox')
self.driver.get(url)
log1.info('访问url')
self.driver.maximize_window()
log1.info('浏览器最大化')
self.driver.implicitly_wait(10)
log1.info('设置静态等待时间10秒')
return self.driver
except BaseException:
log1.error('浏览器打开报错', exc_info=1)
def get_element(self, selector):
"""定位元素"""
by = selector[0]
value = selector[1]
bys = ['id', 'name', 'class', 'tag', 'link', 'plink', 'css', 'xpath']
element = None
if by in bys:
try:
if by == 'id':
element = self.driver.find_element_by_id(value)
elif by == 'name':
element = self.driver.find_element_by_name(value)
elif by == 'class':
element = self.driver.find_element_by_class_name(value)
elif by == 'tag':
element = self.driver.find_element_by_tag_name(value)
elif by == 'link':
element = self.driver.find_element_by_link_text(value)
elif by == 'plink':
element = self.driver.find_element_by_partial_link_text(value)
elif by == 'css':
element = self.driver.find_element_by_css_selector(value)
elif by == 'xpath':
element = self.driver.find_element_by_xpath(value)
log1.info('元素定位成功。定位方式:%s,使用的值:%s' % (by, value))
return element
except NoSuchElementException:
log1.error('没有定位到元素,定位方式:%s,使用的值:%s' % (by, value), exc_info=1)
else:
log1.error('元素定位方式错误,请使用id,name,class,tag,link,plink,css,xpath为定位方式参数')
@staticmethod
def isdisplayed(element):
"""元素是否存在"""
value = element.is_displayed()
return value
def type(self, selector, value):
"""往输入框输入内容"""
element = self.get_element(selector)
element.clear()
# noinspection PyBroadException
try:
element.send_keys(value)
log1.info('输入的内容:%s' % value)
except BaseException:
log1.error('内容输入报错', exc_info=1)
self.get_img()
def click(self, selector):
"""点击元素"""
element = self.get_element(selector)
# noinspection PyBroadException
try:
element.click()
log1.info('点击元素成功')
except BaseException:
isdisplay = self.isdisplayed(element)
if isdisplay is True:
self.my_sleep(3)
element.click()
log1.info('点击元素成功')
else:
log1.error('点击元素报错', exc_info=1)
@staticmethod
def my_sleep(secondes):
"""强制等待"""
time.sleep(secondes)
log1.info('强制等待%d秒' % secondes)
def get_title(self):
"""获取title"""
title = self.driver.title
log1.info('当前打开的title是:%s' % title)
return title
def get_text(self, selector):
"""获取text"""
element = self.get_element(selector)
text = element.text
log1.info("获取的text:%s" % text)
return text
def use_js(self, js):
"""调用js"""
# noinspection PyBroadException
try:
self.driver.execute_script(js)
log1.info('js执行成功,js内容为:%s' % js)
except BaseException:
log1.error('js执行报错', exc_info=1)
def switch_menue(self, parentelement, secelement, targetelement):
"""三级菜单切换"""
self.my_sleep(3)
# noinspection PyBroadException
try:
self.driver.switch_to_default_content()
self.click(parentelement)
log1.info('成功点击一级菜单:%s' % parentelement)
self.click(secelement)
log1.info('成功点击二级菜单:%s' % secelement)
self.click(targetelement)
log1.info('成功点击三级菜单:%s' % targetelement)
except BaseException:
log1.error('切换菜单报错', exc_info=1)
def switch_ifarme(self, selector):
"""切换farm"""
element = self.get_element(selector)
# noinspection PyBroadException
try:
self.driver.switch_to.frame(element)
log1.info('切换frame成功')
except BaseException:
log1.error('切换frame报错', exc_info=1)
def get_handle(self):
"""获得当前handle"""
handle = self.driver.current_window_handle
return handle
def chage_handle(self, handle):
"""切换窗口"""
handles = self.driver.window_handles
for i in handles:
if i != handle:
self.driver.switch_to_window(i)
def dr_quit(self):
self.driver.quit()
2.对LOG日志类也进行封装log.py
def get_log(logger_name):
# 获取项目的根目录
project_path = test_123.getcwd.get_cwd()
Logs_path = os.path.join(project_path, 'Logs')
# 获取本地时间,转为年-月-日格式
local_date = time.strftime('%Y-%m-%d', time.localtime(time.time()))
# 日期文件夹路径
date_file_path = os.path.join(Logs_path, local_date)
# 如果没有日期文件夹,创建该文件夹
if not os.path.exists(date_file_path):
os.makedirs(date_file_path)
# 完整日志存放路径
all_log_path = os.path.join(date_file_path, 'All_Logs/')
# 如果没有完整日志文件夹,创建该文件夹
if not os.path.exists(all_log_path):
os.makedirs(all_log_path)
# 错误日志存放路径
error_log_path = os.path.join(date_file_path, 'Error_Logs/')
# 如果没有错误日志文件夹,创建该文件夹
if not os.path.exists(error_log_path):
os.makedirs(error_log_path)
# 获取本地时间,转为年月日时分秒格式
local_time = time.strftime('%Y-%m-%d %H%M%S', time.localtime(time.time()))
# 设置日志文件名
all_log_name = all_log_path + local_time + '.log'
error_log_name = error_log_path + local_time + '.log'
# 创建一个logger
logger = logging.getLogger(logger_name)
logger.setLevel(logging.INFO)
# 创建handler
# 创建一个handler写入所有日志
fh = logging.FileHandler(all_log_name)
fh.setLevel(logging.INFO)
# 创建一个handler写入错误日志
eh = logging.FileHandler(error_log_name)
eh.setLevel(logging.ERROR)
# 创建一个handler输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
# 定义日志输出格式
# 以时间-日志器名称-日志级别-日志内容的形式展示
all_log_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# 以时间-日志器名称-日志级别-文件名-函数行号-错误内容
error_log_formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(module)s - %(lineno)s - %(message)s')
# 将定义好的输出形式添加到handler
fh.setFormatter(all_log_formatter)
ch.setFormatter(all_log_formatter)
eh.setFormatter(error_log_formatter)
# 给logger添加handler
logger.addHandler(fh)
logger.addHandler(eh)
logger.addHandler(ch)
return logger
log1 = get_log('selenium')
3.POM下简单的元素界面
from test_123.Common.basePage import BasePage
class HomePage(BasePage):
"""51"""
qydl = ['id', 'qydl']
txtent_userName=['id', 'txtent_userName']
txtent_userPwd=['id','txtent_userPwd']
imgbtnuserLogin=['id','imgbtnuserLogin']
spanError=['id','spanError']
def login_click(self, value):
"""输入账号"""
self.click(self.qydl)
self.click(self.txtent_userName)
self.type(self.txtent_userName,value)
def login1_click(self, value):
'''输入密码'''
self.click(self.txtent_userPwd)
self.type(self.txtent_userPwd,value)
self.click(self.imgbtnuserLogin)
ssf=self.get_text(self.spanError)
print(ssf)
4.测试集合的用例管理
import unittest
from test_123.Common.basePage import BasePage
from test_123.PageObject.homePage import HomePage
from test_123.Common.log import log1
from test_123.Common.HTMLTestRunner import *
class TestHome(unittest.TestCase):
"""测试主页面"""
def setUp(self):
browser = BasePage(self)
self.driver = browser.open_browser()
def test_login(self):
"""测试搜索"""
case_name = '测试搜索'
log1.info("执行测试用例:%s" % case_name)
home = HomePage(self.driver)
home.my_sleep(2)
title=home.login_click('123456')
title1=home.login1_click('123456')
def tearDown(self):
home = HomePage(self.driver)
home.dr_quit()
5.对用例进行集合输出报告
调用HtmlTestRuuner进行报告:
entrance.py
import test_123.Common.HTMLTestRunner
import unittest
import logging
from time import strftime, localtime, time
from test_123.TestSuites.testHome import TestHome
suite = unittest.TestSuite()
# 获取TestSuite的实例对象
suite.addTest(TestHome('test_login'))
# 把测试用例添加到测试容器中
now = strftime("%Y-%m-%d-%H_%M_%S", localtime(time()))
# 获取当前时间
filename = now + "test.html"
# 文件名
fp = open(filename, "wb")
# 以二进制的方式打开文件并写入结果
runner = test_123.Common.HTMLTestRunner.HTMLTestRunner(
stream=fp,
verbosity=2,
title="51.test",
description="测试报告的详情")
runner.run(suite)
fp.close()
log_format = '%(asctime)s - %(levelname)s - %(message)s'
logging.basicConfig(filename="server.log", filemode='a+', format=log_format, level=logging.DEBUG)
6.当用例进行了测试后,对测试用例发送到自己邮箱,这个在搭建在Jenkins上时就可以定时看报告
#!/usr/bin/python3
import os
import time
import smtplib
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from test_123.entrance import filename
import test_123.getcwd
from test_123.Common.config import Config
from test_123.Common.log import log1
config = Config()
#rq = time.strftime('%Y%m%d', time.localtime(time.time())) # 获取本地时间 转换成日期
my_sender = config.config_read('sender', 'email') # 发件人邮箱账号
my_pass = config.config_read('sender', 'password') # 发件人邮箱密码
usernmae = config.config_read('sender', 'username') # 发件人姓名 #
my_user = config.config_read('addressed','heemail') # 收件人邮箱
path = test_123.getcwd.get_cwd()
file = 'E:\\untitled\\test_123\\Common\\'+ filename#附件路径
def mail():
ret = True
try:
# 构造一个邮件体:正文 附件
msg = MIMEMultipart()
msg['Subject'] = "51测试" # 主题
msg['From'] = my_sender # 发件人
msg['To'] = my_user # 收件人
# 构建正文
part_text = MIMEText("这个是UI测试,HTMLtextrunner测试报告")
msg.attach(part_text) # 把正文加到邮件体里面去
# 构建邮件附件
# file = file #获取文件路径
part_attach1 = MIMEApplication(open(file, 'rb').read()) # 打开附件
part_attach1.add_header('Content-Disposition', 'attachment', filename=file) # 为附件命名
msg.attach(part_attach1) # 添加附件
server = smtplib.SMTP_SSL("smtp.qq.com", 465) # 发件人邮箱中的SMTP服务器,设置端口是465
server.login(my_sender, my_pass) # 括号中对应的是发件人邮箱账号、邮箱密码
server.sendmail(my_sender, [my_user, ], msg.as_string()) # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
server.quit() # 关闭连接
except Exception: # 如果 try 中的语句没有执行,则会执行下面的 ret=False
ret = False
return ret
ret = mail()
if ret:
print("邮件发送成功")
else:
print("邮件发送失败件")
到这里就简单介绍了一下过程,水平不足,可能说得不太明白
如果大家需要的话,可以找我要一下全部源码
上一篇: 实现一个Python+Selenium的自动化测试框架
下一篇: VMware连接另一台电脑的虚拟机
推荐阅读
-
JAVA WEB快速入门之从编写一个基于SpringMVC框架的网站了解Maven、SpringMVC、SpringJDBC
-
用Python 写一个用于芯片自动化测试的管理小框架
-
实现一个Python+Selenium的自动化测试框架
-
一个基于POM模式的Web自动化测试框架
-
Airtest是一个跨平台的UI自动化测试框架
-
实现一个Python+Selenium的自动化测试框架就这么简单!
-
基于Python的接口自动化unittest测试框架和ddt数据驱动详解
-
基于appium的app自动化测试框架
-
浅谈基于Pytest框架的自动化测试开发实践
-
JAVA WEB快速入门之从编写一个基于SpringMVC框架的网站了解Maven、SpringMVC、SpringJDBC