测试老鸟整理,Selenium自动化测试POM模式分层实战(详细)

news2024/11/18 3:32:26

目录:导读

    • 前言
    • 一、Python编程入门到精通
    • 二、接口自动化项目实战
    • 三、Web自动化项目实战
    • 四、App自动化项目实战
    • 五、一线大厂简历
    • 六、测试开发DevOps体系
    • 七、常用自动化测试工具
    • 八、JMeter性能测试
    • 九、总结(尾部小惊喜)


前言

POM是Page Object Model的简称,它是一种设计思想,意思是,把每一个页面,当做一个对象,页面的元素和元素之间操作方法就是页面对象的属性和行为。

POM一般使用三层架构,分别为:基础封装层、页面对象层、测试用例层。
目录结构大致如下

请添加图片描述

基础封装层

基础封装层主要是封装一些常用的方法,提高代码的复用。
基础封装层当前只包含了3个文件:
base_page.py:将所有界面共用的方法进行封装
browser.py:继承了selenium常用的webdriver操作,并对部分操作进行了封装
log.py:封装日志功能

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=10, wait_time=1)

因为在页面对象层,我们会将每个界面定义成一个类对象,而每个类对象都需要传入一个webdriver的实例对象。

为了减少这样的重复操作,我们在base_page.py定义一个页面基类BasePage,在页面对象层定义的类继承该基类就可以完成webdriver实例对象的传入。

browser.py文件代码如下:

import time
import logging

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


class Browser(Chrome, Firefox):

    def __init__(self, browser_type="chrome", driver_path=None, *args, **kwargs):
        """
        根据浏览器类型初始化浏览器
        :param browser_type: 浏览器类型,只可传入chrome或firefox
        :param driver_path:指定驱动存放的路径
        """
        # 检查browser_type值是否合法
        if browser_type not in ["chrome", "firefox"]:
            # 不合法报错
            logging.error("browser_type 输入值不为chrome,firefox")
            raise ValueError("browser_type 输入值不为chrome,firefox")

        self.__browser_type = browser_type

        # 根据browser_type值选择对应的驱动
        if self.__browser_type == "chrome":
            if driver_path:
                Chrome.__init__(self, executable_path=f"{driver_path}/chromedriver.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()

    @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=1):
        """
        用于定位元素
        :param by: 定位元素的方式
        :param value: 定位元素的值
        :param times: 定位元素的重试次数
        :param wait_time: 定位元素失败的等待时间
        :return: 返回定位的元素
        """
        # 检查by的合法性
        if by not in ["id", "xpath", "name", "class", "tag", "text", "partial_text", "css"]:
            # 不合法报错
            logging.error(f"无效定位方式:{by},请输入:id,xpath, name, class, tag, text, partial_text, css")
            raise ValueError(f"无效定位方式:{by},请输入:id,xpath, name, class, tag, text, partial_text, css")

        # 定位元素,如果定位失败,增加重试机制
        for i in range(times):
            # 定位元素
            el = None
            try:
                if by == "id":
                    el = super().find_element_by_id(value)
                elif by == "xpath":
                    el = super().find_element_by_xpath(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_elements_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)
            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 switch_to_new_page(self):
        # 获取老窗口的handle
        old_handle = self.current_window_handle

        handles = self.window_handles
        for handle in handles:
            if handle != old_handle:
                self.switch_to.window(handle)
                break

在browser.py文件中,我们主要定义一个 Browser类,该类继承了selenium的Chrome 和 Firefox,在实例化Browser类后,我们能使用selenium所有的方法,同时,我们在Browser类中还封装一些其它操作。

比如将查找元素的8种方法进行封装并增加元素定位失败后重试次数,比如切换新界面的handle等

log.py文件代码如下:

import os
import logging
import time


from logging.handlers import RotatingFileHandler


