Page Object 设计原理

Page Object设计模式是Selenium自动化测试项目的最佳设计模式之一,强调测试、逻辑、数据和驱动相互分离。

Page Object模式是Selenium中的一种测试设计模式,主要是将每一个页面设计为一个Class,其中包含页面中需要测试的元素(按钮,输入框,标题等),这样在Selenium测试页面中可以通过调用页面类来获取页面元素,这样巧妙的避免了当页面元素id或者位置变化时,需要改测试页面代码的情况。当页面元素id变化时,只需要更改测试页Class中页面的属性即可。

它的好处如下:

  • 集中管理元素对象
  • 集中管理一个page内的公共方法
  • 后期维护方便

Page Object 的对象

  1. WebDriver封装

    • 这里是对Selenium的封装,完成封装以后的基本封装代码。
  2. Page 基类
    • 设计了一个基本的Page类,以便所有的页面进行继承,该类标明了一个sub page类的基本功能和公共的功能。
  3. Sub Pages(s)子类
    • 具体的页面的类,定义了某个具体的页面的功能。
  4. Tests 类
    • 这部分描述的是具体的测试用例。
  5. 定义Test Suite
    • 多个测试用例添加在一个Test套件里面,一起执行。
  6. 定义Test Runner
    • 设计测试的Runner,开启整个测试,并且对测试的结果生成HTML测试报告,并通过邮件发送到指定邮箱。
  7. 定义测试的主入口
    • 定义测试的主要入口类,代码的入口

HTML测试报告

HTML测试报告需要引入HTMLTestRunner

from ranzhiWeekend import HTMLTestRunner

HTMLTestRunner是基于Python2.7的,我们的课程讲义基于Python3.x,那么需要对这个文件做一定的修改。

测试的示例代码如下

       # 声明一个测试套件
suite = unittest.TestSuite()
# 添加测试用例到测试套件
suite.addTest(RanzhiTests("test_ranzhi_login")) # 创建一个新的测试结果文件
buf = open("./result.html", "wb") # 声明测试运行的对象
runner = HTMLTestRunner.HTMLTestRunner(stream=buf,
title="Ranzhi Test Result",
description="Test Case Run Result")
# 运行测试,并且将结果生成为HTML
runner.run(suite) # 关闭文件输出
buf.close()

集成测试报告

使用邮件发送HTML测试报告的脚本如下

        # 打开测试报告结果
f = open("./result.html", "rb") # 将测试结果放到邮件的主体中
mailBody = f.read()
# 关闭测试结果的文件
f.close() # 声明一个邮件对象,用刚刚得到的邮件主体
msg = MIMEText(mailBody, "html", "utf-8")
# 设置邮件的主题
msg["subject"] = Header("Automation Test Result", "utf-8") # 创建一个SMTP服务对象
# simple message transfer protocol
# 简单的消息转移协议
smtpMail = smtplib.SMTP() # 连接SMTP的服务器
smtpMail.connect("mail.51testing.com") # 登录SMTP的服务器
smtpMail.login("liutingli@51testing.com", "123456789") # 使用SMTP的服务器发送邮件
smtpMail.sendmail("liutingli@51testing.com", targetEmail, msg.as_string()) # 退出SMTP对象
smtpMail.quit()

自动化测试框架示例

WebDriver封装

