webUI自动化测试框架

 🔥 交流讨论:欢迎加入我们一起学习!

🔥 资源分享耗时200+小时精选的「软件测试」资料包

🔥 教程推荐:火遍全网的《软件测试》教程  

📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!

一、设计思路

框架采用python3+yaml+po+unittest+HTMLTestRunner等技术编写的UI自动化测试框架
1.使用Page Object模式将页面定位和业务操作分开,分离测试对象(元素对象)和测试脚本(用例脚本),一个页面建一个对象类,提高用例的可维护性;
2.使用yaml管理页面空间元素和测试用例数据。例如一个页面元素发生变化时,不需要去修改代码,只需要在对应的页面元素yaml文件中修改即可。
3.以每个页面作为模块管理,随时组装,互不影响。

二、测试框架分层

1.框架层:基础组件封装,支撑整个框架的流程执行及功能扩展
2.用例层:根据用例场景构造test测试方法
3.业务层:封装页面对象类,一个页面建立一个类,业务层基础基础层page类
4.基础层:二次开发selenium的元素定位已经操作
 

三、编写用例方法

例如我需要新增百度搜索测试场景用例:

1.在testyaml目录下新增一个页面对象yaml文件,利用封装的yamlload方法将yaml文件中的dom元素读取出来,提供给封装页面对象类调用并定元素操作。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

testinfo:

      - id: test_login001

        title: 登录百度网页测试

        info: 打开百度首页

testcase:

      - element_info: s-usersetting-top

        find_type: ID

        operate_type: click

        info: 打开登录对话框

      - element_info: userName

        find_type: ID

        operate_type: send_keys

        info: 输入用户名称

      - element_info: TANGRAM__PSP_11__password

        find_type: ID

        operate_type: send_keys

        info: 输入密码

      - element_info: TANGRAM__PSP_11__submit

        find_type: ID

        operate_type: click

        info: 单击登录按钮

check:

      - element_info: //*[@id="user"]/span[2]

        find_type: XPATH

        info: 检查用户是否登录

  

2.在testdata目录下新增一个yaml文件提供给用例测试数据

1

2

3

4

5

6

7

8

9

-

  id: test_login001.1

  detail : 验证登录成功

  screenshot : phone_pawd_empty

  data:

    username: 13501198450

    password: Han520520

  check :

     - hhil833

3.在page_obj目录编写百度搜索场景的页面对象类封装

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

testData = getyaml(setting.TEST_Element_YAML + '/' + 'baidu_login.yaml')

class baidu_login(Page):

    def  open_login(self,username,pwd):

        """

              :return:

              """

        dig_login_button_loc = (By.ID, testData.get_elementinfo(0))

        self.find_element(*dig_login_button_loc).click()

        sleep(1)

    def go_login(self,username,pwd):

        self.find_element(By.ID, testData.get_elementinfo(1)).send_keys(username)

        sleep(1)

        self.find_element(By.ID, testData.get_elementinfo(2)).send_keys(pwd)

        sleep(1)

        self.find_element(By.ID, testData.get_elementinfo(3)).click()

    def user_login(self, username, pwd):

        self.go_login(username,pwd)

        sleep(1)

        check = (By.ID, By.ID,testData.get_CheckElementinfo(0))

        return  self.find_element(*check).text

4.在testcase目录编写测试用例文件,采用ddt数据驱动读取yaml测试数据源文件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

@ddt.data(*testData)

def user_login_verify(self, username, password):

    """

           用户登录

           :param phone: 手机号

           :param password: 密码

           :return:

           """

    baidu_login(self.driver).user_login(username,password)

def test_login(self,datayaml):

    """

            登录测试

            :param datayaml: 加载login_data登录测试数据

            :return:

            """

    self.log.info("当前执行测试用例ID-> {0} ; 测试点-> {1}".format(datayaml['id'],datayaml['detail']))

    # c = self.user_login_verify(datayaml["username"],datayaml["password"])

    # log.info("检查点-> {0}".format(c))

    # self.assertEqual(c, datayaml['check'][0],

    #                  "成功登录,返回实际结果是->: {0}".format(c))

5.通过多线程将驱动传给执行方法,并行开启多个浏览器执行测试

1

2

3

4

5

6

7

8

9

10

11

12

def run_case(self,function,name):

    thread_list=[]

    for in range(1):

        appium_server = threading.Thread(target=function,args=(name,))

        thread_list.append(appium_server)

        for in thread_list:

            j.start()

def run_casea(self):

    name = ["chrome""chrome"]

    for in name:

        self.run_case(self.test_baidu,i)

  

6.操作元素封装

1

2

3

4

5

6

7

8

9

10

11

12

13

