前言

经过前面的实战我们已经编写了几个测试用例,下面我们要用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设计模式的更多相关文章

  1. UI自动化实战进阶后续

    前言 最近几天因为回老家的缘故,暂时没空学习和记录,好不容易抽空那就赶紧开始后面的实战. 前面我们已经基本完成了测试的框架,并且也有了PO设计模式,后面我们还缺少什么呢?做为自动化测试最主要的测试报告 ...

  2. 说说UI自动化中的PO模式

    PO模式,全称PageObject模式,即页面对象模式.将页面定位与业务操作分离. po模式有以下几个优点: 1.易读性好 2.扩展性高 3.复用性强 4.维护性好 5.代码冗余率低 了解了po模式及 ...

  3. UI自动化学习笔记- PO模型介绍和使用

    一.PO模型 1.PO介绍:page(页面) object(对象) 在自动化中,Selenium 自动化测试中有一个名字经常被提及 PageObject (思想与面向对象的特征相同),通常PO 模型可 ...

  4. python UI自动化实战记录十一: 总结

    首先说说为什么想起来用自动化脚本来实现该项目的自动化. 工作还是以手工测试为主,业务驱动型的项目大概就是这样,业务不停地变,不断的迭代. 自动化测试实施的先决条件: 一 得有时间. 如果有时间大部分的 ...

  5. python UI自动化实战记录五:测试页面2 pageobject

    该部分记录测试页面2-StrategyPage,所有页面2上的元素定位.操作.获取属性等方法都写在该类中. 1 页面2继承自BasePage: 2 页面2第一部分写的是所有的定位器 3 页面2第二部分 ...

  6. python UI自动化实战记录三:pageobject-基类

    脚本思路: 使用pageobject模式,写一个basepage基类,所有页面的通用方法封装到基类中.比如打开页面,关闭页面,等待时间,鼠标移到元素上,获取单个元素,获取一组元素,获取元素的子元素,截 ...

  7. python UI自动化实战记录二:请求接口数据并提取数据

    该部分记录如何获取预期结果-接口响应数据,分成两步: 1 获取数据源接口数据 2 提取后续页面对比中要用到的数据 并且为了便于后续调用,将接口相关的都封装到ProjectApi类中. 新建python ...

  8. python UI自动化实战记录一:测试需求与测试思路

    测试需求: 项目包含两个数据展示页面,数据均来自于四个数据源接口. 测试操作步骤: 选择5个大类型中的一个,每个大类型下有3个子类型,选择任一子类型,页面数据更新.需验证页面上的数据与数据源接口数据一 ...

  9. python UI自动化实战记录十:执行测试及测试报告

    使用简单的unittest.TextTestRunner. 思路: 1 在report目录下创建当日测试报告目录 20190113 2 创建测试报告文件 f = 时间戳.txt 3 加载测试集,运行测 ...

随机推荐

  1. Redis性能篇(二)CPU核和NUMA架构的影响

    Redis被广泛使用的一个很重要的原因是它的高性能.因此我们必要要重视所有可能影响Redis性能的因素.机制以及应对方案.影响Redis性能的五大方面的潜在因素,分别是: Redis内部的阻塞式操作 ...

  2. 数据库(MySQL)最新版8.0安装教程,小白都能学会安装

    首先打开数据库官网 接下来点击不用登录注册 下载好软件,双击运行程序(中间不需要点击其他,等他运行好) 点击安装服务端 ,然后点击下一步 选择自己安装目录(一定要牢记)这里我选择默认目录,点击下一步 ...

  3. windows7 错误0xc00000ba;无法进入系统;

    事件背景:电脑windows7 错误0xc00000ba无法进系统:无法进入安全模式:无法进入最后一次正确配置: 事件处理:提示系统文件丢失,注册表异常:知乎有人提及更换WS2_32.DLL; 使用P ...

  4. LeetCode 面试题16.18.模式匹配

    模式匹配 题目: 你有两个字符串,即pattern和value. pattern字符串由字母"a"和"b"组成,用于描述字符串中的模式.例如,字符串" ...

  5. 【递归】P2386放苹果

    题目相关 题目描述 把 m个同样的苹果放在 n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法.(5,1,1 和 1,1,5 是同一种方法) 输入格式 第一行是测试数据的数目 t,以下每行 ...

  6. LeetCode876 链表的中间结点

    给定一个带有头结点 head 的非空单链表,返回链表的中间结点. 如果有两个中间结点,则返回第二个中间结点. 示例 1: 输入:[1,2,3,4,5] 输出:此列表中的结点 3 (序列化形式:[3,4 ...

  7. 【Nginx】使用keepalive和nginx搭载高可用

    首先介绍一下Keepalived,它是一个高性能的服务器高可用或热备解决方案,Keepalived主要来防止服务器单点故障的发生问题,可以通过其与Nginx的配合实现web服务端的高可用. Keepa ...

  8. oracle释放空间到OS

    测试: 建表空间 CREATE TABLESPACE TESTTBS DATAFILE '/oradata01/dfhdb/testtbs01.dbf' SIZE 2G; 在表空间上建表 CREATE ...

  9. three.js cannon.js物理引擎之约束

    今天郭先生继续说cannon.js,主演内容就是点对点约束和2D坐标转3D坐标.仍然以一个案例为例,场景由一个地面.若干网格组成的约束体和一些拥有初速度的球体组成,如下图.线案例请点击博客原文. 下面 ...

  10. 图解 | 原来这就是TCP

    你是一台电脑,你的名字叫 A 经过<图解 | 原来这就是网络>这篇文章中的一番折腾,只要你知道另一位伙伴 B 的 IP 地址,且你们之间的网络是通的,无论多远,你都可以将一个数据包发送给你 ...