# coding=utf-8
from selenium import webdriver
from selenium.webdriver.support.select import Select class AutomateDriver(object):
"""
a simple demo of selenium framework tool
""" def __init__(self): driver = webdriver.Firefox()
try:
self.driver = driver
except Exception:
raise NameError("Firefox Not Found!") def clearCookies(self):
"""
clear all cookies after driver init
"""
self.driver.delete_all_cookies() def refreshBrowser(self):
self.driver.refresh() def maximizeWindow(self):
self.driver.maximize_window() def navigate(self, url):
self.driver.get(url) def quitBrowser(self):
self.driver.quit() def closeBrowser(self):
self.driver.close() def getElement(self, selector):
"""
to locate element by selector
:arg
selector should be passed by an example with "i,xxx"
"x,//*[@id='langs']/button"
:returns
DOM element
"""
if ',' not in selector:
return self.driver.find_element_by_id(selector)
selector_by = selector.split(',')[0]
selector_value = selector.split(',')[1] if selector_by == "i" or selector_by == 'id':
element = self.driver.find_element_by_id(selector_value)
elif selector_by == "n" or selector_by == 'name':
element = self.driver.find_element_by_name(selector_value)
elif selector_by == "c" or selector_by == 'class_name':
element = self.driver.find_element_by_class_name(selector_value)
elif selector_by == "l" or selector_by == 'link_text':
element = self.driver.find_element_by_link_text(selector_value)
elif selector_by == "p" or selector_by == 'partial_link_text':
element = self.driver.find_element_by_partial_link_text(selector_value)
elif selector_by == "t" or selector_by == 'tag_name':
element = self.driver.find_element_by_tag_name(selector_value)
elif selector_by == "x" or selector_by == 'xpath':
element = self.driver.find_element_by_xpath(selector_value)
elif selector_by == "s" or selector_by == 'selector_selector':
element = self.driver.find_element_by_css_selector(selector_value)
else:
raise NameError("Please enter a valid type of targeting elements.") return element def type(self, selector, text):
"""
Operation input box. Usage:
driver.type("i,el","selenium")
"""
el = self.getElement(selector)
el.clear()
el.send_keys(text) def click(self, selector):
"""
It can click any text / image can be clicked
Connection, check box, radio buttons, and even drop-down box etc.. Usage:
driver.click("i,el")
"""
el = self.getElement(selector)
el.click() def selectByIndex(self, selector, index):
"""
It can click any text / image can be clicked
Connection, check box, radio buttons, and even drop-down box etc.. Usage:
driver.select_by_index("i,el")
"""
el = self.getElement(selector)
Select(el).select_by_index(index) def clickByText(self, text):
"""
Click the element by the link text Usage:
driver.click_text("新闻")
"""
self.getElement('p,' + text).click() def submit(self, selector):
"""
Submit the specified form. Usage:
driver.submit("i,el")
"""
el = self.getElement(selector)
el.submit() def executeJs(self, script):
"""
Execute JavaScript scripts. Usage:
driver.js("window.scrollTo(200,1000);")
"""
self.driver.execute_script(script) def getAttribute(self, selector, attribute):
"""
Gets the value of an element attribute. Usage:
driver.get_attribute("i,el","type")
"""
el = self.getElement(selector)
return el.getAttribute(attribute) def getText(self, selector):
"""
Get element text information. Usage:
driver.get_text("i,el")
"""
el = self.getElement(selector)
return el.text def getDisplay(self, selector):
"""
Gets the element to display,The return result is true or false. Usage:
driver.get_display("i,el")
"""
el = self.getElement(selector)
return el.is_displayed() def getTitle(self):
'''
Get window title. Usage:
driver.get_title()
'''
return self.driver.title def getUrl(self):
"""
Get the URL address of the current page. Usage:
driver.get_url()
"""
return self.driver.current_url def acceptAlert(self):
'''
Accept warning box. Usage:
driver.accept_alert()
'''
self.driver.switch_to.alert.accept() def dismissAlert(self):
'''
Dismisses the alert available. Usage:
driver.dismissAlert()
'''
self.driver.switch_to.alert.dismiss() def implicitlyWait(self, secs):
"""
Implicitly wait. All elements on the page. Usage:
driver.implicitly_wait(10)
"""
self.driver.implicitly_wait(secs) def switchFrame(self, selector):
"""
Switch to the specified frame. Usage:
driver.switch_to_frame("i,el")
"""
el = self.getElement(selector)
self.driver.switch_to.frame(el) def switchDefaultFrame(self):
"""
Returns the current form machine form at the next higher level.
Corresponding relationship with switch_to_frame () method. Usage:
driver.switch_to_frame_out()
"""
self.driver.switch_to.default_content() def openNewWindow(self, selector):
'''
Open the new window and switch the handle to the newly opened window. Usage:
driver.open_new_window()
'''
original_windows = self.driver.current_window_handle
el = self.getElement(selector)
el.click()
all_handles = self.driver.window_handles
for handle in all_handles:
if handle != original_windows:
self.driver._switch_to.window(handle)

Base Page类

class RanzhiBasePage():
def __init__(self, driver, baseUrl):
"""
构造方法
:param driver: 封装好的webdriver
:param baseUrl: 然之系统的基本url http://【localhost:808】/ranzhi/www
""" self.baseUrl = baseUrl
self.driver = driver def openPage(self, url):
"""
打开然之系统的页面,通过拼接URL的方式
:param url: /sys/index.html
:return:
"""
self.driver.navigate(self.baseUrl + url)

