前言

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

    ---已更新至3.0.3---经过近期的努力,wdCP_v3正式版终于可以和大家见面了v3功能预览1 底层完全重新架构,更安全稳定,省资源更高效2 安装更简单,快速与方便3 功能更强大和易扩展,且完美 ...

  2. BPOS关于“相邻库存查询”的调整

    "相邻库存查询"的应用场景:主要是实现门店间,相互查看商品库存状况,但出于公司对门店的查看权限控制要求,不能一次性查看到相关店铺的所有库存,所以产生了"相邻库存查询&qu ...

  3. java进阶(29)--HashMap集合

    一.HashMap简介 1.HashMap底层是哈希表结构,类似字典,初始化如下: 2.哈希表结构: 是一个数组+单向链表的结构体 数组:查询效率较高,随机增删效率很低 单向链表:在随机增删方面效率较 ...

  4. Java微服务 vs Go微服务,究竟谁更强!?

    前言 Java微服务能像Go微服务一样快吗? 这是我最近一直在思索地一个问题. 去年8月份的the Oracle Groundbreakers Tour 2020 LATAM大会上,Mark Nels ...

  5. SpringCloud Alibaba Nacos服务注册与配置管理

    Nacos SpringCloud Alibaba Nacos是一个狗抑郁构建云原生应用的动态服务发现.配置管理和服务管理平台. Nacos:Dynamic Naming and Configurat ...

  6. .NET 5网络操作的改进

    随着.net 5在11月的发布,现在是谈论网络栈中许多改进的好时机.这包括对HTTP.套接字.与网络相关的安全性和其他网络通信的改进.在这篇文章中,我将重点介绍一些版本中更有影响力和更有趣的变化. H ...

  7. mysql中更改字段属性实际上都做了哪些操作

     mysql> set profiling=1; Query OK, 0 rows affected (0.00 sec) mysql> alter table test modify n ...

  8. 目前用下来最溜的MacOS微信多开工具!

    一个生活微信,一个工作微信是很多上班族的基本配置. 但由于微信客户端在PC端上只能打开一个,这使得在上班时候就非常不便,一个号在PC端上登录,一个在手机上使用,但是上班时候又不能一直看手机,不然老板还 ...

  9. SwiftUI 中一些和响应式状态有关的属性包装器的用途

    SwiftUI 借鉴了 React 等 UI 框架的概念,通过 state 的变化,对 View 进行响应式的渲染.主要通过 @State, @StateObject, @ObservedObject ...

  10. django使用缓存之drf-extensions

    使用方法:1.直接添加装饰器@cache_response该装饰器装饰的方法有两个要求: 它必须是继承了rest_framework.views.APIView的类的方法 它必须返回rest_fram ...