前言

经过前面的实战我们已经编写了几个测试用例,下面我们要用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. transmission protocol

    传输层主要定义了主机应用程序间端到端的连通性,它一般包含四项基本功能 . 将应用层发往网络层的数据分段或将网络层发往应用层的数据段合并 建立端到端的链接,主要是建立逻辑连接以传送数据流 将数据段从一台 ...

  2. GitLab的安装及使用

    Gitlab环境部署 安装依赖包.   sudo yum install -y curl policycoreutils-python openssh-server 设置SSH开机自启动并启动SSH服 ...

  3. .NET的并发编程(TPL编程)是什么?

    写在前面 优秀软件的一个关键特征就是具有并发性.过去的几十年,我们可以进行并发编程,但是难度很大.以前,并发性软件的编写.调试和维护都很难,这导致很多开发人员为图省事放弃了并发编程.新版 .NET 中 ...

  4. uber_go_guide解析(一)

    前言 实力有限,guide啃着好费劲 原地址https://github.com/xxjwxc/uber_go_guide_cn 加我自己的体会和补充 基于Golang 1.14 正文 Interfa ...

  5. 了解一下RPC,为何诞生RPC,和HTTP有什么不同?

    了解一下RPC,为何诞生RPC,和HTTP有什么不同? 开篇提问 什么是RPC? 为什么需要RPC,用来解决什么问题? RPC与HTTP有什么不同? 你知道几种RPC? 认识RPC RPC:Remot ...

  6. SpringBoot配置文件(1)

    配置文件 1.配置文件 SpringBoot使用一个全局的配置文件 application.properties application.yml 配置文件名是固定的: 他的作用是修改SpringBoo ...

  7. 基于 MapReduce 的单词计数(Word Count)的实现

    完整代码: // 导入必要的包 import java.io.IOException; import java.util.StringTokenizer; import org.apache.hado ...

  8. 改进你的c#代码的5个技巧(四)

    像每一篇文章一样,我会重复几行.我在我的Core i3 CPU.4GB主内存和Windows 7平台上测试了以下代码.如果你在不同的硬件配置或使用不同的平台,那么你的输出可能会随着我的输出屏幕而变化, ...

  9. mysql—group_concat函数

    MySQL中的group_concat函数的使用方法,比如select group_concat(name) . 完整的语法如下: group_concat([DISTINCT] 要连接的字段 [Or ...

  10. CyNix-lxd提权

    0x01 信息收集 nmap -p- -T5 192.168.43.155扫描开放端口 nmap -sV -p 80,6688 -A 192.168.43.155 -oA cynix扫描指定端口 go ...