SeleniumUI自动化的POM三层架构

news2024/11/29 6:34:05

目录

1、定义log.py日志

2、在基础封装层初始化类uitls.__init__.py中选择了日志的打印级别,

3、定义页面基础类base_page.py,定义了页面找元素的方法,

4、将百度页面的元素以代码形式保存,baidu.py

5、重新封装浏览器方法, browser.py

6、编写测试用例


简介:
企业级自动化测试中,要写的代码太多了,写着写着会发现很多的代码都重复的写,而且硬编码导致了代码很冗余,一大坨一大坨,当出现了问题后,不好剖析原因以及快速找到对应的解决办法。
写成POM三层架构就方便管理代码,而且避免了代码的冗余。
目的:使代码结构清晰,方便管理代码,将代码和业务分开来,一定程度实现了解耦合性。

文件夹层级如下

1、定义log.py日志


①定义了日志的存放的位置,
②定义的日志的最大存放大小,
③定义了日志的输出格式,
④日志即打印在控制台上也写入日志文件中,

import os
import logging
import time

from logging.handlers import RotatingFileHandler

def log(log_level="DEBUG"):
    logger = logging.getLogger()
    logger.setLevel(log_level)
    log_size = 1024*1024*20
    dir_name = "../../logs/"
    if not os.path.exists(dir_name):
        os.mkdir(dir_name)
    time_str = time.strftime("%Y%m%d",time.localtime())
    fh = RotatingFileHandler(dir_name+f"{time_str}.log",encoding="utf-8",maxBytes=log_size,backupCount=100)

    #将日志输出到控制台
    ch = logging.StreamHandler()
    #设置输出日志格式
    formatter = logging.Formatter(
        fmt="%(asctime)s [%(levelname)s] %(filename)s line:%(lineno)s %(message)s",
    )
    #为handler指定输出格式,注意大小写
    fh.setFormatter(formatter)
    ch.setFormatter(formatter)
    #为logger添加的日志处理器
    logger.addHandler(fh)
    logger.addHandler(ch)

2、在基础封装层初始化类uitls.__init__.py中选择了日志的打印级别,

在browser.py中会使用,使用日志时只需导入logging包,使用logging.info("日志信息")的方式即可

from .log import log
log("INFO")

3、定义页面基础类base_page.py,定义了页面找元素的方法,


①专门服务于页面类,用于寻找元素,
②使用了显示等待,设置了没找到元素时重复寻找的次数和隔多长时间找一次
③定义了driver驱动,则继承他的类在实例化时需要传入驱动

class BasePage(object):
    def __init__(self,driver):
        self.__driver = driver
    def find_element(self,by,value,times=10,wait_time=1)->object:
        return self.__driver.until_find_element(by,value,times=times,wait_time=wait_time)

4、将百度页面的元素以代码形式保存,baidu.py


①HomePage类继承了BasePage类,则可使用他的方法
②方法上添加@property,则调用这方法时可以像调用属性的方式一样(如:eles=对象.link_xinwen)

from automation.demo1.src.utils.base_page import BasePage

class HomePage(BasePage):
    @property
    def link_xinwen(self):
        return self.find_element('xpath', '//*[@id="s-top-left"]/a[1]')
    @property
    def link_hao123(self):
        return self.find_element('xpath', '//*[@id="s-top-left"]/a[2]')
    @property
    def link_ditu(self):
        return self.find_element('xpath', '//*[@id="s-top-left"]/a[3]')
    @property
    def link_tieba(self):
        return self.find_element('xpath', '//*[@id="s-top-left"]/a[4]')
    @property
    def link_shipin(self):
        return self.find_element('xpath', '//*[@id="s-top-left"]/a[5]')
    @property
    def link_tupian(self):
        return self.find_element('xpath', '//*[@id="s-top-left"]/a[6]')
    @property
    def link_wangpan(self):
        return self.find_element('xpath', '//*[@id="s-top-left"]/a[7]')
    @property
    def link_gengduo(self):
        return self.find_element('xpath', '//*[@id="s-top-left"]/div/a')
    @property
    def shurukuang(self):
        return self.find_element('xpath', '//*[@id="kw"]')
    @property
    def baiduyixia(self):
        return self.find_element('xpath', '//*[@id="su"]')
    @property
    def shezhi(self):
        return self.find_element('xpath', '//*[@id="s-usersetting-top"]')
    @property
    def denglu(self):
        return self.find_element('xpath', '//*[@id="s-top-loginbtn"]')
    @property
    def link_fanyi(self):
        return self.find_element('xpath','//*[@id="s-top-more"]/div[1]/a[1]')

