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

news2024/11/14 13:32:11

目录

概念

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/'+filename
    driver.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 sleep

class Page():
    def __init__(self,driver):
        self.driver=driver
        self.base_url="http://localhost"
        self.timeout=10

    def _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 By

class 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).text

    def 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 sleep

class 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 time

report_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.coloradmin.cn/o/988494.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】详解红黑树并模拟实现

前言: 上篇文章我们一起学习了AVL树比模拟实现,我们发现AVL树成功地把时间复杂度降低到了O(logN)。但是同时我们不难发现一个问题,在构建AVL树中我们也付出了不小的代价,频繁的旋转操作导致效率变低。为了解决这个问题&#xff0c…

使用Fastchat部署vicuna大模型

FastChat是一个用于训练、提供服务和评估基于大型语言模型的聊天机器人的开放平台。其核心特点包括: 最先进模型(例如 Vicuna)的权重、训练代码和评估代码。一个分布式的多模型提供服务系统,配备 Web 用户界面和与 OpenAI 兼容的…

算法通关村第十七关:黄金挑战-跳跃游戏问题

黄金挑战-跳跃游戏问题 1. 跳跃游戏 LeetCode 55 https://leetcode.cn/problems/jump-game/ 思路分析 关键是判断能否到达终点,不用管每一步跳跃到哪里,而是尽可能的跳跃到最远的位置 看最多能覆盖到哪里,只要不断更新能覆盖的距离&#x…

【狂神】Spring5笔记(一)之IOC

目录 首页: 1.Spring 1.1 简介 1.2 优点 2.IOC理论推导 3.IOC本质 4.HelloSpring ERROR 5.IOC创建对象方式 5.1、无参构造 这个是默认的 5.2、有参构造 6.Spring配置说明 6.1、别名 6.2、Bean的配置 6.3、import 7.DL依赖注入环境 7.1 构造器注入 …

[JAVA] byte与int的类型转换案例剖析

总结: ①没有byte的字面值,赋值时需要强制转换类型 ②涉及运算,系统自动进行类型升级,由此用final修饰,代表这是一个不会更改值的常量,通过编译 感受:还是用int吧,自动类型转换太复…

VB:顺序查找

VB:顺序查找 Private Sub Command1_Click()Dim i%, m%Dim x(1 To 10) As SingleFor i 1 To 10x(i) Val(InputBox("请输入"))Next im seqSearch(x, 10)If (m 1) ThenPrint "已找到"ElsePrint "未找到"End If End Sub Function se…

为什么在线客服系统的消息撤回功能是有必要的?

如今在日常工作和沟通中,很多企业都在使用在线客服系统跟客户进行线上交流和协作。然而有时候客服可能会不小心发送错误的消息或包含敏感信息的消息,人们在现实的沟通交流中是不会真实存在“说出去的话还能收回来”的情况,但这是在网络上&…

thinkphp开启定时任务的三种办法(最全)

第一种方法 使用think-cron类库 //composer 安装 composer require yunwuxin/think-cron github文档地址 https://github.com/yunwuxin/think-cron 1.创建任务类 <?php namespace app\task; use yunwuxin\cron\Task; class DemoTask extends Task { public function …

【从入门到起飞】JavaSE—File的使用,构造方法,成员方法

&#x1f38a;专栏【JavaSE】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【The truth that you leave】 &#x1f970;欢迎并且感谢大家指出我的问题 文章目录 &#x1f354;File概述&#x1f354;File构造方法⭐根据文件路径…

el-carousel-item轮播一个swiper显示多个卡片数据

效果图&#xff1a; 图片路径均为假地址&#xff0c;需自行替换&#xff0c;1rem100px&#xff0c;可自行转换成px <template><div class"exhibitors page-item-blue-bg"><comItemTitle :titleInfo"titleInfo"> </comItemTitle>…

如何评估需求优先级?