def log(log_level="DEBUG"):
    # 创建logger,如果参数为空则返回root logger
    logger = logging.getLogger()

    # 设置logger日志等级
    # logger.setLevel(logging.DEBUG)
    logger.setLevel(log_level)

    # 创建handler
    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",
        # datefmt="%Y/%m/%d %X"
    )
    # 注意 logging.Formatter的大小写

    # 为handler指定输出格式,注意大小写
    fh.setFormatter(formatter)
    ch.setFormatter(formatter)

    # 为logger添加的日志处理器
    logger.addHandler(fh)
    logger.addHandler(ch)

log.py文件主要定义了一个log函数,函数中定义了日志相关的操作,注意,定义的log函数需要在任意被执行文件中被调用。

比如,在用例层我们调用了browser.py文件中的方法,那么在架构中必定执行utils文件中__init.py文件,所以我们在__init__.py文件中调用log函数。

init.py文件代码如下:

from .log import log

log("INFO")

到此,我们完成了日志的环境配置,当需要记录日志时,只需要在文件中导入logging包,使用logging.info()这种方式记录日志即可。

页面对象层

什么是页面对象?
页面对象就是将每个界面当成一个对象,界面中的元素当成对象的属性。下面以百度首页和新闻页为例,介绍页面对象层。

在页面对象层,新增文件baidu.py,文件代码如下:

from utils.base_page import BasePage


class HomePage(BasePage):

    @property
    def input_box(self):
        return self.find_element("id", "kw")

    @property
    def search_button(self):
        return self.find_element("id", "su")

    @property
    def news_link(self):
        return self.find_element("xpath", '//*[@id="s-top-left"]/a[1]')


class NewsPage(BasePage):
    @property
    def game_link(self):
        return self.find_element("xpath", '//*[@id="channel-all"]/div/ul/li[10]/a')

类对象HomePage和NewsPage分别代表百度首页和百度新闻页,在类对象中定义了一些方法,每个方法表示页面中的一个元素,再使用装饰器@property将这些方法属性化。比如,input_box表示输入框,search_button表示搜索框。

测试用例层

下面以两个简单的用例,来演示脚本的编写。

test_baidu.py文件代码如下:

import unittest
import time
import logging

from utils.browser import Browser
from page_object.baidu import HomePage, NewsPage


class Baidu(unittest.TestCase):

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

        self.homepage = HomePage(self.driver)
        self.newspage = NewsPage(self.driver)

    def tearDown(self) -> None:
        self.driver.quit()
        logging.info("关闭浏览器")

    def test_search(self):
        """ 用例1:测试百度搜索框输入selenium能搜索出包含selenium相关的信息 """
        logging.info("用例1:测试百度搜索框输入selenium能搜索出包含selenium相关的信息")

        # 输入搜索信息
        self.homepage.input_box.send_keys("selenium")
        logging.info("输入搜索信息")

        # 点击按钮
        self.homepage.search_button.click()
        logging.info("点击搜索按钮")
        time.sleep(2)

        # 校验搜索结果
        els = self.driver.find_element_by_partial_link_text("selenium")
        self.assertIsNotNone(els)

    def test_access_game_news(self):
        """ 用例2:测试通过百度首页能进入新闻界面的游戏专题 """
        logging.info("用例2:测试通过百度首页能进入新闻界面的游戏专题")

        # 点击新闻链接
        self.homepage.news_link.click()
        logging.info("点击新闻链接")

        # 切换窗口
        self.driver.switch_to_new_page()
        logging.info("切换窗口")

        # 点击游戏链接
        self.newspage.game_link.click()
        logging.info("点击游戏链接")

        # 校验url
        current_url = self.driver.current_url
        self.assertEqual(current_url, "http://news.baidu.com/game")


if __name__ == '__main__':
    unittest.main()
下面是我整理的2023年最全的软件测试工程师学习知识架构体系图

一、Python编程入门到精通

请添加图片描述

二、接口自动化项目实战

请添加图片描述

三、Web自动化项目实战

请添加图片描述

四、App自动化项目实战