Sub Page类

from ranzhiWeekend.ranzhi_base_page import RanzhiBasePage

class RanzhiSubLoginPage(RanzhiBasePage):
def __init__(self, driver, baseUrl):
""" :param driver:
:param baseUrl:
"""
# 调用其 基类 RanzhiBasePage的 构造函数
# 实现 基类 的构造函数的功能
super().__init__(driver, baseUrl)
self.loginPageUrl = "/sys/user-login.html"
self.mainPageUrl = "/sys/index.html"
self.driver.clearCookies() def login(self, userName, password):
self.openPage(self.loginPageUrl)
# self.driver.clearCookies()
self.driver.implicitlyWait(5)
self.driver.type("account", userName)
self.driver.type("password", password)
self.driver.click("submit") def getMainPage(self):
return self.baseUrl + self.mainPageUrl

Tests Case 类

import unittest
from time import sleep from ranzhiWeekend.automate_driver import AutomateDriver
from ranzhiWeekend.ranzhi_sub_login_page import RanzhiSubLoginPage """
1. 导入 unittest
2. 继承 unittest.TestCase
3. 写用例 方法以 test 开头
4. 考虑使用 setUp() 和 tearDown()
""" class RanzhiTests(unittest.TestCase):
def setUp(self):
"""
开始每个测试前的准备事项
:return:
"""
self.autoDriver = AutomateDriver()
self.baseUrl = "http://localhost:808/ranzhi/www" def tearDown(self):
"""
结束每个测试后的清理工作
:return:
"""
self.autoDriver.quitBrowser() def test_ranzhi_login(self):
"""
测试用例:测试然之登录
:return:
"""
# 新建然之的页面对象
loginPage = RanzhiSubLoginPage(self.autoDriver, self.baseUrl) # 利用然之的页面对象进行登录
loginPage.login("admin", "admin")
sleep(2)
# 断言 是否登录成功
self.assertEqual(loginPage.getMainPage(), self.autoDriver.getUrl(), u"登录失败")

Tests Runner类

