当前位置:   article > 正文

【UI自动化】Python + Selenium搭建Web端UI自动化(上)_ui自动化测试平台前端代码

ui自动化测试平台前端代码

Selenium官方文档:https://www.selenium.dev/documentation/
翻译出来的中文文档:https://python-selenium-zh.readthedocs.io/zh_CN/latest/0
网友翻译的中文文档:https://selenium-python-zh.readthedocs.io/en/latest/

一、背景

客服IM系统目前坐席端都是基于web端进行,相比较客户端来讲,每个迭代中新功能和回归点比较多,手工测试成本很高,对于一些长期UI上没有较大变化的页面,考虑使用UI自动化提高回归效率

web自动化常见的验证点

  1. 页面元素验证
  2. 页面列表数据验证
  3. 页面元素属性
  4. UI的文本,图片显示正确性
  5. UI的交互逻辑正确性测试
  6. UI上的用户行为正确性测试

web自动化框架常见的需求点

  1. 分布式执行,可以多机器,多浏览器同步执行脚本
  2. 适用于不同环境运行
  3. 分层设计,方便维护
  4. 生成测试报告
  5. 模块的复用
  6. 必要的日志搜集

收益计算公式:

自动化的收益 = 迭代次数 * 全手动执行成本 - 首次自动化成本 - 维护次数 * 维护成本
每次版本迭代维护成本衡量:
维护用例占比及维护成本耗时
新增用例占比及编写成本耗时

二、目标

提高回归测试效率,节省人工测试成本。

1、目标功能架构图

在这里插入图片描述

  • 全局参数管理
  • 用例脚本管理(用例级别,用例执行顺序编排,用例级别执行参数,执行时间,重试次数等)
  • 测试计划管理(按业务模块划分)
  • 测试报告的多维度展示(计划维度,用例级别维度),失败截图,支持飞书发送指定业务负责人/用例作者

2、目标思维导图

三、框架对比和选型

  • Seleniume2e 测试鼻祖级的框架,有多种编程语言的版本。值得一提的是,它是基于 webdriver 而不是 webkit 内核实现的,所以,Selenium 的浏览器兼容性相对于其他浏览器要好很多。
  • PhantomJS:开创性的 headless(无头)测试框架,何为 headless?即没有 UI 界面的浏览器。headless 最大好处在于可以像单元测试一样,在命令行中跑 e2e 测试。 nightmare:一句话——加强版的 PhantomJS,相对于 PhantomJS,无论是开发还是运行效率都得到了很大的提升。
  • nightmare 还有个优点——它提供了一个 Chrome 插件 daydream,该插件可以通过录制屏幕,自动化生成测试代码,懒人福音。
  • nightwatch:名字和 nightmare 很像,但是完全不一样的一个 e2e 框架,使用 Node 调用 webdriver 实现。相对于 Selenium,开发和运行效率更高,最重要的是,迭代很活跃,这点,用开源产品的用户懂得都懂。
  • cypress:一个 e2e 测试框架,测试界面和文档做到极致的一个产品,推荐大家可以试一试。Cypress 是在 Mocha API 的基础上开发的一套开箱即用的 E2E 测试框架,并不依赖前端框架,也无需其他测试工具库,配置简单,并且提供了强大的 GUI 图形工具,可以自动截图录屏,实现时空旅行并在测试流程中 Debug 等等。总结一下,Cypress 的优点有:
    • 配置简单,可快速集成到现有项目中
    • 支持所有等级的测试(即前面所提到的 e2e 测试,集成测试,单元测试等)
    • 可以给每一步测试都生成快照,易于 Debug
    • 可以获取、操作 Web 页面里的所有 DOM 节点
    • 自动重试功能,Cypress 会在当前节点重试几次再断定测试失败
    • 易于集成到 CI 系统中
  • puppeteere2e 测试框架的集大成者,默认以 headless 模式运行,但是也可以通过配置变为 Chromium 运行。开发效率以及运行效率一流,最重要的是,它像 nightmare 一样,提供了测试代码生成插件——puppeteer-recorder

综上所述,如果考虑浏览器兼容性,使用 nightwatch,反之,选择 cypress 或者 puppeteer,如果需要 headless 或者自动化生成代码的功能,那就使用 puppeteer