class NewsPage(BasePage):
    @property
    def help_link(self):
        return self.find_element("xpath",'//*[@id="sbox"]/tbody/tr/td[2]/table/tbody/tr/td[2]/a')

5、重新封装浏览器方法, browser.py


①初始化寻找驱动
②打开浏览器,输入地址,且最大化
③切换窗口
④悬浮到元素
④JS下拉滚动条
⑤下拉滚动条到某位置
⑥下拉滚动条到某元素
⑦JS点击元素
⑧JS使元素变为可点击状态 
⑨JS修元素属性
⑩获取浏览器名字和版本
11,智能寻找元素
12,智能点击元素

import logging
import time

from selenium.webdriver import Chrome, Firefox, ActionChains
from selenium.common.exceptions import NoSuchElementException, ElementNotInteractableException


class Browser(Chrome, Firefox):
    def __init__(self, browser_type="chrome", driver_path=None, *args, **kwargs):
        """
        :param browser_type:浏览器类型,如果不传则默认是谷歌浏览器
        :param driver_path:驱动的地址
        :param args:可变列表参数
        :param kwargs:可变字典参数
        """
        # 检查browser_type是否合法
        if browser_type not in ["chrome", "firefox"]:
            logging.error("browser_type浏览器类型即不是谷歌也不是火狐")
            raise ValueError("browser_type浏览器类型既不是谷歌也不是火狐")
        self.__browser_type = browser_type

        # 根据__browser_type的类型选择对于的驱动
        if self.__browser_type == "chrome":
            if driver_path:
                Chrome.__init__(self, executable_path=f"{driver_path}/chromedirver.exe", *args, **kwargs)
            else:
                Chrome.__init__(self, *args, **kwargs)
        elif self.__browser_type == 'firefox':
            if driver_path:
                Firefox.__init__(self, executable_path=f"{driver_path}/geckodriver.exe", *args, **kwargs)
            else:
                Firefox.__init__(self, *args, **kwargs)
    #打开页面且最大化,习惯性需要最大化,不然容易出现问题
    def open_browser(self, url):
        self.get(url)
        self.maximize_window()

    # 切换窗口
    def switch_to_new_page(self):
        # 获取目前窗口与最后窗口的对比
        current_handle = self.current_window_handle
        handles = self.window_handles
        if current_handle != handles[-1]:
            self.switch_to.window(handles[-1])

    # 悬浮到元素
    def suspension(self, ele):
        ActionChains(self).move_to_element(ele).perform()

    # 下拉滚动条-通过滚动滚动条
    def scrollTo1(self):
        self.execute_script("document.documentElement.scrollTop=10000")
        time.sleep(1)

    # 下拉滚动条-通过位置
    def scrollTo2(self):
        self.execute_script("window.scrollTo(0,100000)")
        time.sleep(1)

    # 下拉滚动条到某元素
    def scrollTo3(self, ele):
        self.execute_script("arguments[0].scrollIntoView()", ele)
        time.sleep(1)

    # 使用js点击元素
    def js_click(self, button):
        self.execute_script("$(arguments[0]).click();", button)

    # 使元素变成可点击状态
    def js_enable(self,ele):
        self.execute_script('arguments[0].removeAttribute(\"disabled\")',ele)
    # 修改元素不可点击的状态
    def js_disable(self,ele):
        self.execute_script('arguments[0].setAttribute(arguments[1],arguments[2])',ele,'disabled','enable')

    @property
    def browser_name(self):
        return self.capabilities["browserName"]

    @property
    def browser_version(self):
        return self.capabilities["browserVersion"]

    def until_find_element(self, by, value, times=10, wait_time=0.5):
        """
        用于定位元素
        :param by:定位元素的方式
        :param value:定位元素的值
        :param times:定位元素的重试次数
        :param wait_time:定位元素失败的等待时间
        :return:返回定位的元素
        """
        # 检查by的合法性
        if by not in ["id", "name", "class", "tag", "text", "partial_text", "css", "xpath"]:
            logging.error(f"无效的定位方式:{by},请输入id,name,class,tag,text,partial_text,css,xpath")
        for i in range(times):
            # 定位元素
            el = None
            try:
                if by == "id":
                    el = super().find_element_by_id(value)
                elif by == "name":
                    el = super().find_element_by_name(value)
                elif by == "class":
                    el = super().find_element_by_class_name(value)
                elif by == "tag":
                    el = super().find_element_by_tag_name(value)
                elif by == "text":
                    el = super().find_element_by_link_text(value)
                elif by == "partial_text":
                    el = super().find_element_by_partial_link_text(value)
                elif by == "css":
                    el = super().find_element_by_css_selector(value)
                elif by == "xpath":
                    el = super().find_element_by_xpath(value)
            except NoSuchElementException:
                logging.error(f"通过{by}未能找到元素【{value}】,正在进行第{i + 1}此重试...")
                time.sleep(wait_time)
            else:
                # 如果成功定位元素则返回元素
                logging.info(f"通过{by}成功定位元素【{value}】!")
                return el
        logging.error(f"通过{by}无法定位元素【{value}】,请检查...")
        raise NoSuchElementException(f"哦通过{by}无法定位元素【{value}】,请检查...")
    def click(self,button,repeat=5):
        for i in repeat:
            # 判断元素是否可见和可点击
            if(button.is_displayed() and button.is_enabled()):
                button.click()
                return
        logging.info(f"元素{button},是不可见得,或者是不可点击的")
        raise ElementNotInteractableException(f"元素{button},是不可见的,或者是不可点击的")


