基于Python+Selenium+Unittest+PO设计模式

一、什么是PO设计模式(Page Object Model)
1、Page Object是一种设计模式,它主要体现在对界面交互细节的封装上,使测试用例更专注于业务的操作,从而提高测试用例的可维护性。

2、一般PO设计模式有三层

第一层:

对Selenium 进行二次封装,定义一个所有页面都继承的 BasePage ,
封装 Selenium 基本方法 例如:元素定位,元素等待,导航页面 ,
不需要全部封装,用到多少方法就封装多少方法。
第二层:

页面元素进行分离,每个元素只定位一次,隔离定位,如果页面改变,只需要改变相应的元素定位;
业务逻辑分离 或 操作元素动作分离
第三层:

使用单元测试框架对业务逻辑进行测试

二、为什么要使用PO设计模式
页面频繁变化,(页面html结构等变化)导致页面UI元素频繁变动,元素定位改变
传统线性自动化(面向过程开发),用例中需要反复的定位同一个元素
每当页面发生变化的时候,需要在用例中寻找变动的部分,工作量大,容易产生遗漏,不容易维护
三、PO设计模式的六大原则
公共方法代表页面提供的服务
不要暴露细节
不要在封装的框架中做断言
方法可以return到新打开的页面
不要对所有元素建模,仅对自己关注的元素建模
相同的行为会产生不同的结果,可以封装不同的结果
四、PO设计模式实例
以公司的统一登录作为项目例子,用PO设计模式实现登陆:

1、手工用例:

用例编号    标题    前置条件    操作步骤    预期结果    实际结果
T-001    登录成功    输入正确的用户名和密码    
1、打开统一登录页

2、输入用户名

3、输入密码

4、点击登录按钮

登录成功,正确跳转到应用系统界面    XXX
T-002    登录失败    输入错误的用户名    
1、打开统一登录页

2、输入用户名

3、输入密码

4、点击登录按钮

登录失败,正确提示用户名或密码不正确    XXX

2、用PO模式实现自动化用例

项目目录

Base.py
login_page.py
from Page import Base
 
# 创建LoginPage类继续BasePage类
class LoginPage(Base.BasePage):
    '''统一平台登录Page层,登录页面封装操作到的元素'''
    '''第二层:页面元素进行分离,每个元素只定位一次,操作元素动作分离'''
    # 定义url变量,供父类中的open()方法使用
    url ="https://test01....cn/#/login"
    # 用户名输入框定位
    def form_username(self,user_name):
        return self.by_id("name").send_keys(user_name) # 使用了父类的self.by_id()方法定位元素,简洁了不少
    # 密码输入框定位
    def form_password(self,pass_word):
        return self.by_id("password").send_keys(pass_word)
    # 登录按钮定位
    def button_login(self):
        return self.by_xpath("//*[text()='登录']").click()
test_login.py
from Page import login_page
import unittest
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.keys import Keys
from CommonMethod import LogUtil
 
logger = LogUtil.logs() # 调用封装的日志方法,将日志输出到控制台以及写入文件
 
class LoginCase(unittest.TestCase):
    '''第三层:用单元测试框架对业务逻辑进行测试'''
    '''使用LoginPage类及它所继承的父类中的方法'''
    @classmethod
    def setUpClass(cls):
        # 实例化webdriver,俗称:打开浏览器
        cls.driver = webdriver.Firefox(executable_path='E:\\UI test\\UnittestProject\\Driver\\geckodriver.exe')
        cls.driver.implicitly_wait(10)
    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()
    def test_login_success(self):
        page = login_page.LoginPage(self.driver) # 需要用到哪个Page类时,只需要将它传入浏览器驱动,就可以使用该类中提供的方法了
        page.open()
        page.form_username("XXX")
        page.form_password("123456")
        page.button_login()
        sleep(2)
        self.assertEqual(page.get_current_url(), "https://test01....cn/#/home")
        print("登录成功,用例执行结果通过,当前的url为"+ page.get_current_url())
        sleep(1)
    def test_login_fail(self):
        page = login_page.LoginPage(self.driver)
        page.open()
        page.form_username("XXX11")
        page.form_password("123456")
        page.button_login()
        self.assertNotEqual(page.get_current_url(), "https://test01....cn/#/home")
        print("登录失败,用例执行结果通过,当前的url为"+ page.get_current_url())
        page.form_username(Keys.CONTROL+'a') # 输入组合键Ctrl+a,全选输入框内容
        page.form_username(Keys.BACK_SPACE) # 删除键,删除选中的内容
        page.form_password(Keys.CONTROL + 'a')
        page.form_password(Keys.BACK_SPACE)
        sleep(1)
