学好selenium工具,能实现你想得到的所有事情

news2024/11/15 15:58:16

文章目录

      • 一、介绍背景
      • 二、开发与实现
        • 2.1、部署开发环境
        • 2.2、开始码代码<demo只为提供思路>
        • 2.3、思路分析
        • 2.4、难点解析
      • 三、总结

一、介绍背景

情况是这样的:某段时间之前,开发想找我用ui自动化帮他们实现一个功能:在系统某些时候生成报告的时候会failed,但是又不再重新生成,因此需要人工edit再次submit才能生成,原因png是由当前html页面生成。但是作为测试的我有一个疑惑?开始不是常用定时任务或是失败重试吗?怎么不这样做呢?或者有其他办法使之成功呢?然后开发自己优化了一下,就默默的成功了,这事儿就算过去了,不曾想几天前又复活了,需要我来协助,然后我问,这玩意儿不能使用接口去完成吗?开发解释:不能,why?原因是html转png:前端拿到接口响应数据,动态绘制html,然后再生成png。那么问题来了:为什么会失败?什么情况下会失败呢?

二、开发与实现

作者的python开发环境那是有好几套,接口、ui自动化的环境那是现成的,拿来即用,这里仅用来演示步骤。

2.1、部署开发环境

下载python安装包,一路默认,会自动加入path环境变量;
pip工具安装:pip install selenium
再下载对应chromedriver浏览器驱动:https://chromedriver.storage.googleapis.com/index.html

2.2、开始码代码<demo只为提供思路>

又因为作者是有比较系统的ui自动化测试思想,首先是po模式,但是这个需求是一次性的,所以并不想把它复杂化<相对线性脚本>,本着开发效率出发<不曾想也花了一天的时间,主要耗时在调试脚本>

#!/bin/python3
# -*-coding: utf-8 -*-
# 编码在linux环境下才能识别中文

import json
import logging
from time import sleep
import time

import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait


# 日志系统
log_format = '%(asctime)s - %(levelname)s - %(message)s'
logging.basicConfig(filename="scoreSys.log", filemode='a+', format=log_format, level=logging.DEBUG)

options = webdriver.ChromeOptions()
#options.add_argument('--disable-gpu')
#options.add_argument('--headless')
#options.add_argument('--no-sandbox')
#options.add_argument('--disable-dev-shm-usage')

# 初始化页面对象
driver = webdriver.Chrome(executable_path="../chromedriver.exe", options=options)


"""打开浏览器"""
# https://score.ieltsbro.com/
logging.info(">>>>>>>>>>>>>>>>>打开口语报告系统<<<<<<<<<<<<<<<<<<<<<<")
#     driver.get("https://xxx.xxx.com/home")
driver.get("https://uat.xxx.xxx.com/xxx/home")
driver.maximize_window()
driver.implicitly_wait(10)

# 登录页,页面元素
account_input = (By.XPATH, "//input[@placeholder='Email']")
passwd_input = (By.XPATH, "//input[@placeholder='Password']")
verify_code = (By.XPATH, "//input[@placeholder='Code']")
signIn_btn = (By.XPATH, "//span[text()=' Sign In ']")

# 登录的操作步骤
driver.find_element(*account_input).send_keys("xxx.x@hcp.tech")
driver.find_element(*passwd_input).send_keys("xxxxx")
driver.find_element(*verify_code).send_keys("1234")
driver.find_element(*signIn_btn).click()
logging.info(">>>>>>>>>>>>>>>>>用户登录口语报告系统<<<<<<<<<<<<<<<<<<<<<<")
sleep(1)


# ui登录后获取请求头中token属性
headers = {"content-type":"application/json"}
# 登录系统后用户名元素
account_text = (By.CSS_SELECTOR, ".user_name")
change_passwd = (By.CSS_SELECTOR, ".pwdBtn")

"""检查登录状态"""
account_info = driver.find_element(*account_text).text
logging.info(">>>>>>>>>>>>>>>>>检查用户是否成功登录系统<<<<<<<<<<<<<<<<<<<<<<")
try:
    assert account_info == "xxxx", "断言失败"