if __name__ == '__main__':
    try:
        browser = Browser()
        browser.open_browser('http://sahitest.com/demo/clicks.htm')
        ele_disable1 = browser.find_element('xpath','/html/body/form/input[5]')
        # browser.js_click(ele_disable1)
        browser.js_enable(ele_disable1)
        browser.addAttribute(browser,ele_disable1,'disable')
        time.sleep(2)
        ele_disable1.click()
    finally:
        time.sleep(15)
        browser.quit()

6、编写测试用例


①起始工作,打开浏览器输入地址
②结束工作,关闭浏览器
①用例1:测试百度输入框输入selenium能搜索出包含selenium相关的信息
②用例2:测试通过百度首页进入新闻界面
③用例3:测试能进入hao123界面
。。。。。。

import unittest
import time
import logging
from selenium.webdriver import ActionChains
from automation.demo1.src.pages.baidu import HomePage,NewsPage
from automation.demo1.src.utils.browser import Browser

class Baidu(unittest.TestCase):
    def setUp(self) -> None:
        self.driver = Browser()
        self.driver.open_browser("https://www.baidu.com")
        logging.info("打开浏览器")
        logging.info(f"浏览器名称:{self.driver.browser_name},浏览器版本:{self.driver.browser_version}")

        self.homepage =  HomePage(self.driver)
        self.newpage = NewsPage(self.driver)
    def tearDown(self) -> None:
        self.driver.quit()
        logging.info("关闭浏览器")
    def test_01_search(self):
        """用例1:测试百度输入框输入selenium能搜索出包含selenium相关的信息"""
        logging.info("用例1:测试百度输入框输入selenium能搜索出包含selenium相关的信息")

        #输入搜索信息
        self.homepage.shurukuang.send_keys("selenium_automation")
        logging.info("输入搜索信息")
        #点击按钮
        self.homepage.baiduyixia.click()
        time.sleep(2)
        #校验搜索结果
        els = self.driver.find_element_by_partial_link_text("Selenium")
        self.assertIsNotNone(els)
        logging.info("用例1测试通过")
    def test_02_access_help_news(self):
        """用例2:测试通过百度首页进入新闻界面"""
        logging.info("用例2:测试通过百度首页能进入新闻界面")
        #点击新闻链接
        self.homepage.link_xinwen.click()
        logging.info("点击新闻链接")
        #切换窗口
        self.driver.switch_to_new_page()
        logging.info("切换窗口")
        #点击游戏链接
        self.newpage.help_link.click()
        logging.info("点击游戏链接")
        #校验url
        current_rul = self.driver.current_url
        self.assertEqual(current_rul,"https://help.baidu.com/")
        logging.info("用例2测试通过")
    def test_03_access_hao123(self):
        """用例3:测试能进入hao123界面"""
        logging.info("用例3:测试能进入hao123界面")
        self.homepage.link_hao123.click()
        self.driver.switch_to_new_page()
        logging.info("切换窗口")
        #校验url
        current_url = self.driver.current_url
        self.assertEqual(current_url,"https://www.hao123.com/?src=from_pc")
        logging.info("用例3测试通过")
    def test_04_access_map(self):
        """用例4:测试能进入地图界面"""
        logging.info("用例4:测试能进入地图界面")
        self.homepage.link_ditu.click()
        logging.info("切换窗口")
        self.driver.switch_to_new_page()
        #校验url
        current_url = self.driver.current_url
        els= self.driver.find_element('xpath','//*[@id="componseLeft"]/p')
        self.assertIsNotNone(els)
        logging.info("用例4测试通过")
    def test_05_access_tieba(self):
        """用例5: 测试能进入贴啊界面"""
        logging.info("用例5:测试能进入贴吧界面")
        self.homepage.link_tieba.click()
        logging.info("切换窗口")
        self.driver.switch_to_new_page()
        #校验url
        current_url = self.driver.current_url
        self.assertEqual(current_url,"https://tieba.baidu.com/index.html")
        logging.info("用例5通过测试覅")
    def test_06_access_shiping(self):
        """用例6:能进入视频界面"""
        logging.info("用例6:能进入视频界面")
        self.homepage.link_shipin.click()
        logging.info("切换窗口")
        self.driver.switch_to_new_page()
        #校验url
        current_url = self.driver.current_url
        self.assertEqual(current_url,"https://haokan.baidu.com/?sfrom=baidu-top")
        logging.info("用例6测试通过")
    def test_07_access_tupian(self):
        """用例7:能进入图片界面"""
        logging.info("用例7:能进入视频界面")
        self.homepage.link_tupian.click()
        logging.info("切换窗口")
        self.driver.switch_to_new_page()
        #校验rul
        current_url = self.driver.current_url
        self.assertEqual(current_url,"https://image.baidu.com/")
        logging.info("用例7测试通过")
    def test_08_access_wangpan(self):
        """用例8:能进入网盘界面"""
        logging.info("用例8:能进入网盘界面")
        self.homepage.link_wangpan.click()
        logging.info("切换窗口")
        self.driver.switch_to_new_page()
        #校验url
        current_url = self.driver.current_url
        self.assertEqual(current_url,"https://pan.baidu.com/?from=1026962h")
        logging.info("用例8测试通过")
    def test_09_access_gengduo(self):
        """用例9:能进入更多界面"""
        logging.info("用例9:能进入更多界面")
        self.homepage.link_gengduo.click()
        logging.info("切换窗口")
        self.driver.switch_to_new_page()
        #校验url
        current_url = self.driver.current_url
        self.assertEqual(current_url,"https://www.baidu.com/more/")
        logging.info("用例9测试通过")
    def test_10_access_fanyi(self):
        """用例10,能进入翻译页面"""
        logging.info("用例10:能进入翻译页面")
        #悬浮到设置元素上,后点击进入翻译页面
        self.driver.suspension(self.homepage.link_gengduo)
        self.homepage.link_fanyi.click()
        #校验url
        self.driver.switch_to_new_page()
        current_url = self.driver.current_url
        self.assertEqual(current_url,"https://fanyi.baidu.com/")
        logging.info("用例10测试通过")