def get_element(self, find_type, element=""):

    # getdata = getyaml(file)

    # type = getdata.get_find_type(find_type_index)

    if find_type == "id" or find_type == "ID":

        print(1111111111111111111111)

        return self.driver.find_element_by_id(element)

    elif find_type == "xpath" or find_type == "XPATH":

        return self.driver.find_element_by_xpath(element)

    elif find_type == "name" or find_type == "NAME":

        return self.driver.find_element_by_name(element)

    else:

        raise Exception("错误!")

7.浏览器驱动封装

from typing import Union, Type
from selenium.webdriver import *
from selenium.webdriver.opera.options import Options as OperaOptions
from selenium.webdriver.edge.options import Options as EdgeOptions
from setting import *

BROWSERS = (Chrome, Ie, Firefox, Edge, Opera, PhantomJS)
OPTIONS = (ChromeOptions, IeOptions, FirefoxOptions, EdgeOptions, OperaOptions)


class BROWSER:

    CHROME_DRIVER_PATH = CHROME_DRIVER_PATH

    # 使用32位ie驱动解决文本输入缓慢的问题
    IE_DRIVER_PATH = IE_DRIVER_PATH

    FIREFOX_DRIVER_PATH = FIREFOX_DRIVER_PATH
    EDGE_DRIVER_PATH = EDGE_DRIVER_PATH
    OPERA_DRIVER_PATH = OPERA_DRIVER_PATH

    HEADLESS = HEADLESS

    # IMPLICITLY WAITING TIME METHOD
    IMPLICITLY_WAIT_TIME = 10

    # PAGE SOURCE LOAD TIME METHOD
    PAGE_LOAD_TIME = 10

    # the script should wait during an
    # execute_async_script call before throwing an error
    SCRIPT_TIMEOUT = 0

    # SET WINDOW SIZE METHOD
    WINDOWS_SIZE = (1024, 900)

    def __init__(self, browser_type: Type[Union[Chrome, Ie, Firefox, Edge, Opera, PhantomJS, Remote]] = Chrome,
                 option_type: Type[Union[FirefoxOptions, ChromeOptions, IeOptions, EdgeOptions, OperaOptions]] = ChromeOptions,
                 driver_path: str = CHROME_DRIVER_PATH):
        if not issubclass(browser_type, BROWSERS):
            raise TypeError
        if not issubclass(option_type, OPTIONS):
            raise TypeError
        if not isinstance(driver_path, str):
            raise TypeError
        self._driver = browser_type
        self._option = option_type
        self._path = driver_path

    @property
    def browser(self):
        """
        subclass should implement this method
        return the instance of WebDriver
        :return:
        """
        return

    @property
    def _options(self):
        """
        subclass should implement this method
        return instance of the Option Type like ChromeOptions
        :return:
        """
        return


class CHROME(BROWSER):

    METHOD_MARK = True

    IMPLICITLY_WAIT_TIME = 30

    PAGE_LOAD_TIME = 20

    SCRIPT_TIMEOUT = 10

    # HEADLESS MODEL OPTION
    HEADLESS = False

    OPTION_MARK = True

    # EXPERIMENTAL OPTION
    EXPERIMENTAL = {
        # 'mobileEmulation': {'deviceName': 'iPhone 6'},  #以移动格式现实启动页面做h5时候会用到
        'excludeSwitches': ['enable-automation'] #浏览器启动时左上角提示正在运行自动化
    }

    # WINDOW SIZE OPTION
    WINDOW_SIZE = ''
    # WINDOW_SIZE = '--window-size=1920,1080'

    # START MAXIMIZED OPTION
    START_MAXIMIZED = '--start-maximized'

    @property
    def _options(self):
        """
        chrome浏览器特有的操作属性
        :return:
        """
        if self.OPTION_MARK:
            chrome_option = self._option()
            chrome_option.headless = self.HEADLESS
            if self.WINDOW_SIZE:
                chrome_option.add_argument(self.WINDOW_SIZE)
            if self.START_MAXIMIZED:
                # chrome_option.add_argument(self.START_MAXIMIZED)
                chrome_option.add_argument('--headless')
                chrome_option.add_argument('--disable-gpu')

            for k, v in self.EXPERIMENTAL.items():
                chrome_option.add_experimental_option(k, v)
            return chrome_option
        return None
    
    @property
    def browser(self):
        """
        启动chrome浏览器并进行初始配置
        :return:
        """

        if self._options:
            chrome = self._driver(self._path, options=self._options)
        else:
            chrome = self._driver(self._path)

        if self.METHOD_MARK:
            chrome.implicitly_wait(self.IMPLICITLY_WAIT_TIME)
            chrome.set_page_load_timeout(self.PAGE_LOAD_TIME)
            chrome.set_script_timeout(self.SCRIPT_TIMEOUT)
            return chrome