if __name__ == '__main__':
    unittest.main(verbosity=2)
执行结果

在test_login.py中有调用封装的日志方法,这里把封装的日志附上,在CommonMethod目录下的LogUtil.py

 LogUtil

 五、其他补充
1、相同的行为会产生不同的结果,可以封装不同的结果:在login_page针对【登录】按钮封装了2个方法

2、方法可以return到新打开的页面:在login_page针对【登录】按钮封装,封装了之后要return新页面或其他信息。test_login调用时命名变量来接收这个函数就行了,比如indexurl = page.button_login_success(),在后面断言可以用indexurl变量来跟预期的url断言

 # 登录失败封装
    def button_login_fail(self):
        self.by_xpath("//span[text()='登录']").click()
        toast = self.by_xpath("//p[text()='账号或密码错误!']").text
        return toast
 
    # 登录成功封装
    def button_login_success(self):
        self.by_xpath("//span[text()='登录']").click()
        sleep(2)
        windows = self.driver.window_handles# 获取打开的多个窗口句柄
        self.driver.switch_to.window(windows[-1])# 切换到当前最新打开的窗口
        indexurl = self.get_current_url()
        return indexurl

3、断言:可以通过url、页面标题、text来断言

'''断言跳转的地址,通过try except语句块来进行测试断言,在实际自动化测试脚本开发中,经常要用到处理异常'''
        try:
            self.assertEqual(indexurl,"https://qa-xxxt/add")
            print("点击创建,正确跳转到新页面" + indexurl)
        except AssertionError as msg:
            print("没有跳转到正确页面,当前跳转的地址为"+addurl+"\n报错信息如下"+format(msg))
            '''当断言失败时会抛出异常测试用例执行失败,输出提示信息后重新将异常抛出,即raise,
            若不重新抛出,用例则永远是显示执行成功的,因为它把异常处理掉了'''
            raise msg
  try:
            self.assertEqual(toast, "账号或密码错误!")
            print("登录失败用例场景执行通过,正确弹出提示信息为:" + toast)
        except AssertionError as msg:
            print("错误提示语与预期结果不一致,请检查"+ format(msg))
            raise msg
try:
            self.assertIn("2106000013",source) # 断言搜索值是否存在页面源码中
            print("正确搜索出该编号数据")
            excepttotal ="1"
            self.assertEqual(total,excepttotal) # 断言total值是否为1
            print("底部分页统计正确,搜索出"+total+"条数据")
        except AssertionError as msg:
            print("搜索的数据不正确"+format(msg))
            raise msg    
总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/232493.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【基于NLP的微博情感分析:从数据爬取到情感洞察】

基于NLP的微博情感分析:从数据爬取到情感洞察 背景数据集技术选型功能实现创新点 今天我将分享一个基于NLP的微博情感分析项目,通过Python技术、NLP模型和Flask框架,对微博数据进行清洗、分词、可视化,并利用NLP和贝叶斯进行情感分…

基于Lucene的全文检索系统的实现与应用

文章目录 一、概念二、引入案例1、数据库搜索2、数据分类3、非结构化数据查询方法1) 顺序扫描法(Serial Scanning)2)全文检索(Full-text Search) 4、如何实现全文检索 三、Lucene实现全文检索的流程1、索引和搜索流程图2、创建索引1)获取原始…

Moco框架的搭建使用

一、前言   之前一直听mock,也大致了解mock的作用,但没有具体去了解过如何用工具或框架实现mock,以及也没有考虑过落实mock,因为在实际的工作中,很少会考虑用mock。最近在学java,刚好了解到moco框架是用于…

语言模型GPT与HuggingFace应用

受到计算机视觉领域采用ImageNet对模型进行一次预训练,使得模型可以通过海量图像充分学习如何提取特征,然后再根据任务目标进行模型微调的范式影响,自然语言处理领域基于预训练语言模型的方法也逐渐成为主流。以ELMo为代表的动态词向量模型开…

创建dockerSwarm nfs挂载

创建dockerSwarm nfs挂载 nfs高可用部署(lsyncd两主机双向同步) nfs高可用部署(lsyncd三主机三向同步) 1. 通过 Volume 1.1 创建 Docker Volume 每个 swarm 节点均创建相同名称的 Docker Volume(名称为 nfs120) docker volume create --driver local …

Jupyter notebook修改背景主题

打开Anaconda Prompt,输入以下内容 1. pip install --upgrade jupyterthemes 下载对应背景主题包 出现Successfully installed jupyterthemes-0.20.0 lesscpy-0.15.1时,说明已经下载安装完成 2. jt -l 查看背景主题列表 3. jt -t 主题名称(…

【docker 】centOS 安装docker

官网 docker官网 github源码 卸载旧版本 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine 安装软件包 yum install -y yum-utils \device-mapper-persistent-data…

Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)