if __name__ == '__main__':
    unittest.main()

SeleniumGUI自动化POM三层架构结束,欢迎进我主页观看其它技术类文章~~

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

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

相关文章

ChatGPT版微信个人号搭建流程

[TOC] 参考链接: github仓库 准备服务器 进入腾讯云服务器官网,搜索“轻量应用服务器”立即选购 注意,地区要选海外,镜像选Docker镜像 购买之后,就进入控制台 然后登陆到shell 安装部署 查看一下docker&#xff0…

【探索Spring底层】11.切点匹配

文章目录1. 前言2. 给一个类中的其中一个方法增强3. 根据注解给方法增强4. Spring中Transactional的底层实现1. 前言 这里主要讲述一些切点匹配的相关例子,其主要是关于切点表达式匹配的实现。 主要有三种例子: 给一个类中的其中一个方法增强根据注解…

Gitee创建自己的仓库并且上传项目

Gitee创建自己的仓库并且上传项目前言在码云上创建仓库上传项目到远程仓库前言 之前用了一段时间的Gitee(码云)一直想写一篇文章记录下,结果赶上世界杯 被人把苦茶子给抢走了。。。正好这几天筹钱,那就简单记录下。 这里的Git的安…

[附源码]Python计算机毕业设计动漫网站Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等…

机器人开发--Pepperl+Fuchs倍加福激光雷达系列

机器人开发--PepperlFuchs倍加福激光雷达系列1 介绍2 R2000系列2.1 按键操作2.2 测量方法2.3 协议2.3.1 文档2.3.2 特点2.3.3 控制 HTTP收发报文格式get_protocol_info设置传感器参数list_parameters – list parametersget_parameter – read a parameterset_parameter – cha…

springboot simple (10) springboot protobuf

