Selenium Web自动化测试——基于unittest框架的PO设计模式
引言
前面一直在讲接口自动化测试框架与案例分享,很少讲Selenium这个Web自动化测试神器。它主要用来做UI自动化测试,大家都知道UI自动化测试成本相当高,一般的Web自动化测试我是一直不建议做的。
虽然不推荐,但是这里有一个设计思想是不错的——PO设计模式。
PO设计模式
PO设计模式,英文名称:Page Object Model。PO设计模式是Selenium自动化测试中最佳的设计方式之一。相比传统设计中:页面定位元素→输入数据→操作元素→断言结果,会有以下问题:
1、易用性差:杂乱无章的定位元素方法,例如:find_element;
2、扩展性不好:用例孤立,无法扩展;
3、复用性差:无公共方法,很难服用;
4、可维护性差:一旦元素变化或测试步骤变化,需要维护大量代码和用例;
针对上面一些弊端,做了一些优化:
POM设计模式,将页面定位和业务操作分开,将元素定位和测试方法分离,从而提高代码的维护性。而传统的POM是元素定位和测试方法放在一起,如下图:
这样做的优势:
1、页面元素定位和业务操作方法分离,使得代码更加清晰,减少冗余代码;
2、测试方法单独抽离,这样提高用例的可读性;
3、针对ui变化频繁的项目和测试步骤的变化,提高了测试用例的维护性;
一条测试用例可能需要多个步骤操作元素,将每一个步骤单独封装成一个方法,在执行测试用例时调用封装好的方法进行操作。PO模式可以把一个页面分为三个层级,对象库层、操作层、业务层。
对象库层:封装定位元素的方法。
操作层:封装对元素的操作。
业务层:将一个或多个操作组合起来完成一个业务功能。
PO设计模式核心组件
画一个操作如下:
PO的核心要素:
- 在 PO 模式中抽离封装集成一个 BasePage 类,该基类应该拥有一个只实现 webdriver 实例的属性
- 每一个page 都继承BasePage,通过 driver 来管理 page 中元素,将 page 中的操作封装成一个个方法
- TestCase 继承 unittest.TestCase类,并依赖page类,从而实现相应的测试步骤
首先抽象封装一个BasePage类,这个基类拥有Webdriver实例的属性,将页面分成一个个Page,每一个Page继承基类BasePage,可以通过driver来管理每一个Page中的元素,
在Page中将定位元素的操作封装成一个一个方法。TestCase继承unittest里面的TestCase类,并且依赖Page类,进行测试步骤的执行工作。
这样以来,页面元素一旦变化,只需要维护每一个Page中的方法,测试流程发生变化,只需要维护TestCase即可。
核心组件:
BasePage.py模块:
class BasePage(object):
def __init__(self,driver):
self.driver = driver
pass
Page页面模块:
from SeleniumProject.PO.BasePage import BasePage
class LoginBase(BasePage):
# 定位元素,括号中是通过find_element来获取元素的属性
uname = ()
pwd = ()
def set_uname(self,uname):
name =self.driver.find_element(*LoginBase.uname)
name.send_keys("用户名")
def set_pwd(self,pwd):
password = self.driver.find_element(*LoginBase.pwd)
password.send_keys("密码")
pass
TestCase用例模块:
from unittest import TestCase
import unittest
from selenium import webdriver
class Test_Login(TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get("https://cn.bing.com/")
# 测试步骤
def test_Login(self):
self.driver.get(self.base_url)
pass
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()
PO模式简单实例
现在根据PO设计模式思想,简单实现一个需求:
打开浏览器,输入url:https://www.baidu.com,在百度搜索文本框内输入关键字:selenium,然后单击:百度一下,进行搜索。
根据需求,设计步骤如下:
BasePage:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
# @Time : 2020/11/22 0022 16:07
# @Author : liudinglong
# @File : basepage.py
# @Description:
# @Question:
'''
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class BasePage(object):
def __init__(self,driver,url):
"""
@param driver:
@param base_url:
"""
self.dr = driver
self.base_url = url
# 定义私有方法,类对象和子类可以访问
def _open(self,url):
self.dr.get(url)
self.dr.maximize_window()
# 定义open方法,调用_open方法
def open(self):
self._open(self.base_url)
def find_emelemt(self,*loc):
try:
WebDriverWait(self.dr,10).until(EC.visibility_of_all_elements_located(loc))
return self.dr.find_element(*loc)
except:
print("页面中没有%s元素"%(self.loc))
# 定义script()方法,用于执行JS脚本,比方上上传文件啥的
def script(self, src):
self.dr.excute_script(src)
# 定义页面跳转方法,比方说有的页面有frame嵌套
def switch_frame(self, loc):
return self.dr.switch_to_frame(loc)
# 重新定义send_keys()方法,为了保证搜索按钮是否存在,还有有的输入框中默认有值,要清空
def send_keys(self, loc, value, clear_first=True, click_first=True):
try:
# getattr方法相当于实现了self.loc
loc = getattr(self, "_%s" % loc)
# 是否存在搜索按钮
if click_first:
self.find_emelemt(*loc).click()
# 清空搜索框中的值,并输入需要搜索的值
if clear_first:
self.find_emelemt(*loc).clear()
self.find_emelemt(*loc).send_keys(value)
except:
print("页面上未找到%s元素" % (self.loc))
SearchPage:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
# @Time : 2020/11/22 0022 18:38
# @Author : liudinglong
# @File : SearchPage.py
# @Description:
# @Question:
'''
from selenium.webdriver.common.by import By
from Common.basepage import BasePage
class SearchPage(BasePage):
# 定位元素
search_loc = (By.ID,"kw") #搜索框
btn_loc = (By.ID,"su") #搜索按钮
# 重写父类的open()方法
def open(self):
self._open(self.base_url)
def search_content(self,content):
# 调用父类的find_emelemt,然后将本类的参数传入
content1 = self.find_emelemt(*self.search_loc)
content1.send_keys(content)
def btn_click(self):
btn1 = self.find_emelemt(*self.btn_loc)
btn1.click()
TestCase:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
# @Time : 2020/11/22 0022 18:40
# @Author : liudinglong
# @File : test_001.py
# @Description:
# @Question:
'''
from unittest import TestCase
import unittest
from selenium import webdriver
from time import sleep
from Page.searchpage import SearchPage
class CaseRun(TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.url = "https://www.baidu.com"
sleep(3)
self.content = "selenium"
# 测试步骤
def test_search(self):
bing_page = SearchPage(self.driver,self.url)
bing_page.open()
bing_page.search_content(self.content)
try:
bing_page.btn_click()
sleep(3)
print("查询成功")
except Exception as Error:
print(Error)
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()
三个核心组件完成,项目结构如下:
运行测试,生成报告如下:
C:\Users\Administrator\Desktop\Demo_PO
C:\Users\Administrator\Desktop\Demo_PO\Report
.
Time Elapsed: 0:00:13.370322
Process finished with exit code 0
总结
这个Demo很简单,主要意图是帮助理解PO设计模式的思想,如果需要代码,可以加入QQ群:696400122 ,我们这里主要是进行自动化测试和测试开发学习与沟通交流,如果其他意图请绕行~
相关文章
- 做自动化测试选择Python还是Java?
- Selenium的Web自动化测试(送源码)
- 6.Redis数据库性能测试及优化配置
- 自动化测试哪家强?Apipost用实力来告诉你。
- 海量订单系统微服务开发:订单接口管理后台微服务开发、集成测试
- 开源 web ide_强大的开源Web编辑器(IDE)[通俗易懂]
- 值得收藏的几款渗透测试常用的脚本
- 【架构师(第四十三篇)】 服务端开发之单元测试和接口测试
- selenium最大化浏览器-Web UI自动化测试之Selenium工具篇
- 在芯片上培养脑细胞,还能用来测试新药,LLNL实验室开发出3D「芯片大脑」
- 极速搭建:使用Linux快速搭建Web服务器(linux搭建web服务器)
- 服务器快速安装Linux下的Web服务器(linux安装web)
- 给你的Web服务加上Linux强化保障(web服务linux)
- Linux为Web服务器带来的福音(linux做web服务器)
- 应用Linux服务器:打开Web应用的大门(linux服务器web)
- web服务器高可用性架构:两台Linux搭建Web服务器(两台linux挂载)
- 器重启Web服务器:Linux下的快速操作(linux重启web服务)
- Linux轻松搭建个人Web服务器(linux架设web服务器)
- 服务快速部署Linux服务器,轻松架设Web服务(linux部署web)
- asp.net的web服务MSSQL检测ASP.NET的Web服务——利用它构建更棒的站点(mssql检测基于)
- MySQL 测试之旅:体验革新测试工具(mysql测试工具)
- 基于C语言技术的Web应用程序开发与MySQL集成(c web mysql)
- 在Web服务器上使用Redis进行高性能处理(web服务器 redis)
- 使用Redis提高Web性能的技巧(web中redis用法)
- MySQL数据库不支持断言语句限制测试与调试(mysql不支持断言)
- 松下 HOSPI 机器人消费场景首测试 在成田机场做服务生