【自动化测试】之PO模式介绍及案例

目录

概念

PO三层模式:

1. 构建基础的 BasePage 对象层

2. 构建首页的 Page 层(操作层)

3.构建业务层

常用断言方法:

4. 构建用例集,执行文件,输出自动化测试报告

 测试报告模板


概念

PO(Page Object)设计模式是一种面向对象( 页面对象)的设计模式,将测试对象及单个的测试步骤封装在每个Page对象以page为单位进行管理。

优点

  1. 可以使代码复用
  2. 降低维护成本
  3. 提高程序可读性和编写效率。
  4. 可以将页面定位和业务操作分开,测试对象(元素对象)和测试脚本(用例脚本)
  5. 提高用例的可维护
非PO模式PO模式
面向过程的线性脚本POM把页面元素定位和业务操作流程分开,实现松耦合
复用性性差UI元素的改变不需要修改业务逻辑代码,只需要找到对应的PO页修改定位即可,数据代码分离
维护性差PO能使代码更具有可读性,高复用性、可维护性

PO三层模式:

主要分三层:
1.base层(对象库层):page页面一些公共的方法。如:初始化、元素定位、点击、输入、获取文本、截图等方法;
2.page层(操作层):封装对元素的操作。将每个涉及的元素操作单独封装一个操作方法,然后根据需求组装操作步骤,如登录方法=输入帐号+输入密码+点击登录三个操作进行组装;
3.scripts层(业务层):导包调用 page页面,使用单元测试框架对业务逻辑进行封装测试。如:实现登录,直接调用page组装的登陆方法即可。
三者的关系:page层继承base层,scripts层调用page层

案例:

项目结构介绍:

创建项目,如下图

1. 构建基础的 BasePage 对象层

创建driver,浏览器驱动封装

# encoding='UTF-8'
# 浏览器启动
from selenium import webdriver
def browser():driver=webdriver.Chrome()# driver.get("http://www.baidu.com")return driver

创建myuni.py文件,初始化封装,

定义一个继承自unittest.TestCase的测试用例类

定义setUp和tearDown,这两个方法与junit相同,即如果定义了则会在每个测试case执行前先执行setUp方法,执行完毕后执行tearDown方法。

# encoding='UTF-8'
import unittest
from driver import *
class StartEnd(unittest.TestCase):def setUp(self):self.driver=browser()self.driver.implicitly_wait(10)self.driver.maximize_window()def tearDown(self):self.driver.quit()

创建function.py文件,截图功能

# encoding='UTF-8'
import os
from selenium import webdriver# 截图
def insert_img(driver,filename):func_path=os.path.dirname(__file__)# print(func_path)base_dir=os.path.dirname(func_path)# print(base_dir)# 将路径转化为字符串base_dir=str(base_dir)# 对路径的字符串进行替换base_dir=base_dir.replace("\\","/")# print(base_dir)# 获取项目文件的要目录路径base=base_dir.split('/Website')[0]# print(base)# 指定截图存放路径(注意路径最后要加/)filepath=base+'/Website/test_report/screnshot/'+filenamedriver.get_screenshot_as_file(filepath)if __name__=='__main__':driver=webdriver.Chrome()driver.get("http://www.sogou.com")

2. 构建首页的 Page 层(操作层)

创建BasePage.py文件,判断打开的页面是否是预期的页面

# encoding='UTF-8'
from time import sleepclass Page():def __init__(self,driver):self.driver=driverself.base_url="http://localhost"self.timeout=10def _open(self,url):url_=self.base_url+url# print("这个页面url是:%s"%url_)self.driver.maximize_window()self.driver.get(url_)# sleep(2)assert self.driver.current_url==url_,'这不是我们想要的地址'def open(self):self._open(self.url)def find_element(self,*loc):return self.driver.find_element(*loc)

创建LoginPage.py文件,页面元素定位封装

# encoding='UTF-8'
from BasePage import *
from selenium.webdriver.common.by import Byclass LoginPage(Page):url='/news/'username_loc=(By.NAME,'username')password_loc=(By.NAME,'password')submit_loc=(By.NAME,'Submit')def type_username(self,username):self.find_element(*self.username_loc).send_keys(username)def type_password(self,password):self.find_element(*self.password_loc).send_keys(password)def type_submit(self):self.find_element(*self.submit_loc).click()def login_action(self,username,password):self.open()self.type_username(username)self.type_password(password)self.type_submit()loginPass_loc=(By.LINK_TEXT,'我的空间')loginErr_loc=(By.LINK_TEXT,'加入收藏')def type_loginPass_hint(self):return self.find_element(*self.loginPass_loc).textdef type_loginErr_hit(self):return self.find_element(*self.loginErr_loc).text