except:
    logging.info(">>>>>>>>>>>>>>>>>用户:{},登录失败!!!<<<<<<<<<<<<<<<<<<<<<<".format(account_info))
else:
    logging.info(">>>>>>>>>>>>>>>>>用户:{},登录成功!!!<<<<<<<<<<<<<<<<<<<<<<".format(account_info))
    userInfo = json.loads(driver.execute_script('return localStorage.getItem("userInfo");'))
    v = json.loads(userInfo.get("v"))
    token = v.get("token")
    headers["token"] = token

# 搜索条件
select_box = (By.XPATH, "//input[@placeholder='Report status']")
select_input = (By.XPATH, "//span[text()='Failed']")
select_btn = (By.XPATH, "//span[text()='Search']")

"""输入fail点击查询"""
# 查询操作
driver.find_element(*select_box).click()
sleep(1)
driver.find_element(*select_input).click()
driver.find_element(*select_btn).click()


# 列表是否有失败状态的
fail_status = "//td//div[text()='Fail']"
# 找到失败的edit按钮
edit_btn = (By.XPATH, "{}/../parent::td[1]//following-sibling::td//span[text()='Edit']".format(fail_status))
submit_selector = (By.XPATH, "//div[contains(text(),'Submit')]")

"""提交报告"""
# 首先按fail条件查询
click_search()
# 找到更多需要edit的按钮
status_eles = driver.find_elements(*edit_btn)
ele_nums = len(status_eles) # 页面元素找到元素不唯一
# 接口获取fail总数及id列表
nums, fail_li = get_fail_nums()

count = 0    # 记录真实补偿次数
success_li = []    # 记录成功补偿报告id
while ele_nums > 0:
    status_eles = driver.find_elements(*edit_btn)
    try:
        for ele in status_eles:
            clicked = ele.is_displayed() # 因为找到元素不唯一,需要判断元素是否显示
            if clicked:
                ele.click()
                driver.find_element(*submit_selector).click()    # 提交
                success_li.append(driver.current_url.split("=")[-1])
                #等待提交之后跳转的页面元素是否出现
                WebDriverWait(driver, 50).until(EC.presence_of_element_located(change_passwd)) 
                count += 1
    except:
        ele_nums -= 1
    else:
        ele_nums -= 1
    finally:
        click_search() # 每次需重新查询
            
driver.quit()

2.3、思路分析

  1. 第一步,开发针对我的特殊帐号去除验证码登录,<毕竟实现验证码登录成本还是有的>
  2. 首页增加报告查询条件:success or failed;
  3. 需要发送钉钉通知<这是后面实现>
  4. 操作流程:登录-检查登录状态-查询fail条件的数据-进入编辑页面-点击submit-再重新查询fail条件-如有继续edit-submit,如初反复直到没有fail的数据为止-关闭浏览器

2.4、难点解析

在selenium做ui自动化的时候,最难的不是实现某个功能代码块,而是定位元素的表达式,但是页面又不全是id、name等唯一元素,更多是需要写css_selector\xpath表达式;

  • html的结果页是个table,那么在根据fail失败元素同级找到它的edit,这个如下所示;是不是比较懵圈
# 列表是否有失败状态的
fail_status = "//td//div[text()='Fail']"
# 找到失败的edit按钮
edit_btn = (By.XPATH, "{}/../parent::td[1]//following-sibling::td//span[text()='Edit']".format(fail_status))
# 解释下上面的表达式:/.. 表示查找上级,parent::表示父级,following-sibling::平级中的下级
  • 其实实现之后并不需要如此,因为是先按fail条件查询,那么剩下就是fail,直接找edit即可。
  • 难点是ui+接口的结合;因为上述代码之初,在找到需要重新submit的报告,数目不正确,因为元素重复不唯一<每个元素都有显示和隐藏>,
clicked = ele.is_displayed() # 因为找到元素不唯一,需要判断元素是否显示
  • 所以想通过接口来确定真正fail的条数,所以先ui登录,获取token传递给接口请求,
    在这里插入图片描述