请添加图片描述

五、一线大厂简历

请添加图片描述

六、测试开发DevOps体系

请添加图片描述

七、常用自动化测试工具

请添加图片描述

八、JMeter性能测试

请添加图片描述

九、总结(尾部小惊喜)

每一天都是全新的起点,不要轻易放弃自己的梦想和目标。坚持努力,相信自己的实力和能力,付出总有回报,成功就在前方等待着你。无论遇到什么困难,勇于面对并克服,一步一个脚印,迈向辉煌人生!

只要你心怀梦想,坚持努力不懈,勇攀高峰,就一定能够达到自己的目标;人生的路虽然坎坷不平,但只有不断前行才能收获成功的喜悦。相信自己,勇往直前!

勇往直前,不畏困难;脚踏实地,追求卓越;不怕失败,勇于尝试;心存梦想,终将成功;坚持不懈,永不放弃;努力奋斗,创造美好未来!

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

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

相关文章

3. SpringCloudAlibaba、nacos 实现配置中心

一、微服务中配置文件的问题 1.1 配置文件的问题: 配置文件的数量会随着服务的增加持续递增单个配置文件无法区分多个运行环境配置文件内容无法动态更新,需要重启服务 1.2 引入配置中心 引入配置中心:刚才架构就会成为这样。是由配置中心统…

ASP.NET Core Web API入门之二:Swagger详细使用路由设置

ASP.NET Core Web API入门之二:Swagger详细使用 一、引言二、Swagger的作用以及优点2.1 作用2.2 优点 三、API接口添加注释3.1 编辑项目文件3.2 修改 Startup.cs 文件的 ConfigureServices 方法3.3 修改浏览器的网页标题3.4 注册路由中间件3.4 接口添加注释 四、运行…

基于html+css的图展示125

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

项目管理专业人员能力评价(CSPM)好考吗?考试时间什么时候?

2021年10月,中共中央、国务院发布的《国家标准化发展纲要》明确提出构建多层次从业人员培养培训体系,开展专业人才培养培训和国家质量基础设施综合教育。建立健全人才的职业能力评价和激励机制。由中国标准化协会(CAS)组织开展的项…

和数集团Baas服务如何推动区块链技术应用和产业发展?

近日,《区块链和分布式记账技术 参考架构》(GB/T 42752-2023)国家标准正式发布。这是我国首个获批发布的区块链技术领域国家标准。该标准在区块链技术应用和产业发展方面提出了参考架构规范,包括用户视图、功能视图、实现视图和部署视图。在功能架构方面…

启程阿拉德之怒三端架设教程

阿拉德之怒是一款横版动作冒险RPG手游,游戏采用虚拟按键模式呈现指尖上的连击盛宴,波动血气等不同的奥义带来多系转职技能,讲述不同时空交错的节点诞生的大陆之上,来个各界的强者们汇聚在一起冒险战斗故事,领悟鬼手之力…

基于ubuntu22.04-深入浅出 eBPF

笔者在很早之前就看eBPF这类似的文章,那时候看这个技术一脸懵逼,不知道它是用来做什么,可以解决什么问题。所以也没有太关注这个技术。很庆幸最近刚好有机会研究这个技术。 什么是BPF BPF的全称是Berkaley Packet Filter,即伯克利报文过法器…

计算机视觉的应用7-利用YOLOv5模型启动电脑摄像头进行目标检测

大家好,我是微学AI,今天给大家介绍一下计算机视觉的应用7-利用YOLOv5模型启动电脑摄像头进行目标检测,本文将详细介绍YOLOv5模型的原理,YOLOv5模型的结构,并展示如何利用电脑摄像头进行目标检测。文章将提供样例代码&a…

【GitLab】-HTTP Basic: Access denied.remote:You must use a personal access token