3.构建业务层

  1. 创建test_login.py文件
  2. 导包:function、myunit、LoginPage
  3. 创建LoginTest类,继承myunit.StartEnd,初始化方法
  4. 定义测试用例,名字以test开头,unittest会自动将test开头的方法放入测试用例集中
  5. 实现登录,调用LoginPage组装的登陆方法,输入用户名、密码、点击登录、断言,截图
# encoding='UTF-8'
import unittest
from model import function,myunit
from page_object.LoginPage import *
from time import sleepclass LoginTest(myunit.StartEnd):def test_login1_normal(self):print("test_login1_normal测试开始")po=LoginPage(self.driver)po.login_action("yuruyi","12345678")sleep(5)self.assertEqual(po.type_loginPass_hint(),'我的空间')function.insert_img(self.driver,"login_normal.png")print("test_login1_normal执行结束")def test_login2_PasswdError(self):print("test_login2_PasswdError测试开始")po=LoginPage(self.driver)po.login_action("yuruyi","1234567")sleep(5)self.assertEqual(po.type_loginErr_hit(),'加入收藏')function.insert_img(self.driver,"login_Err.png")print("test_login2_PasswdError执行结束")def test_login3_empty(self):print("test_login3_empty测试开始")po = LoginPage(self.driver)po.login_action("", "")sleep(5)self.assertEqual(po.type_loginErr_hit(), '加入收藏')function.insert_img(self.driver, "login_empty.png")print("test_login3_empty执行结束")if __name__=='__main__':unittest.main()

常用断言方法:

4. 构建用例集,执行文件,输出自动化测试报告

在测试用例、测试文件比较多的时候,使用统一的主测试执行文件进行测试用例的执行非常方便,这就需要结合discover方法和TextTestRunner进行。

# encoding='UTF-8'
import unittest
# 测试报告模板
from HTMLTestRunnerCN import HTMLTestRunner
import timereport_dir='./test_report'
test_dir='./test_case'print("start run test case")
discover=unittest.defaultTestLoader.discover(test_dir,pattern="test_login.py")now=time.strftime("%Y-%m-%d %H_%M_%S")
report_name=report_dir+'/'+now+'result.html'print("start write report..")
#使用runner运行器运行测试集
with open(report_name,'wb')as f:runner=HTMLTestRunner(stream=f,title="Test Report",description="localhost login test")runner.run(discover)f.close()
print("Test end")

 测试报告模板

 


以下是我收集到的比较好的学习教程资源,虽然不是什么很值钱的东西,如果你刚好需要,可以评论区,留言【777】直接拿走就好了

 

各位想获取资料的朋友请点赞 + 评论 + 收藏,三连!

三连之后我会在评论区挨个私信发给你们~

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

webhook--详解(gitee 推送)

一、简介 webhook 是一种基于 HTTP 的回调函数,可在 2 个应用编程接口(API)之间实现轻量级的事件驱动通信。是一种新型的前后端交互方式,一种对客户端-服务器模式的逆转,在传统方法中,客户端从服务器请求数…

Vue3---uni-app--高德地图引用BUG

先给报错信息:module libs/map//libs/map_min.js is not defined, require args is /libs/map_min.js 查看我引用方法: 本人查阅资料发现 是 require 使用的是 commonJS方式引用说这个适配Vue2可我项目是Vue3应该使用ES6语法糖 然后我有跑了项目发现BU…

Excel数学、工程和科学计算插件:FORMULADESK Studio

如果 Excel 是您的武器 - 让我们磨砺您的剑!为整天使用 Excel 的人们提供创新的 Excel 加载项,你需要这个 FORMULADESK Studio。。。 Excel 插件为任何使用 Excel 执行数学、工程和科学计算的人提供了必备工具。 * 将公式视为真正的数学方程 * 为您的公…

接口自动化测试总结

一、什么项目适合做自动化测试? 软件需求变动不频繁 测试脚本的稳定性决定了自动化测试的维护成本。如果软件需求变动过于频繁,测试人员需要根据变动的需求来更新测试用例以及相关的测试脚本,而脚本的维护本身就是一个代码开发的过程&#x…

快速解决 adb server version doesn‘t match this client

这个问题是由于电脑上安装了多个版本的adb工具,客户端和服务端的版本不一致,无法正常通信导致。最快的解决方法就是将Android SDK中adb复制到系统目录下。 操作步骤如下: 1. 查看adb版本和路径 执行adb version,如下&#xff0…

Python - 队列【queue】task_done()和join()基本使用

一. 前言 task_done()是Python中queue模块提供的方法,用于通知队列管理器,已经处理完了队列中的一个项目。 queue.task_done()是Queue对象的一个方法,它用于通知Queue对象,队列中的某一项已经被处理完毕。通常在使用Queue对象时…

STM32 Nucleo-144开发板开箱bring-up