class IE(BROWSER):

    IMPLICITLY_WAIT_TIME = 20

    PAGE_LOAD_TIME = 10

    SCRIPT_TIMEOUT = 10

    WINDOWS_SIZE = (1600, 1024)

    CLEAN_SESSION = True

    ATTACH_TIMEOUT = 10000

    MARK = True

    def __init__(self):
        super(IE, self).__init__(
            browser_type=Ie,
            option_type=IeOptions,
            driver_path=super().IE_DRIVER_PATH
        )

    @property
    def _options(self):
        """
        ie浏览器特有的操作属性
        :return:
        """
        ie_option = self._option()
        ie_option.browser_attach_timeout = self.ATTACH_TIMEOUT
        ie_option.ensure_clean_session = self.CLEAN_SESSION
        return ie_option

    @property
    def browser(self):
        """
        启动ie浏览器并进行初始配置
        :return:
        """
        if self.MARK:
            ie = self._driver(self._path, options=self._options)
        else:
            ie = self._driver(self._path)
        ie.implicitly_wait(self.IMPLICITLY_WAIT_TIME)
        ie.set_page_load_timeout(self.PAGE_LOAD_TIME)
        ie.set_script_timeout(self.SCRIPT_TIMEOUT)
        ie.set_window_size(*self.WINDOWS_SIZE)
        return ie


class FIREFOX(BROWSER):

    def __init__(self):
        super(FIREFOX, self).__init__(
            browser_type=Firefox,
            option_type=FirefoxOptions,
            driver_path=super().FIREFOX_DRIVER_PATH
        )

    @property
    def _options(self):
        return

    def browser(self):
        return self._driver(self._path)


class OPERA(BROWSER):

    def __init__(self):
        super(OPERA, self).__init__(
            browser_type=Opera,
            option_type=OperaOptions,
            driver_path=super().OPERA_DRIVER_PATH
        )

    @property
    def _options(self):
        return

    def browser(self):
        return self._driver(self._path)

最后我邀请你进入我们的【软件测试学习交流群:785128166】, 大家可以一起探讨交流软件测试,共同学习软件测试技术、面试等软件测试方方面面,还会有免费直播课,收获更多测试技巧,我们一起进阶Python自动化测试/测试开发,走向高薪之路

作为一个软件测试的过来人,我想尽自己最大的努力,帮助每一个伙伴都能顺利找到工作。所以我整理了下面这份资源,现在免费分享给大家,有需要的小伙伴可以关注【公众号:程序员二黑】自提!

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

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

相关文章

【LeetCode】升级打怪之路 Day 16:二叉树题型 —— 二叉树的构造

今日题目: 654. 最大二叉树105. 从前序与中序遍历序列构造二叉树106. 从中序与后序遍历序列构造二叉树889. 根据前序和后序遍历构造二叉树 目录 LC 654. 最大二叉树 【easy】 Problem:根据遍历序列来还原二叉树 【classic】 ⭐⭐⭐⭐⭐LC 105. 从前序与中…

数据库原理实验课(1)