教程列表: springboot simple(0) springboot简介 springboot simple(1) springboot Helloworld springboot simple(2) springboot Starter springboot simple(3 )spri…

Flutter Web CORS问题

Flutter Web CORSCORS 相关概念协议请求跨域问题App2WebCodingAppCORS 相关概念 关于 CORS 概念,可参考 mozilla 的相关文档资料: Cross-Origin Resource Sharing (CORS)Reason: CORS header ‘Access-Control-Allow-Origin’ missing An example of …

震撼发布,快鲸企微工单任务管理系统上线了

快鲸推出的企微SCRM系统被大家所熟知,这是一款帮助企业通过企微维护客户的管理系统。在客户管理服务过程中,很多企业需要通过工单来进行事项处理和文件内容流转,为了满足这方面客户的需求,快鲸工单系统也应运而生。 品牌都将客户的…

关于json的集合接收和多表关联查询

文章目录一、json的接收与发送1.postman工具发送格式2.controller接收处理二、查询集合数据1.利用mybatis-plus进行分页处理三.读取数据配置mapper.xml输出结果提示:以下是本篇文章正文内容,下面案例可供参考 一、json的接收与发送 1.postman工具发送格…

selenium之鼠标操作详解

前言 人类频繁的用手操作鼠标和键盘,为了解决这个问题,selenium工具为我们提供了一个类来处理这些事件— Actionchains ,该类可以完成鼠标移动,鼠标点击事件、键盘输入、内容菜单交互等交互行为。 1、常见的鼠标操作有&#xff1…

DSPE-Thiol; DSPE-SH; 二硬脂酰磷脂酰乙醇胺改性巯基

名称:DSPE-Thiol DSPE-SH 全称:18:0 PE Thiol 中文名称:二硬脂酰磷脂酰乙醇胺改性巯基 结构式: 外观:白色粉末 溶剂:HCCl3及其他有机溶剂 反应基团:马来酰亚胺,可以跟任何带有马来酰亚胺活…

【计算机毕业设计】html学生管理系统 OA管理系统设计与实现 HTML网页设计结课作业

🎉精彩专栏推荐 💭文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (10…

[附源码]Nodejs计算机毕业设计基于JAVA语言的宠物寄养管理Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置: Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分…

Java基于springboot+vue+elementUI城乡精准扶贫信息管理系统

系统设计的主要意义在于,一方面,对于网站来讲,系统上线后可以带来很大的便利性,精准扶贫网站管理属于非常细致的管理模式,要求数据量大,计算机管理可以提高精确性,更为便利的就是信息的查询&…

短信引导用户关注公众号短信唤起小程序h5跳转公众号引导用户关注

背景 想要短信唤起微信并引导用户关注公众号,经过调研这样是做不了的,但是我们发现可以通过短信唤起小程序,那么我们只需要在小程序中内嵌一个h5,用 h5 来引导跳转公众号就好了。 那么我们拆解一下要做的事情: 短信唤…

数字孪生园区创新实验室落地解决方案

园区实验室管理实质上是对园区、人员、实验试剂耗材、仪器等的整体管理。借助数字孪生技术,实现数字化管理,可以大大提高实验室管理者以及科研人员的工作效率。 数字孪生园区创新实验室落地解决方案 北京智汇云舟科技有限公司成立于2012年,专…

概论_第4章__期望的定义和性质

一. 定义 1. 离散型随机变量的期望 2. 连续型随机变量的期望 定义2:设连续型随机变量 X的概率密度为f(x), 若积分 绝对收敛, 称其为X的数学期望。记为: 注意: 被积函数是: xf(x) 看例题: 几种重要分布的数学期…

Oracle-图形化界面-数据库安装

0、Oracle网址 1、oracle官网 2、Oracle下载地址 3、官网安装教程 1、Oracle数据库简介 Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是…

还在手写接口文档?看Swagger如何助你解放双手去吃鸡

近期又有小伙伴私信辉哥,问辉哥现在的接口文档都是怎么编写的?今天辉哥就给大家聊聊,项目中怎么接入Swagger,实现在线接口文档。来,咱们这就开怼! 一. 前言 现在的项目开发很多都会采用前后端分离的模式&…

Linux程序包管理工具

Linux程序包管理工具 1. 程序包 我已经使用 Linux 已经有很长一段时间了,日常中经常会安装或者卸载一些应用,久而久之很多的命令已经让我的记忆能力不容乐观了,所以今天在这里写一点管理程序包管理的博客。一方面,之后可以帮助我…