一些大厂产物

腾讯:QTAF
https://github.com/Tencent/QTAF
据说支持mac,但是貌似没开源mac版本
平台支持

当前阶段选用selenium框架

四、特别的工具

1、过滑块功能

考虑平台IM登录有一个滑块验证,这块需要单独编写一个过滑块的工具类

基本思路

  1. 定位滑块
  2. 按下滑块
  3. 滑动一定的距离
  4. 抬起鼠标
driver.find_elements(by=By.ID,value="tab-KEY")[0].click()
time.sleep(2)
# 定位滑块
slider = driver.find_elements(by=By.CSS_SELECTOR, value='#nc_3_n1z')[0]
print(slider)
action = ActionChains(driver)
# 按下滑块
action.click_and_hold(slider)
# 滑动一定的偏移量(通过元素检查查看)
action.move_by_offset(308, 0)
# 释放鼠标
action.release()
# 执行上述action操作
action.perform()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

遇到问题

  • 移动,右滑要多少呢?右滑长度不好确认
    因为不同的屏幕分辨率,右滑的长度是不相同的,当前方案不做适配
    通过元素查找,找到滑块
    在这里插入图片描述
    当我们手动滑动的时候,这个移动距离会动态变化,我们只需要查看滑到最右边时候显示多少
    action.move_by_offset(308, 0)方法第一个参数就是右移的距离,单位px

绕过网页的反爬机制
在这里插入图片描述
通过浏览器驱动打开浏览器之后,滑块滑动之后会一直出现出error,经过问题排查

使用自动化软件打开浏览器会有特征码,可以通过在浏览器控制台上输入window.navigator.webdriver 查看

在这里插入图片描述

说明当前网站通过检测webdrive的返回值发现我们使用了自动化软件,这是网站的反爬常见手段。
因为现在解决办法就很明确了,需要修改我们的浏览器启动时的特征值

如何解除特征值

  • 通过execute_cdp_cmd方法解决
from selenium import webdriver

driver = webdriver.Chrome()

# 处理selenium中webdriver特征值
driver.execute_cdp_cmd(
    'Page.addScriptToEvaluateOnNewDocument',
    {
        'source':'Object.defineProperty(navigator,"webdriver",{get:()=>false})'
    }
)
driver.get('https://www.baidu.com')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

再次打开浏览器,查看特征值
在这里插入图片描述
再次执行,搞定。

2、OCR应用于UI自动化

http://www.juzicode.com/image-ocr-python-easyocr/
https://github.com/JaidedAI/EasyOCR

作为新式断言(主要识别文字,中英文)
选用OCR识别精度较高的EasyOCR

~/.EasyOCR
# 子文件名就叫model
  • 1
  • 2

直接调用使用

import easyocr
reader = easyocr.Reader(['ch_sim','en'])
result = reader.readtext('test.jpg')
for res in result:
     print(res)
  • 1
  • 2
  • 3
  • 4
  • 5

默认使用的是CPU,需要有要求用GPU,可以进行单独配置
在这里插入图片描述
在这里插入图片描述

五、UI 自动化用例编写规范

在这里插入图片描述

1、测试用例编写

  • PO模式
    • 测试用例:Testcases中不允许出现元素定位和元素操作;
    • TestDatas数据驱动
    • 测试对象:PageObjects & PageObjects元素行为
  • basepage封装
    日志/截图/异常/简化代码
  • 测试用例编写步骤
    • TestCase写出用例步骤
    • PageLocators元素定位
    • PageObjects元素行为编写
    • TestDatas准备测试数据
    • TestCases 填充用例的步骤/断言/前置
  • 测试用例管理 - 执行 (Pytest)
    • 筛选测试用例
    • 重试用例
    • 数据驱动
    • pytest命令行执行用例
    • 可拓展
      • 多线程/进程 xdist/parallel
      • selenium-grid分布式并行
      • 多浏览器切换
  • 测试报告输出:html、allure
  • 自动集成:Jenkins - master&slave模式

2、案例

编写商家客服登录case

from time import sleep

import pytest
from utils.du_log import du_loger   # 单例模式导入日志类
from pageobj.front_login_page import MsdFrontLoginPage
from pageobj.front_home_page import MsdFrontHomePage as HomePage
from testdata import msd_login_data as LD
from urllib.parse import urlparse