写在前面 本文简要说明GitLab配置accessToken以及双因子认证(Two-factor authentication)。 目录 写在前面一、场景描述二、具体步骤1.环境说明2.配置accessToken3.克隆项目4.双因子认证 三、参考资料写在后面 一、场景描述 在使用账号和密码的方式拉取公…

数据库的 Schema 变更实现

一、减少元数据变更的措施 元数据变更是数据库管理中不可避免的工作项,减少元数据变更次数可降低数据库维护和管理成本,减轻对业务的影响。这里我们可以优先考虑以下 3 点: 精细计划 在数据库设计和开发阶段,精细设计元数据结构…

月度精华汇总 | 最新XR行业资讯、场景案例、活动都在这一篇里啦!

​ 在过去的一个月中,平行云为您带来了关于XR领域的一系列精彩文章,涵盖了行业资讯、应用案例,市场互动,帮助您掌握XR领域最新动态,了解实时云渲染、Cloud XR技术的价值,以及平行云实时云渲染解决方案LarkX…

【每日算法】【160. 相交链表】

☀️博客主页:CSDN博客主页 💨本文由 我是小狼君 原创,首发于 CSDN💢 🔥学习专栏推荐:面试汇总 ❗️游戏框架专栏推荐:游戏实用框架专栏 ⛅️点赞 👍 收藏 ⭐留言 📝&…

【陈老板赠书活动 - 04期】- 【C++、Linux、算法等系列众书】

陈老老老板🦸 👨‍💻本文专栏:赠书活动专栏(为大家争取的福利,免费送书) 👨‍💻本文简述:与几分醉意.一起搞的赠书活动一次30本书哦!!…

软件项目质量管理的4大注意事项

1、制定质量计划和评估标准 项目质量管理首先需要制定详细的质量计划,明确项目质量目标,制定质量评估标准和验收方案。质量计划需与项目计划密切相关,并确保项目质量管理与项目进度和成本控制相配合。 软件项目质量管理的4大注意事项 2、构建…

Java+Swing+mysql仿QQ聊天工具

JavaSwingmysql仿QQ聊天工具 一、系统介绍二、功能展示1.用户登陆2.好友列表3.好友聊天4.服务器日志 三、系统实现四、其它1.其他系统实现2.获取源码 一、系统介绍 系统主要功能:用户登陆、好友列表、好友聊天、服务器日志 二、功能展示 1.用户登陆 2.好友列表 3…

想要避免计划外停机?预测性维护技术是关键

在现代工业领域,非计划停机是一项令人头疼的问题,它导致生产损失、利润减少,并给运营团队带来巨大的压力。然而,基于时间的维护策略并不能有效应对所有设备故障,因为大部分故障表现出随机模式,难以准确预测…

深入探索基于Webdriver的分层自动化框架搭建

目录 前言: 1、基于webdriver的分层自动化框架及平台搭建,目前刚好在做这一块的工作,对于分层次和平台搭建,想问下大神有什么好的建议? 2、希望大神能自己的工作经历和经验,对初入测试行业的后辈有何建议…

SpringCloudAlibaba环境搭建版本说明

可以通过www.github.com网站搜索alibaba,点击第一个超链接 点击wiki 点击版本说明 里面有对应版本: 也可以通过版本说明 alibaba/spring-cloud-alibaba Wiki GitHub这个链接直接访问

模板学堂|DataEase地图视图功能详解

DataEase开源数据可视化分析平台于2022年6月正式发布模板市场(https://dataease.io/templates/)。模板市场旨在为DataEase用户提供专业、美观、拿来即用的仪表板模板,方便用户根据自身的业务需求和使用场景选择对应的仪表板模板,并…

【渗透测试学习】RCE漏洞是什么意思?其危害是什么?

RCE漏洞是网络安全中非常常见的漏洞之一,该漏洞又叫做远程代码执行漏洞,属于高危漏洞,其有着巨大的危害和影响。但很多人初识网络安全时,对RCE漏洞并不是很了解,到底是什么是RCE漏洞?RCE漏洞危害是什么?又该如何预防…