文章目录 1. 开篇2. 开发环境搭建2.1 下载官方例程2.2 ST-Link安装 3. STM32F446ZE demo工程3.1 STM32F446ZE简介3.2 跑个demo试一试 1. 开篇 最近做项目,用到STM32F446ZET6这款MCU,为了赶进度,前期软件需要提前开发,于是在某宝买…

将PyCharm中的终端运行前面的PS修改成当前环境

最近使用Pycharm中的Terminal来pip安装一些pakage,发现Terminal运行前面的显示的是PS,然后输入安装指令报错。“python无法将“pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。” 解决方法: 只需要在pycharm的设置中修改一些termi…

高频golang面试题:简单聊聊内存逃逸?

文章目录 问题怎么答举例 问题 知道golang的内存逃逸吗?什么情况下会发生内存逃逸? 怎么答 golang程序变量会携带有一组校验数据,用来证明它的整个生命周期是否在运行时完全可知。如果变量通过了这些校验,它就可以在栈上分配。…

Greenplum执行SQL卡住的问题

问题 今天社区群里面一位同学反映他的SQL语句执行会hang住,执行截图如下。 分析 根据提示信息,判断可能是网络有问题,或者是跟GP使用UDP包有关系。 此同学找了网络检查的人确定网络没有问题,于是猜测跟UDP包有关。 参考文章ht…

git中的cherry-pick和merge有些区别以及cherry-pick怎么用

git中的cherry-pick和merge在使用场景上有些区别: cherry-pick用于将另一个分支的某一次或几次commit应用到当前分支。它可以选择性地拉取代码修改。merge用于将两个分支合并成一个新分支。它会把整个分支上的所有修改都合并过来。 具体区别:cherry-pick通常用于将bug修复从发…

plt函数显示图片 在图片上画边界框 边界框坐标转换

%matplotlib inline import torch from d2l import torch as d2l读取图片并显示图片 读取图片 image_path ../data/images/cat_dog_new.jpg # 创建画板 figure d2l.set_figsize() image d2l.plt.imread(image_path) d2l.plt.imshow(image);给出一个(x左上角,y左上角,x右下角…

Java多线程篇(1)——深入分析synchronized

文章目录 synchronized原理概述锁升级 初始状态偏向锁偏向锁获取/重入偏向锁的撤销/重偏向和升级批量重偏向和批量偏向撤销偏向锁的释放 轻量级锁轻量级锁获取/重入轻量级锁膨胀轻量级锁释放 重量级锁重量级锁获取/重入重量级锁释放重量级锁的降级 其他锁粗化、锁消除调用hashc…

【LeetCode】5 . 最长回文子串

5 . 最长回文子串(中等) 方法:中心扩散法 思想 「中心扩散法」的基本思想是:遍历每一个下标,以这个下标为中心,利用「回文串」中心对称的特点,往两边扩散,看最多能扩散多远。 枚举…

【系统设计系列】 回顾可扩展性

系统设计系列初衷 System Design Primer: 英文文档 GitHub - donnemartin/system-design-primer: Learn how to design large-scale systems. Prep for the system design interview. Includes Anki flashcards. 中文版: https://github.com/donnemart…

后端/DFT/ATPG/PCB/SignOff设计常用工具/操作/流程及一些文件类型

目录 1.PD/DFT常用工具及流程 1.1 FC和ICC2 1.2 LC (Library compiler) 1.3 PrimeTime 1.4 Redhawk与PA 1.5 Calibre和物理验证PV 1.6 芯片设计流程 2.后端、DFT、ATPG的一些常见文件 2.1 LEF和DEF 2.2 ATPG的CTL和STIL 2.3 BSDL 2.4 IPXCT 3.PCB设计的一些工作和工…

RabbitMQ: Routing结构

生产者 package com.qf.mq2302.routing;import com.qf.mq2302.utils.MQUtils; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection;public class EmitLog {public static final String EXCHANGE_NAME"emitlogs";public static void main(…

OpenCV 03(数据结构--Mat)

一、Mat介绍 Mat是OpenCV在C语言中用来表示图像数据的一种数据结构.在python中转化为numpy的ndarray. Mat由header和data组成, header中记录了图片的维数, 大小, 数据类型等数据. 1.1 Mat拷贝 - Mat共享数据 在python中Mat数据对应numpy的ndarray, 使用numpy提供的深浅拷贝方…

NIFI实现数据库数据增量同步

说明 nifi版本:1.23.2(docker镜像) 需求背景 将数据库中的数据同步到另一个数据库中,要求对于新增的数据和历史有修改的数据进行增量同步 模拟数据 建表语句 源数据库和目标数据库结构要保持一致,这样可以避免后…

【美团3.18校招真题1】

大厂笔试真题网址:https://codefun2000.com/ 塔子哥刷题网站博客:https://blog.codefun2000.com/ 小美剪彩带 提交网址:https://codefun2000.com/p/P1088 题意:找出区间内不超过k种数字子数组的最大长度 使用双指针的方式&…