# 这是个新技能点,每次尝试不同的需求,总会遇到不同的问题,然后找到解决方案
userInfo = json.loads(driver.execute_script('return localStorage.getItem("userInfo");')) # 这个userInfo是key,而不是直接叫token
从demo中可以看出作者的po思想,将定位元素的标识单独提取出来保存,没直接放在方法里
  • 从demo中可以看出作者的po思想,将定位元素的标识单独提取出来保存,没直接放在方法里

这里提醒所有重试UI自动化测试的工作者:写代码不是为了去实现某个功能;而是提炼思想,解决思想问题,因为功能问题早晚都有解决办法,而解决问题的思想没有,那就真的没有了。

三、总结

条条大路通罗马,不是所有问题都只有一种解决办法,而是任何问题都会有解决办法。解决问题的思路很重要,思维、眼界需要打开,会有不一样的风景,感谢您的收看,咱们下次再见!

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

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

相关文章

[附源码]计算机毕业设计大学生心理健康测评系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

零基础CSS入门教程(17)——内边距

本章目录1.任务目标2.默认情况3.有内边距4.小结1.任务目标 上一篇介绍了外边距&#xff0c;也就是元素跟相邻元素的距离。 本篇来介绍内边距&#xff0c;顾名思义&#xff0c;内边距是指的元素内部的内容&#xff0c;与元素的边的距离 2.默认情况 <!DOCTYPE html> <…

Velero 系列文章(一):基础

概述 Velero 是一个开源工具&#xff0c;可以安全地备份和还原&#xff0c;执行灾难恢复以及迁移 Kubernetes 集群资源和持久卷。 灾难恢复 Velero 可以在基础架构丢失&#xff0c;数据损坏和/或服务中断的情况下&#xff0c;减少恢复时间。 数据迁移 Velero 通过轻松地将 …

使用VictoriaMetrics 对Prometheus的数据进行分布式存储

前言 Prometheus 就是一个很好的时序数据库&#xff0c;对于监控数据量没有超过千万级的 情况下没必要进行分布式存储。一般的监控数据存3个月以内即可&#xff0c;所以数据量并不会很大。 并且生产环境可以搞多个Proms数据源在Grafana中做统一的告警。并且在时序数据库的排名…

windows安装minikube

由于学习的需要&#xff0c;需要在windows上搭建一套可以使用的k8s学习用&#xff0c;最后选择了minikube这个安装k8s&#xff0c;本博客介绍了minikube的安装步骤&#xff0c;详细命令以及截图 1、首先是本机windows安装docker&#xff0c;具体可以参考这个 win10安装docker…

奥曲肽-葡聚糖-亲和索的偶联物TOC-Dx40-Av)|紫杉醇-DHA-右旋糖酐偶联聚合物

中文名称&#xff1a;奥曲肽-葡聚糖-亲和索的偶联物 英文名称&#xff1a;TOC-Dx40-Av 纯度&#xff1a;95% 存储条件&#xff1a;-20C&#xff0c;避光&#xff0c;避湿 外观:固体或粘性液体 包装&#xff1a;瓶装/袋装 溶解性&#xff1a;溶于大部分有机溶剂&#xff0…

GC 算法总结_java培训

1.标记清除压缩(Mark-Sweep-Compact) 标记清除、标记压缩的结合使用 原理java培训GC 算法总结 2.算法总结 内存效率&#xff1a;复制算法>标记清除算法>标记整理算法&#xff08;此处的效率只是简单的对比时间复杂度&#xff0c;实际情况不一定如此&#xff09;。 内…

城市云灾备,为业务连续性保驾护航

摘要&#xff1a;华为云作为中国政务云基础设施领域领导者&#xff0c;基于华为公有云技术架构的政务云平台&#xff0c;具备领先的云灾备技术实力&#xff0c;支持IaaS、PaaS等云服务云原生灾备能力。本文分享自华为云社区《城市云灾备&#xff0c;为业务连续性保驾护航》&…

Delphi Base64 的“坑”

使用 Delphi 原生的Base64编码&#xff08;System.NetEncoding 单元&#xff09; &#xff0c;编码后的字符串每隔76个字符会增加一个回车换行&#xff08;#13#10&#xff09;&#xff0c;这样就导致和其他语言对接的时候出现问题&#xff0c;特别是Base64以后再进行签名&#…

