Page Object 是 Selenium 自动化测试项目开发实践的最佳设计模式之一,Page Object 的主要体现于对界面交互细节的封装,这样可以使测试案例更关注与业务而非界面细节,提高测试案例的可读性。
认识 Paget Object
一、Page object 简称POM框架
POM提供了一种在UI层操作、业务流程与验证分离的模式,这使得测试代码变得更加清晰和高可读性;
对象库与用例分离,使得我们更好的复用对象,甚至能与不同的工具进行深度结合应用;
可复用的页面方法代码会变得更加优化;
更加有效的命名方式使得我们更加清晰的知道方法所操作的UI元素。例如我们要回到首页,方法名命名为: gotoHomePage(),通过方法名即可清晰的知道具体的功能实现。;
二、Page object设计模式的优点
减少代码的重复;
提高测试用例的可读性;
提高测试用例的可维护性,特别是针对 UI 频繁变化的项目;
实战--博客园登录自动化测试发送测试报告
思路分析:
浏览器封装;
页面截图函数封装,偏于后续浏览查看;
页面元素基础类操作封装,包含断言设计;
登录元素操作封装;
登录测试用例设计;
代码参考
myunit.py
# 浏览器驱动封装
'''
@author: Yvon_早安阳光
'''
from selenium import webdriver
import unittest
class MyTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
def tearDown(self):
self.driver.quit()
function.py
'''
@author: Yvon_早安阳光
'''
import time
from selenium import webdriver
#封装截图函数
def insert_img(driver,filename):
file_path = 'insert_img/'
now = time.strftime("%Y-%m-%d %H_%M_%S")
screen_name = file_path + '\\' + now + filename
driver.get_screenshot_as_file(screen_name)
# 登录成功截图
def success_img(driver,file_name):
filepath = 'success_img/'
now = time.strftime("%Y-%m-%d %H_%M_%S")
screenname = filepath + '\\' + now + file_name
driver.get_screenshot_as_file(screenname)
if __name__ == '__main__':
driver = webdriver.Firefox()
driver.quit()
Base.py
# 页面元素基础类操作封装
'''
@author: Yvon_早安阳光
'''
class Page(object):
#BasePage封装所有页面都公用的方法,例如driver, url ,FindElement等
login_url = "https://passport.cnblogs.com/user/signin"
#实例化BasePage类时,最先执行的就是__init__方法,该方法的入参,其实就是BasePage类的入参。
#__init__方法不能有返回值,只能返回None,self只实例本身,相较于类Page而言
def __init__(self,selenium_driver,base_url = login_url,parent = None):
self.base_url = base_url
self.driver = selenium_driver
self.timeout =10
self.parent = parent
'''通过title断言进入的页面是否正确。使用title获取当前窗口title,检查输入的title是否在当前title中,返回比较结果(True 或 False)'''
def on_page(self):
return self.driver.current_url == (self.base_url + self.url)
'''#打开页面,并校验页面链接是否加载正确,以单下划线_开头的方法,在使用import *时,该方法不会被导入,保证该方法为类私有的。'''
def _open(self,url):
#使用get打开访问链接地址
url = self.base_url + url
self.driver.get(url)
#使用assert进行校验,打开的窗口title是否与配置的title一致。调用on_page()方法
# assert self.on_page(), u"打开开页面失败 %s"%url
'''定义open方法,调用_open()进行打开链接'''
def open(self):
self._open(self.url)
def find_elements(self,*loc):
return self.driver.find_elements(*loc)
'''重写switch_frame方法'''
def switch_frame(self, loc):
return self.driver.switch_to_frame(loc)
'''script方法,用于执行js脚本,范围执行结果'''
def script(self, src):
self.driver.execute_script(src)
'''重写定义send_keys方法'''
def send_keys(self, loc, vaule, clear_first=True, click_first=True):
try:
loc = getattr(self,"_%s"% loc) #getattr相当于实现self.loc
if click_first:
self.find_element(*loc).click()
if clear_first:
self.find_element(*loc).clear()
self.find_element(*loc).send_keys(vaule)
except AttributeError:
print (u"%s 页面中未能找到 %s 元素"%(self, loc))
LoginPage.py
登录元素操作封装
'''
@author: Yvon_早安阳光
'''
from selenium.webdriver.common.by import By
from Base import Page
from time import sleep
class login(Page):
'''博客园登录页面模型'''
url = '/'
# 定位器
'''用户名'''
username_loc = (By.ID,"input1")
'''密码'''
password_loc = (By.ID,"input2")
'''登陆按钮'''
submit_loc = (By.ID,"signin")
'''输入用户名:调用send_keys对象,输入用户名'''
def input_username(self,username):
self.find_element(*self.username_loc).clear()
self.find_element(*self.username_loc).send_keys(username)
'''输入密码:调用send_keys对象,输入密码'''
def input_password(self,password):
self.find_element(*self.password_loc).clear()
self.find_element(*self.password_loc).send_keys(password)
'''点击登录:调用send_keys对象,点击登录'''
def click_submit(self):
self.find_element(*self.submit_loc).click()
# 定义统一登录入口
def user_login(self,username = '123',password = '123'):
'''获取用户的用户名和密码'''
self.open()
self.input_username(username)
self.input_password(password)
self.click_submit()
sleep(2)
'''用户为空'''
user_error_hint_loc = (By.XPATH,".//*[@id='tip_input1']")
'''密码为空'''
pawd_error_hint_loc = (By.XPATH,".//*[@id='tip_input2']")
'''用户名和密码不匹配'''
user_pawd_error_hint_loc = (By.XPATH,".//*[@id='tip_btn']")
'''登陆成功ID校验'''
user_login_success_loc = (By.ID,"lnk_current_user")
#用户名错误提示
def user_error_hint(self):
return self.find_element(*self.user_error_hint_loc).text
#密码错误提示
def pawd_error_hint(self):
return self.find_element(*self.pawd_error_hint_loc).text
#用户名和密码不匹配错误提示
def user_pawd_error_hint(self):
return self.find_element(*self.user_pawd_error_hint_loc).text
#登录成功用户名
def user_login_success(self):
return self.find_element(*self.user_login_success_loc).text
Login_sta.py
登录测试用例
'''
@author: Yvon_早安阳光
'''
from time import sleep
import unittest,random
from Login1 import myunit
from LoginPage import login
from Login1 import function
class LoginTest(myunit.MyTest):
'''博客园登录'''
#测试用户登录
def user_login_verify(self,username = "",password = ""):
login(self.driver).user_login(username,password)
def test_login1(self):
'''用户名、密码为空'''
self.user_login_verify()
po = login(self.driver)
self.assertEqual(po.user_error_hint(),'请输入登录用户名')
print(po.user_error_hint())
sleep(1)
# '''单个截图'''
# screen_name = 'insert_img/' + '\\' + time.strftime("%Y-%m-%d %H_%M_%S")
# self.driver.get_screenshot_as_file(str(screen_name ) + "请输入登录用户名.jpg")
u"""封装函数截图"""
function.insert_img(self.driver,"用户名和密码为空.jpg")
def test_login2(self):
'''用户名正确、密码为空'''
self.user_login_verify(username='a2036')
po = login(self.driver)
self.assertEqual(po.pawd_error_hint(),'请输入密码')
print(po.pawd_error_hint())
sleep(1)
function.insert_img(self.driver,"用户名正确-密码为空.jpg")
def test_login3(self):
'''用户名为空、密码正确'''
self.user_login_verify(password ='123456')
po = login(self.driver)
self.assertEqual(po.user_error_hint(),'请输入登录用户名')
print(po.user_error_hint())
sleep(1)
function.insert_img(self.driver,"用户名为空-密码正确.jpg")
def test_login4(self):
'''用户名和密码不匹配'''
character = random.choice('zyxwvutsrqponmlkjihgfedcba')
user_name = 'zhangsan' + character
self.user_login_verify(username=user_name,password ='123456')
sleep(2)
po = login(self.driver)
self.assertEqual(po.user_pawd_error_hint(),'该用户不存在\n\n联系 [email protected]')
print(po.user_pawd_error_hint())
sleep(1)
function.insert_img(self.driver,"用户名和密码不匹配.jpg")
def test_login5(self):
'''用户名、密码正确登录'''
self.user_login_verify(username='a2036', password ='20A3d4p43W36#20')
sleep(1)
po = login(self.driver)
sleep(1)
self.assertEqual(po.user_login_success(),'a2036')
print(po.user_login_success())
function.success_img(self.driver,"登录成功.jpg")
if __name__ == '__main__':
unittest.main()
Send_mail_report.py
发送邮件包含测试报告、邮件标题、邮件正文,附件(图片、PDF)
'''
@author: Yvon_早安阳光
'''
import unittest,time,os,smtplib
from HTMLTestRunner import HTMLTestRunner
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.mime.application import MIMEApplication
from email.mime.text import MIMEText
#======================定义发送邮件======================
def send_mail(file_new):
#测试报告
'''file_new是指最新的测试报告'''
f = open(file_new,'rb')
mail_body = f.read()
f.close()
msg = MIMEMultipart()
'''邮件标题'''
msg['Subject'] = Header('博客园登录测试报告' ,'utf-8')
'''邮件正文'''
zhengwen = "各位,详情测试结果请见附件文档"
msg.attach(MIMEText(zhengwen, 'plain'))
'''附件测试报告 '''
att= MIMEText(mail_body,'html','utf-8')
att.add_header('Content-Disposition', 'attachment', filename='New_TestReport.html')
msg.attach(att)
'''附件图片'''
jpgpart = MIMEApplication(open('fujian/测试计划.jpg','rb').read())
jpgpart.add_header('Content-Disposition', 'attachment', filename='测试计划.jpg')
msg.attach(jpgpart)
'''附件PDF'''
pdfpart = MIMEApplication(open('fujian/功能需求.pdf','rb').read())
pdfpart.add_header('Content-Disposition', 'attachment', filename='功能需求.pdf')
msg.attach(pdfpart)
#发送邮件
smtp = smtplib.SMTP()
smtp.connect('smtp.exmail.qq.com')
smtp.login('[email protected]','36#20qa20A')
smtp.sendmail('[email protected]','[email protected]',msg.as_string())
print('email has send out !')
smtp.quit()
#======================查找测试报告的目录,找到最新生成的测试报告======================
def new_report(testreport):
lists = os.listdir(testreport)
lists.sort(key = lambda fn: os.path.getatime(testreport + '\\' + fn))
file_new = os.path.join(testreport,lists[-1])
print(file_new)
return file_new
if __name__ == '__main__':
#指定测试用例为当前文件夹下的目录
test_dir = './'
discover = unittest.defaultTestLoader.discover(test_dir, pattern='login_sta*.py')
#定义报告存放的路径
result_report_dir= 'result_report/'
'''实时当前的时间'''
now = time.strftime("%Y-%m-%d %H_%M_%S")
file_name = result_report_dir + '\\' + now +'result.html'
fp = open(file_name,'wb')
#定义测试报告
runner =HTMLTestRunner(stream = fp,title ='自动化测试报告',
description='用例执行情况:')
runner.run(discover)
fp.close() #关闭报告文件
new_report = new_report(result_report_dir)
send_mail(new_report)
脚本目录
1.本地文件目录.png
2.图片和文档附件存放目录.png
3.测试用例测试结果截图目录.png
4.测试报告目录.png
5.登录成功附件目录.png
6.邮件接收附件和测试报告.png
7.自动化详细测试报告.png