import smtplib
import unittest
from email.header import Header
from email.mime.text import MIMEText from ranzhiWeekend import HTMLTestRunner
from ranzhiWeekend.ranzhi_tests_0605 import RanzhiTests class RanzhiTestRunner(): def runTest(self):
"""
运行测试用例
:return:
""" # 声明一个测试套件
suite = unittest.TestSuite()
# 添加测试用例到测试套件
suite.addTest(RanzhiTests("test_ranzhi_login")) # 创建一个新的测试结果文件
buf = open("./result.html", "wb") # 声明测试运行的对象
runner = HTMLTestRunner.HTMLTestRunner(stream=buf,
title="Ranzhi Test Result",
description="Test Case Run Result")
# 运行测试,并且将结果生成为HTML
runner.run(suite) # 关闭文件输出
buf.close() def sendEmail(self, targetEmail):
"""
发送邮件
:param targetEmail:
:return:
""" # 打开测试报告结果
f = open("./result.html", "rb") # 将测试结果放到邮件的主体中
mailBody = f.read()
# 关闭测试结果的文件
f.close() # 声明一个邮件对象,用刚刚得到的邮件主体
msg = MIMEText(mailBody, "html", "utf-8")
# 设置邮件的主题
msg["subject"] = Header("Automation Test Result", "utf-8") # 创建一个SMTP服务对象
# simple message transfer protocol
# 简单的消息转移协议
smtpMail = smtplib.SMTP() # 连接SMTP的服务器
smtpMail.connect(“***.******.com") # 登录SMTP的服务器
smtpMail.login(“*******@*****.com", “*********") # 使用SMTP的服务器发送邮件
smtpMail.sendmail(“*******@********.com", targetEmail, msg.as_string()) # 退出SMTP对象
smtpMail.quit()

main函数入口

if __name__ == "__main__":
# 实例化一个runner
runner = RanzhiTestRunner() # 执行测试
runner.runTest() # 发送测试结果
runner.sendEmail(“********@******.com")

Selenium+Python :WebDriver设计模式( Page Object )的更多相关文章

  1. 【Selenium+Python Webdriver】报错之:TypeError: user_login() missing 1 required positional argument: 'self'

    先贴一下源码: base.py文件如下: from selenium import webdriver class Page(object): ''' 页面基础类,用于所有页面的继承 ''' rb_u ...

  2. How to set Selenium Python WebDriver default timeout?

    Trying to find a good way to set a maximum time limit for command execution latency in Selenium Pyth ...

  3. selenium 的页面对象模型Page Object

    页面对象模型page object model是selenium中的一种脚本设计模式,它能将页面元素封装起来,与业务操作分隔开, 在页面变化改变时,无需去修改业务逻辑代码,提高脚本维护的效率. 1.p ...

  4. Selenium+Python+Webdriver:保存截图到指定文件夹

    保存图片到指定文件夹: from selenium import webdriverfrom pathlib import Pathfrom time import sleepdriver = web ...

  5. 【selenium+Python WebDriver API】之复选框顺序正选和顺序反选

    from selenium import webdriver from selenium.webdriver.common.by import By import os,time driver = w ...

  6. 【转载】【selenium+Python WebDriver】之元素定位

    总结: 感谢: “煜妃”<Selenuim+Python之元素定位总结及实例说明> “Huilaojia123”<selenium WebDriver定位元素学习总结> “上海 ...

  7. selenium +python webdriver运行时报错cannot find Chrome binary

    今日在公司电脑运行自动化测试脚本,出现cannot find Chrome binary报错 百思不得其解,排错后发现应该是电脑以前有配置driver文件路径,driver所在文件路径已变更,现pyt ...

  8. 【转】【selenium+Python WebDriver】之元素定位不到解决办法

    感谢: 煜妃的<Python+Selenium定位不到元素常见原因及解决办法(报:NoSuchElementException)> ClassName定位报错问题:<[Python] ...

  9. 自动化设计模式Page Object

    https://blog.csdn.net/qq_37546891/article/details/79052054#t1

随机推荐

  1. C语言基础之变量、作用域

    1.变量的定义 变量类型 变量名; int score; 2.变量的赋值 score = 100; score = a; score = b = 100; 3.变量的输出 int a = 200; p ...

  2. 通过CVE-2017-17215学习路由器漏洞分析,从入坑到放弃

    1.基本信息: 2017/11/27,Check Point 软件技术部门报告了一个华为 HG532 产品的远程命令执行漏洞(CVE-2017-17215),Mirai的升级版变种中已经使用该漏洞.看 ...

  3. Git 历险记(三)——创建一个自己的本地仓库

    如果我们要把一个项目加入到Git的版本管理中,可以在项目所在的目录用git init命令建立一个空的本地仓库,然后再用git add命令把它们都加入到Git本地仓库的暂存区(stage or inde ...

  4. Java三大器之监听器(Listener)的工作原理和代码演示

    现在来说说Servlet的监听器Listener,它是实现了javax.servlet.ServletContextListener 接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次, ...

  5. mysql binlog 使用

    用于数据恢复的binlog 前提条件 1.定时mysqldumps全备数据库 2.开启binlog增量备份 情景:手滑误操作删表操作 立刻 mysql>flush logs;  #开启一个新的b ...

  6. 在HTML页面中实现一个简单的Tab

    参考:http://blog.sina.com.cn/s/blog_6cccb1630100m23i.html HTML页面代码如下: <!DOCTYPE html PUBLIC "- ...

  7. 【转】WEB开发三层架构概述

    关于 三层架构(3-tier application) 通常意义上的三层架构就是将整个业务应用划分为:表现层(UI).业务逻辑层(BLL).数据访问层(DAL).区分层次的目的即为了“高内聚,低耦合” ...

  8. 使用UI Automation实现自动化测试--2

    1. 首先建立一个待测试的winform程序,即UI Automation的服务端. 下面是button事件处理程序. private void CalculateButton_Click(objec ...

  9. JavaScript创建块级作用域

    1.JavaScript创建块级作用域 (1)方法一:ES6 (2)方法二:闭包 2.示例 <!DOCTYPE html> <html lang="zh"> ...

  10. C中的C文件与h文件辨析

    简单的说其实要理解C文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程:       1.预处理阶段 2.词法与语法分析阶段 .编译阶段,首先编译成纯 ...