目录 一、前言 二、Bean配置信息重用 1.简介 : 2.实例 : 三、关于Bean的创建顺序 1.简介 : 2.实例 : 四、关于Bean的单例和多例 1.简介 : 2.实例 : 五、关于Bean的生命周期 1.简介 : 2.实例 : 六、Bean配置后置处理器 1.简介 : 2.实例 : 七、通过.properties文…

AcWing 93. 递归实现组合型枚举

Every day a AcWing 题目来源:93. 递归实现组合型枚举 解法1:回溯算法 标准的回溯算法模板题。 如果把 n、m 和数组 nums 都设置成全局变量的话,backtracking 回溯函数可以只用一个参数 level。 注意传参时 nums 不能用引用,…

Hive SQL间隔连续问题

问题引入 下面是某游戏公司记录的用户每日登录数据, 计算每个用户最大的连续登录天数,定义连续登录时可以间隔一天。举例:如果一个用户在 1,3,5,6,9 登录了游戏,则视为连续 6 天登录。 id dt1001 2021-12-121002 2021-12-12…

SQL语句---删除索引

介绍 使用sql语句删除索引。由于索引会占用一定的磁盘空间,因此,为了避免影响数据库性能,应该及时删除不再使用的索引。 命令 drop index 索引名 on 表名;例子 删除a表中的singleidx索引: drop index singleidx on a;下面是执…

GoldWave注册机 最新中文汉化破解版-安装使用教程

GoldWave是一个功能强大的数字音乐编辑器,是一个集声音编辑、播放、录制和转换的音频工具。它还可以对音频内容进行转换格式等处理。它体积小巧,功能却无比强大,支持许多格式的音频文件,包括WAV、OGG、VOC、 IFF、AIFF、 AIFC、AU…

FPGA 低延时 TCP UDP IP协议栈兼容1G 10G 25G MAC

在计算和数据中心、军事和航天、政府、仪器与测量、金融服务和广播和视频等行业,需要高可靠性的硬件和软件产品,帮助客户更快地开发部署新一代产品,减少技术和市场风险,我司研发的低延迟TCP/IP的IP核的传输速率高于传统网口&#…

汽车4S店中的“S”指的什么?柯桥生活英语学习

很多人买车都会去4S店选购 因为比较有保障 服务又很到位 可你有没有想过 这里的“4S”是什么意思 其实,这几个单词大家都认识 今天我们就来聊一下 与“4S店”相关的英文表达 01 “4S店”的英语表达 其实,4S店的全称是:汽车销售服务4S店…

基于Java的汽车客运站管理系统的设计与实现论文

摘 要 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对汽车客运站售票信息管理混乱,出错率高,信息安…

Redis对象类型检测与命令多态

一. 命令类型 Redis中操作键的命令可以分为两类。 一种命令可以对任意类型的键执行,比如说DEL,EXPIRE,RENAME,TYPE,OBJECT命令等。 举个例子: #字符串键 127.0.0.1:6379> set msg "hello world&…

Verilog基础:寄存器输出的两种风格

相关文章 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 Verilog中的寄存器操作一般指的是那些对时钟沿敏感而且使用非阻塞赋值的操作。例如状态机中的状态转移,实际上就是一种寄存器操作,因为这相…

换根DP模板

给你一个无根树&#xff0c;问你以哪个节点为根节点的时候得到所有点的深度之和最大 《贴一张 知乎大佬的一个解释》 #include<bits/stdc.h> using namespace std; const int N 2e610; using ll long long; ll dep[N],sz[N]; ll ans[N]; vector<int>g[N]; int n;…

What the DAAM: Interpreting Stable Diffusion Using Cross Attention

What the DAAM: Interpreting Stable Diffusion Using Cross Attention (Paper reading) Raphael Tang, Comcast Applied AI, ACL2023 best paper, Code, Paper 1. 前言 大规模扩散神经网络是文本到图像生成中的一个重要里程碑&#xff0c;但人们对其了解甚少&#xff0c;缺…

超详细的Selenium:设置元素等待、上传文件、下载文件

前言&#xff1a;在工作和学习selenium自动化过程中记录学习知识点&#xff0c;深化知识点 1、设置元素等待 元素定位之元素等待-- WebDriver提供了两种类型的等待&#xff1a;显示等待和隐式等待。 同时&#xff0c;在这我为大家准备了一份软件测试视频教程&#xff08;含…