UI自动化实战进阶PO设计模式
前言
经过前面的实战我们已经编写了几个测试用例,下面我们要用PO设计模式来调整我们的代码,让页面元素和测试业务进行分离,这样看起来直观而且后期的维护也方便。
python有一个第三方的PO设计的库,既然已经有了轮子,我们就可以直接造车了。
安装
首先我们来安装
pip install page_objects
Code
页面封装
#pages.py
from page_objects import PageElement, PageObject
class Blog_Login_Page(PageObject):
'''登陆页面'''
login_user = PageElement(id_ = 'user_login')
login_passwd = PageElement(id_ = 'user_pass')
login_jizhu = PageElement(id_ = 'rememberme')
login_button = PageElement(id_ = 'wp-submit')
测试用例
#test_case.py
import unittest
from selenium import webdriver
from pages import Blog_Login_Page
username = passwd = 'pyse_24'
url = 'http://139.199.192.100:8000/wp-login.php'
class Test_Blog(unittest.TestCase):
'''博客测试用例前置和后置'''
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get(url)
self.driver.implicitly_wait(10)
self.driver.maximize_window()
blog_home = Blog_Login_Page(self.driver)
blog_home.login_user.send_keys(username)
blog_home.login_passwd.send_keys(passwd)
blog_home.login_jizhu.click()
blog_home.login_button.click()
def tearDown(self):
self.driver.quit()
class Test_login(Test_Blog):
'''博客登陆测试用例'''
def test_login_success(self):
title_url = self.driver.current_url
assert 'wp-admin' in title_url, '登陆不成功或者断言错误'
if __name__ == '__main__':
unittest.main()
下面我们在把之前的其他的用例按照这个模式进行整合
首先继续进行封装,如果后面的页面越来越多,我们就必须封装多个,并进行分类,首先创建一个pages的文件夹,然后将之前的封装文件改名成blog_login_page.py,然后创建新的封装页面文件
这里增加了目录以及修改文件名称,导包时可能会有点问题了,后面我的代码会有解决办法
#blog_write_page.py
from page_objects import PageElement, PageObject ,MultiPageElement
class Blog_Post_Page(PageObject):
home_post = PageElement(css = '#menu-posts > a >.wp-menu-name')
write_post = PageElement(css = '.page-title-action')
write_post_alert = PageElement(css = 'div.components-modal__header > button > svg')
write_post_title = PageElement(css = '#post-title-0')
write_post_text = PageElement(css = '#post-content-0')
write_post_release = PageElement(css = 'button.components-button.editor-post-publish-panel__toggle.editor-post-publish-button__button.is-primary')
write_post_release_button = PageElement(css = 'div.editor-post-publish-panel__header-publish-button > button')
post_release_status = PageElement(css = 'div.components-panel__body.post-publish-panel__postpublish-header.is-opened')
继续封装删除博客的页面
#blog_delete_page.py
from page_objects import PageElement, PageObject ,MultiPageElement
class Blog_Post_Page(PageObject):
home_post = PageElement(css = '#menu-posts > a >.wp-menu-name')
delect_post_locat = PageElement (css = 'td.author.column-author > a')
delect_post_button = MultiPageElement (css = 'td.title.column-title.has-row-actions.column-primary.page-title > div.row-actions > span.trash > a')
页面封装好了,开始写测试用例了,既然页面有了分类,那么我们的测试用例也应该进行分类
首先登陆用例
#test_login_blog.py
from pages.blog_login_page import Blog_Login_Page
import unittest
from selenium import webdriver
import os
import sys
path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(path)
username = passwd = 'pyse_24'
url = 'http://139.199.192.100:8000/wp-login.php'
class Test_Blog(unittest.TestCase):
'''博客测试用例前置和后置'''
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get(url)
self.driver.implicitly_wait(10)
self.driver.maximize_window()
blog_home = Blog_Login_Page(self.driver)
blog_home.login_user.send_keys(username)
blog_home.login_passwd.send_keys(passwd)
blog_home.login_jizhu.click()
blog_home.login_button.click()
def tearDown(self):
self.driver.quit()
class Test_login(Test_Blog):
'''博客登陆测试用例'''
def test_login_success(self):
title_url = self.driver.current_url
assert 'wp-admin' in title_url, '登陆不成功或者断言错误'
if __name__ == '__main__':
unittest.main()
写文章用例
#test_write_blog.py
import unittest
import uuid
import os,sys
path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(path)
from pages.blog_write_page import Blog_Post_Page
from test_login_blog import Test_Blog
uid = str(uuid.uuid1())
suid = ''.join(uid.split('-'))
class Test_write_blog(Test_Blog):
'''写博客测试用例'''
def test_write_blog_success(self):
write_blog = Blog_Post_Page(self.driver)
write_blog.home_post.click()
write_blog.write_post.click()
write_blog.write_post_alert.click()
write_blog.write_post_title.send_keys(suid)
write_blog.write_post_text.send_keys(suid)
write_blog.write_post_release.click()
write_blog.write_post_release_button.click()
blog_status = write_blog.post_release_status
assert '已被发布' in blog_status.text, '文章未发布或断言错误'
if __name__ == '__main__':
unittest.main()
删除文章用例
#test_delete_blog.py
import unittest
from time import sleep
from selenium.webdriver.common.action_chains import ActionChains
import os,sys
path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(path)
from pages.blog_delete_page import Blog_Post_Page
from test_login_blog import Test_Blog
class Test_delete_blog(Test_Blog):
'''删除博客测试用例'''
def test_delete_blog_success(self):
delete_blog = Blog_Post_Page(self.driver)
delete_blog.home_post.click()
mouse = delete_blog.delect_post_locat
ActionChains(self.driver).move_to_element(mouse).perform()
blog_title_old = delete_blog.delect_post_button
bt = blog_title_old[0].text
blog_title_old[0].click()
blog_title_new = delete_blog.delect_post_button
bt2 = blog_title_new[0].text
assert bt != bt2, '文章未删除成功'
if __name__ == '__main__':
unittest.main()
这样每个用例都是独立的,当然我这里调用了登陆用例的方法,这么写并不推荐,建议还是将登陆用例独立出来,然后另外封装一个成功登陆方法让其他用例调用,具体方法我就不实现了,也算比较简单了。
既然用例独立了,如果我想一次运行多个用例呢?那么我们需要添加一个测试套件,将需要执行的多个测试用例添加进来,如果用例过多添加比较麻烦怎么办?那就执行整个目录下的用例,其中如果有不需要执行的可以使用skip进行跳过,这样灵活的组合基本能满足所有的场景了。
首先创建main目录,再目录中进行执行方法的分类
#run_test_class.py
import unittest
import os,sys
path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(path)
print(path)
print(sys.path)
from test_case.test_login_blog import Test_login
if __name__ == '__main__':
# 根据给定的测试类,获取其中所有以test开头的测试方法,并返回一个测试套件
suite1 = unittest.TestLoader().loadTestsFromTestCase(Test_login)
# 将多个测试类加载到测试套件中
suite = unittest.TestSuite([suite1])
# 设置verbosity = 2,可以打印出更详细的执行信息
unittest.TextTestRunner(verbosity=2).run(suite)
这里我遇到一个问题,导包的时候尝试各种方法一直报错,后面无意中执行发现再其他的目录也存在相同的test_case目录名称并且也添加进了系统环境,所以一直查不到其他test_case目录下有包.
这里主要是命名不规范导致的,希望大家都能规范编码,不然一个小问题可能会排查半天
修改目录名称并且和导包的名称
#run_test_class.py
import unittest
import os,sys
path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(path)
print(path)
print(sys.path)
from test_blog_case.test_login_blog import Test_login
if __name__ == '__main__':
# 根据给定的测试类,获取其中所有以test开头的测试方法,并返回一个测试套件
suite1 = unittest.TestLoader().loadTestsFromTestCase(Test_login)
# 将多个测试类加载到测试套件中
suite = unittest.TestSuite([suite1])
# 设置verbosity = 2,可以打印出更详细的执行信息
unittest.TextTestRunner(verbosity=2).run(suite)
执行成功,如果需要执行那几个测试类直接导入再添加到套件里面进行执行即可
下面我们来写执行整个目录的方法
#run_test_discover.py
import os
import unittest
if __name__ == '__main__':
path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'test_blog_case')
suite = unittest.defaultTestLoader.discover(path, pattern='test*.py')
runner = unittest.TextTestRunner()
runner.run(suite)
再结合skip跳过用例的方法,再需要跳过的测试类或者测试方法添加下面的方法
@unittest.skip(reason):强制跳过,不需要判断条件。reason是跳过原因的描述必须填写。
#test_delete_blog.py
import unittest
from time import sleep
from selenium.webdriver.common.action_chains import ActionChains
import os,sys
path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(path)
from pages.blog_delete_page import Blog_Post_Page
from test_login_blog import Test_Blog
@unittest.skip('跳过删除博客用例')
class Test_delete_blog(Test_Blog):
'''删除博客测试用例'''
def test_delete_blog_success(self):
delete_blog = Blog_Post_Page(self.driver)
delete_blog.home_post.click()
mouse = delete_blog.delect_post_locat
ActionChains(self.driver).move_to_element(mouse).perform()
blog_title_old = delete_blog.delect_post_button
bt = blog_title_old[0].text
blog_title_old[0].click()
blog_title_new = delete_blog.delect_post_button
bt2 = blog_title_new[0].text
assert bt != bt2, '文章未删除成功'
if __name__ == '__main__':
unittest.main()
第一个执行的是删除博客用例并出现了s跳过的标记,为什么先执行删除博客这里需要了解unittest的执行顺序,具体知识不在此文章范围内,需要了解的自行百度。
UI自动化实战进阶PO设计模式的更多相关文章
- UI自动化实战进阶后续
前言 最近几天因为回老家的缘故,暂时没空学习和记录,好不容易抽空那就赶紧开始后面的实战. 前面我们已经基本完成了测试的框架,并且也有了PO设计模式,后面我们还缺少什么呢?做为自动化测试最主要的测试报告 ...
- 说说UI自动化中的PO模式
PO模式,全称PageObject模式,即页面对象模式.将页面定位与业务操作分离. po模式有以下几个优点: 1.易读性好 2.扩展性高 3.复用性强 4.维护性好 5.代码冗余率低 了解了po模式及 ...
- UI自动化学习笔记- PO模型介绍和使用
一.PO模型 1.PO介绍:page(页面) object(对象) 在自动化中,Selenium 自动化测试中有一个名字经常被提及 PageObject (思想与面向对象的特征相同),通常PO 模型可 ...
- python UI自动化实战记录十一: 总结
首先说说为什么想起来用自动化脚本来实现该项目的自动化. 工作还是以手工测试为主,业务驱动型的项目大概就是这样,业务不停地变,不断的迭代. 自动化测试实施的先决条件: 一 得有时间. 如果有时间大部分的 ...
- python UI自动化实战记录五:测试页面2 pageobject
该部分记录测试页面2-StrategyPage,所有页面2上的元素定位.操作.获取属性等方法都写在该类中. 1 页面2继承自BasePage: 2 页面2第一部分写的是所有的定位器 3 页面2第二部分 ...
- python UI自动化实战记录三:pageobject-基类
脚本思路: 使用pageobject模式,写一个basepage基类,所有页面的通用方法封装到基类中.比如打开页面,关闭页面,等待时间,鼠标移到元素上,获取单个元素,获取一组元素,获取元素的子元素,截 ...
- python UI自动化实战记录二:请求接口数据并提取数据
该部分记录如何获取预期结果-接口响应数据,分成两步: 1 获取数据源接口数据 2 提取后续页面对比中要用到的数据 并且为了便于后续调用,将接口相关的都封装到ProjectApi类中. 新建python ...
- python UI自动化实战记录一:测试需求与测试思路
测试需求: 项目包含两个数据展示页面,数据均来自于四个数据源接口. 测试操作步骤: 选择5个大类型中的一个,每个大类型下有3个子类型,选择任一子类型,页面数据更新.需验证页面上的数据与数据源接口数据一 ...
- python UI自动化实战记录十:执行测试及测试报告
使用简单的unittest.TextTestRunner. 思路: 1 在report目录下创建当日测试报告目录 20190113 2 创建测试报告文件 f = 时间戳.txt 3 加载测试集,运行测 ...
随机推荐
- TCP三次握手(通俗易懂)
一--导读 前不久中国和外国RPEC协议的签订,标志着东亚自贸区的建立成功.现在韩国和日本要做贸易.日本一直监听着韩国总统的一举一动,但他又不会主动.(服务器的监听状态)只是被动的等着韩国总统先开口. ...
- loj #6179. Pyh 的求和 莫比乌斯反演
题目描述 传送门 求 \(\sum\limits_{i=1}^n\sum\limits_{j=1}^m \varphi(ij)(mod\ 998244353)\) \(T\) 组询问 \(1 \leq ...
- SpringBoot整合Shiro完成验证码校验
SpringBoot整合Shiro完成验证码校验 上一篇:SpringBoot整合Shiro使用Redis作为缓存 首先编写生成验证码的工具类 package club.qy.datao.utils; ...
- java调用js代码
jdk8里使用脚本引擎调用js 1.定义一个js方法: function getRouteInfo(province){ //注意,参数不要带var..在java里执行会报错.. if (provin ...
- hugo建站 | 我的第一个博客网站
前言 博客地址 - https://billie52707.cn 1. 建博客的初衷? 2020那一年,八月的第一天,我还是像往常一样打开我的域名网站,本以为还是会像以前一样显示每日一图的界面,结果出 ...
- 通过JS逆向ProtoBuf 反反爬思路分享
前言 本文意在记录,在爬虫过程中,我首次遇到Protobuf时的一系列问题和解决问题的思路. 文章编写遵循当时工作的思路,优点:非常详细,缺点:文字冗长,描述不准确 protobuf用在前后端传输,在 ...
- misc刷题
前言:听说misc打得好,头发多不了 kali自带的字典: cd /usr/share/wordlists/ 字典网站:http://contest-2010.korelogic.com/wordli ...
- ABP vNext 实现租户Id自动赋值插入
背景 在使用ABP vNext过程中,因为我们的用户体系庞大,所以一直与其他业务同时开发,在开发其他业务模块时,我们一直存在着误区:认为ABP vNext 自动处理了数据新增时的租户Id(Tenant ...
- 彻底解决小程序无法触发SESSION问题
一.首先找到第一次发起网络请求的地址,将服务器返回set-cookie当全局变量存储起来 wx.request({ ...... success: function(res) { console.lo ...
- 数据库 | 001-MySQL梳理系列(一)
MySQL基本组成 SQL执行流程 Server 层主要包括连接器.查询缓存.分析器.优化器.执行器,包含了MySQL主要的很多核心功能,以及所有的内置函数.存储过程.触发器.视图等,其实就是所有跨存 ...