元学习:IVIF:输入不同分辨率,输出任意分辨率

Different Input Resolutions and Arbitrary Output Resolution: A Meta Learning-Based Deep Framework for Infrared and Visible Image Fusion &#xff08;不同的输入分辨率和任意输出分辨率: 基于元学习的红外和可见光图像融合深度框架&#xff09; 在本文中&#xff0c…

Web大学生网页作业成品——城市环卫管理系统后台模板(HTML+CSS+JavaScript)

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

浏览器中的音视频知识总结v1.0(工作中需要和视频打交道必看)

视频是什么 视频&#xff0c;其实就是一系列连续播放的图片&#xff0c;如果1s钟播放24张图片&#xff0c;那么人眼看到的就不再是一张张独立的图片&#xff0c;而是动起来的画面。其中一张图片称为一帧&#xff0c;1s播放的图片数称为帧率。常见的帧率有24帧/s&#xff0c;30帧…

[附源码]JAVA毕业设计西安市城市绿地管理系统(系统+LW)

[附源码]JAVA毕业设计西安市城市绿地管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项…

Linux网络原理及编程(3)——第十三节 HTTPS

我们本文主要来介绍https&#xff0c;主要来介绍https的加密原理。 大家应该都知道http和https的区别&#xff0c;区别很简单&#xff0c;主要就是在https是采用了加密协议的&#xff0c;而http完全是在网络上裸奔的。而我们现在几乎所有的连接都用的是https 我们首先需要明白…

Flink学习26:触发器

触发器 作用&#xff1a;决定何时&#xff0c;触发窗口计算函数&#xff0c;开始计算 每个窗口都有一个默认触发器&#xff0c;也可以自定义触发器。 自定义触发器 示例1&#xff1a; 当流中元素达到5个以后&#xff0c;触发窗口计算。 import org.apache.flink.api.common.fu…

基于数据挖掘算法的服装销售平台的设计与实现(spring+spring mvc+mybatis+mysql+maven)

目 录 摘 要 I Abstract II 目 录 III 1 绪论 1 1.1 研究背景 1 1.2 研究意义 2 1.3 国内外研究现状 2 2 相关理论和开发工具 4 2.1 数据挖掘简述 4 2.2 相关数据挖掘算法概述 4 2.2.1关联规则 4 2.2.2 聚类算法 5 2.2.3 分类算法 5 2.3 文本挖掘概述 6 2.4 开发工具 7 3系统需…

5-10人的创业团队,怎么在半个月内上线一款新产品?

5~10 人的小微型创业团队&#xff0c;需不需要专业的研发协作工具&#xff1f; 随着生产力工具的价值获得更广泛的认可&#xff0c;越来越多观点认为&#xff0c;组织结构精简、业务尚未成熟的小微型团队应该尽早引入专业研发协作工具&#xff0c;完成核心竞争力的蜕变。 猴子…

2022 计网复习应用题【太原理工大学】

最后一道大题 —— 应用题&#xff0c;有以下几个考点&#xff0c;原理无需懂会算就行&#xff0c;15 分 拿 10 分不难&#xff0c;建议看一下。>_< 目录 1. 判断 IP 地址类型 2. 通过 IP 地址求子网掩码 3. 求网络地址和广播地址 4. 求主机号和可用 IP 5. 双绞线的…

【Spring】一文带你搞懂Spring IOC容器

前言 本文为 【Spring】Spring IOC容器 相关知识&#xff0c;首先为大家介绍Spring IOC相关的名词概念&#xff0c;对Spring IOC进行概述&#xff0c;然后具体为大家介绍配置元数据&#xff0c;容器实例化与使用等Spring IOC相关详尽内容~ &#x1f4cc;博主主页&#xff1a;小…

【Python毕业设计】Python基于面向对象+tkinter打造学生信息管理系统 | 附源码

前言 halo&#xff0c;包子们上午好 很多学计算机的小伙伴应该都知道&#xff0c;毕业设计是一个头疼的东西 今天的话小编这边给大家准备好了一个Python基于面向对象tkinter打造学生信息管理系统 这不是毕业设计必备项目 说实话操作起来还是有那么一点点的难度的&#xff0c;但…