@pytest.mark.usefixtures("init")
class TestFrontLogin():
    # 正常场景 - 登录成功
    def test_login_success(self,init):
        du_loger.info("******* 登陆功能 - 正常场景用例:登陆成功 *******")
        # 清除缓存的数据
        init[1].clear_input()
        # 调用登陆页面的。登陆行为。
        init[1].login(LD.success_data["mobile"], LD.success_data["pwd"])
        sleep(1)

        assert HomePage(init[0]).check_avatar_exist()
        # 断言 - 首页当中,应该存在登陆者昵称元素。
        home_addr = urlparse(init[0].current_url).hostname
        print(home_addr)
        assert home_addr == urlparse(LD.success_data["check_url"]).hostname
 
@pytest.mark.parametrize("case", LD.wrong_datas)
def test_login_fail(self,case,init):
    du_loger.info("******* 登陆功能 - 异常场景用例:数据格式校验 - 用户名为空/密码为空/用户名格式不正确 *******")
    init[1].clear_input()
    # 调用登陆页面的。登陆行为。
    init[1].login(case["mobile"], case["pwd"])
    sleep(1)
    textIsExist = init[1].check_text_visible(case["check"], "商家工作台 - 登录页面 - 失败case - " + case["check"])
    if textIsExist:
        du_loger.warning("文本:" + case["check"] + " ---找不到")
    # 断言 - 全文只要找到相关文本就算通过
    assert textIsExist
    sleep(1)
  • 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
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

需要前置的初始化方法,比如,我们case中需要一些 页面对象

@pytest.fixture
def init(init_driver_function):
    du_loger.info("***** TestFrontLogin用例自己的 init 的前置  *****")
    msd_login_page = MsdFrontLoginPage(init_driver_function)
    yield init_driver_function,msd_login_page   # (driver对象,lp页面对象)
    du_loger.info("***** TestFrontLogin用例自己的 init 的后置  *****")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

那我们知道,drive对象不管什么case都是需要初始化的,这个方法为了公用,我们抽离到conftest中作为全局方法

# 测试用例级别

import pytest
from selenium import webdriver
from utils.du_log import du_loger
from testdata import common_datas
from common.dir_config import drive_dir
from pageobj.front_login_page import MsdFrontLoginPage

@pytest.fixture
def init_driver_function():
    """
    前置:打开浏览器,访问系统网址,去除浏览器特征值
    后置:退出浏览器。
    """
    du_loger.info("***** conftest.py共享的 init_driver 的前置  *****")
    driver = webdriver.Chrome(drive_dir + '/chromedriver_mac_M1')
    # 处理selenium中webdriver特征值
    driver.execute_cdp_cmd(
        'Page.addScriptToEvaluateOnNewDocument',
        {
            'source': 'Object.defineProperty(navigator,"webdriver",{get:()=>false})'
        }
    )
    driver.get(common_datas.msd_front_login)
    yield driver
    driver.quit()
    du_loger.info("***** conftest.py共享的 init_driver 的后置  *****")

"""
前置:打开浏览器,访问系统网址 + 登陆系统
后置:退出浏览器。
"""
@pytest.fixture(scope = "module")
def init_login():
    du_loger.info("***** conftest.py共享的 init_login 的前置  *****")
    driver = webdriver.Chrome(drive_dir + '/chromedriver_mac_M1')
    # 处理selenium中webdriver特征值
    driver.execute_cdp_cmd(
        'Page.addScriptToEvaluateOnNewDocument',
        {
            'source': 'Object.defineProperty(navigator,"webdriver",{get:()=>false})'
        }
    )
    driver.get(common_datas.msd_front_login)
    MsdFrontLoginPage(driver).login(common_datas.DUYU_ACCOUNT, common_datas.DUYU_PWD)
    yield driver  # 返回driver对象。
    driver.quit()
    du_loger.info("***** conftest.py共享的 init_login 的后置  *****")
  • 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
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

失败的结果展示:在这里插入图片描述
成功的结果展示:
在这里插入图片描述
配套的截图
在这里插入图片描述

六、其他资料

在这里插入图片描述
项目中开展web自动化需要考虑问题
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/94310
推荐阅读
相关标签
  

闽ICP备14008679号