项目的需求来源有很多方面&#xff0c;最终由产品经理整理出来哪些要做&#xff0c;哪些不做。我前面说过需求评审时&#xff0c;要讲清楚这次版本的目的是什么。这些要做的功能就是达成目的的手段。 一般情况下&#xff0c;我们都默认产品或技术总监给需求定优先级。比如优先…

微信小程序被坑记录

web-view组件 你想要使用它&#xff0c;必须必须要配置 开发管理->开发设置->业务域名 线上版本 wx.saveImageToPhotosAlbum 调用失败 前几天还能用&#xff0c;今天一试&#xff0c;妈耶&#xff0c;除了线上版本都能用。真的头大&#xff0c;线上版本咋看报错嘛 线…

Ei Scopus检索 | 2024年第四届能源与环境工程国际会议(CoEEE 2024)

会议简介 Brief Introduction 2024年第四届能源与环境工程国际会议(CoEEE 2024) 会议时间&#xff1a;2023年5月22日-24日 召开地点&#xff1a;意大利米兰 大会官网&#xff1a;www.coeee.org CoEEE 2024将围绕“能源与环境工程”的最新研究领域而展开&#xff0c;为研究人员、…

深度学习Tensorflow: CUDA_ERROR_OUT_OF_MEMORY解决办法

目前在用深度学习训练&#xff0c;训练中设置batch size后可以正常跑通&#xff0c;但是在训练一轮save_model时&#xff0c;总出现这个错误&#xff0c;即使我调batch size到1也依旧会报错。 发现是在 调用logger时出现问题。 查询后了解到是因为TensorFlow中的eager_executi…

VSCode学习笔记一:添加代码模板

一目了然 1 简述2 设置模板3 Global Snippets file示例 1 简述 问&#xff1a;为什么要设置代码模板&#xff1f; 答&#xff1a;编程语言是有个性的&#xff0c;不同语言的演讲风格是不一样的。 旁白&#xff1a;我不懂&#xff1f;&#xff01; 问&#xff1a;为什么要设置…

C++中引用详解!

前言&#xff1a; 本文旨在讲解C中引用的相关操作&#xff0c;以及引用的一些注意事项&#xff01;搬好小板凳&#xff0c;干货来了&#xff01; 引用的概念 何谓引用呢&#xff1f;引用其实很容易理解&#xff0c;比如李华这个同学&#xff0c;他因为很调皮&#xff0c;所以…

大模型时代下向量数据库的创新与变革

前言&#xff1a; 在当今信息时代&#xff0c;数据库扮演着关键的角色&#xff0c;用于存储和管理各种类型的数据。向量数据库是一种专门设计用于高维数据存储和快速检索的数据库系统。在不断创新和变革后&#xff0c;腾讯云不久前发布了AI原生&#xff08;AI Native&#xff0…

Vue3 + 百度地图实现位置选择,获取地址经纬度

Vue3 百度地图实现位置选择&#xff0c;获取地址经纬度 需求&#xff1a;添加传感器时&#xff0c;需要选择传感器所在的省、市、区、详细地址、以及传感器的经纬度信息。解决方案&#xff1a;集成百度地图API&#xff0c;通过在地图上搜索或者点击获取传感器的具体位置信息。…

什么是敏捷工作流程?如何实施?

依赖传统的项目管理流程&#xff08;即使它们效率不高&#xff09;&#xff0c;会阻碍团队协作&#xff0c;难以管理不断变化的项目需求。 而另一方面&#xff0c;现代项目管理方法&#xff08;如敏捷工作流程&#xff09;为项目带来了简单性、自主性和高效性。它能帮助你了解…

TSINGSEE青犀视频AI算法助力构建城市市容·街面秩序管理解决方案

随着城市化进程加快&#xff0c;未经合理规划设置自然形成的马路市场越来越多&#xff0c;这不仅存在交通安全隐患&#xff0c;也造成了市容秩序混乱&#xff0c;严重影响城市市容面貌。 TSINGSEE青犀AI智能分析网关V3内部部署了几十种算法&#xff0c;包括人脸、人体、车辆、…