目录 实验内容 安装头歌中的相关内容 具体过程 完结撒花~ 我也是第一次接触oracle的相关软件和操作,所以是一次傻瓜式教学记录 实验内容 安装头歌中的相关内容 具体过程 这是我在百度网盘中下载解压出来的oracle文件夹内的全部内容(可能有因为安装完…

使用Portainer让测试环境搭建飞起来

Docker的用处不多加赘述,Docker目前有以下应用场景: 测试:Docker很适合用于测试发布,将 Docker 封装后可以直接提供给测试人员进行运行,不再需要测试人员与运维、开发进行配合,进行环境搭建与部署。 测试…

【技术】基于Github Pages搭建个人博客静态网页

写在前面: 如果文章对你有帮助,记得点赞关注加收藏一波,利于以后需要的时候复习,多谢支持! 文章目录 一、技术基础二、新建特殊仓库三、上传网页文件四、Github Pages设置 个人网页作为仅服务个人的网页,一…

Grafana变量默认全选

注:本文基于Grafana v9.2.8编写 1 问题 EKS集群里的node按照不同label被分为几类,我需要对这几类的node做一些统计。我希望当我使用lable选择时,node的值自动设置为该lable的所有node集合,而不需要再手动全选。 2 解决方案 变…

微信小程序(五十四)腾讯位置服务示范(2024/3/8更新)

教程如下: 上一篇 1.先在官网注册一下账号(该绑定的都绑定一下) 腾讯位置服务官网 2.进入控制台 3.创建应用 3. 额度分配 4.下载微信小程序SDK 微信小程序SDK下载渠道 5.解压将俩js文件放在项目合适的地方 6.加入安全域名or设置不验证合…

扩展CArray类,增加Contain函数

CArray不包含查找类的函数,使用不便。考虑扩展CArray类,增加Contain函数,通过回调函数暴露数组元素的比较方法,由外部定义。该方法相对重载数组元素的“”符号更加灵活,可以根据需要配置不同的回调函数进行比较 //类型…

AD20中关于“failed to add class member”的解决方法

目录 问题描述: 解决方法: 1.切换至PCB界面-选择工具栏的设计-类 2.把Component classes中的所有的类全部按照图中删除,保存 3.重新返回原理图界面转换PCB即可成功 问题描述: failed to add class member:未能添加…

解答关于:水牛社软件是做什么的?水牛社软件靠谱么?

很多对我们软件感兴趣但是没有入手的观望者都会有这样的疑问:水牛社软件具体是做什么的?水牛社软件靠谱么? 其实软件的简介已经讲的很清楚了,但是软件不是功能性软件,所以不能给大家免费试用,短期任务版块…

智能驾驶规划控制理论学习08-自动驾驶控制模块(轨迹跟踪)

目录 一、基于几何的轨迹跟踪方法 1、基本思想 2、纯追踪 3、Stanly Method 二、PID控制器 三、LQR(Linear Quadratic Regulator) 1、基本思想 2、LQR解法 3、案例学习 基于LQR的路径跟踪 基于LQR的速度跟踪 4、MPC(Mode…

Python通过SFTP实现网络设备配置备份

一、背景 为了防止网络设备意外损坏,导致配置文件无法恢复,可以通过将网络设备的配置文件备份到本地电脑上。 一般情况下,设备支持通过FTP、TFTP、FTPS、SFTP和SCP备份配置文件。其中使用FTP和TFTP备份配置文件比较简单,但是存在…

JAVA虚拟机实战篇之内存调优[4](内存溢出问题案例)

文章目录 版权声明修复问题内存溢出问题分类 分页查询文章接口的内存溢出问题背景解决思路问题根源解决思路 Mybatis导致的内存溢出问题背景问题根源解决思路 导出大文件内存溢出问题背景问题根源解决思路 ThreadLocal占用大量内存问题背景问题根源解决思路 文章内容审核接口的…

尚硅谷JavaScript高级学习笔记

01 准备 JavaScript中函数是对象。我们后续描述构造函数的内存模型时,会将构造函数称为构造函数对象。 02 数据类型 typeof 运算符来查看值的类型,它返回的是类型的字符串值 会做数据转换 03 相关问题 04数据_变量_内存 05相关问题1 06相关问题2 …

办公电脑换成MacBookPro半年之后……

小白是从2008年开始接触电脑的,当时朋友给我注册的第一个QQ账号是2008年4月。 从此,小白一直认为电脑全部都是Windows系统。直到上大学那年,看到了外教老师的MacBookPro…… 折腾电脑的开始居然是起源于诺基亚手机,给半智能S40的…

Igraph入门指南 3

4、图转换到其他R数据结构 图是对实体关系的表达,在igraph中,图可以转换为三种数据结构。 4-1 图转邻接矩阵:as_adjacency_matrix | as_adj,结果是矩阵 邻接矩阵又分为有向图邻接矩阵和无向图邻接矩阵,但本函数使用…

老司机都懂的!【打赏】完美运营的最新视频打赏系统

完美运营的最新视频打赏系统优于市面上95%的打赏系统,与其他打赏系统相比,功能更加强大,完美运营且无bug。支付会调、短链接生成、代理后台、价格设置和试看功能等均没有问题。 以上为原简介,经测试验证。成功搭建并可以正常进入…

Linux学习之线程

目录 线程概念 1.什么是线程? 2.线程的优缺点 3.线程异常 4.线程用途 线程操作 1.如何给线程传参 2.线程终止 3.获取返回值 4.分离状态 5.退出线程 线程的用户级地址空间: 线程的局部存储 线程的同步与互斥 互斥量mutex 数据不一致的主要过…

Sora的核心技术预测

在ChatGPT火爆全网的一年后,OpenAI公司又一次大显身手:推出了全新的文生视频大模型Sora。直接输入文字提示词,即可直接生成长达60秒的视频。 “现实真的要不存在了。” 马斯克直接大呼:人类彻底完蛋了! 马斯克为什么…

CDN(内容分发网络):加速网站加载与优化用户体验

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【NR技术】 3GPP支持无人机的关键技术以及场景

1 背景 人们对使用蜂窝连接来支持无人机系统(UAS)的兴趣浓厚,3GPP生态系统为UAS的运行提供了极好的好处。无处不在的覆盖范围、高可靠性和QoS、强大的安全性和无缝移动性是支持UAS指挥和控制功能的关键因素。与此同时,监管机构正在调查安全和性能标准以及…