导语: web自动化的存在问题有:前端ui经常变化,自动化运行速度慢,代码稳定性随着生产环境的变化变得更差。所以常规的web自动化不可避免的需要大量的人力成本来维护,每次需求变更的时候或者前端页面大重构的时候,自动化代码基本上要重写一遍了。针对上面的问题,尝试用自动点击遍历的方式,实现对web页面的自动点击遍历检查。
一. 背景
之前做过关于web前端自动化测试(基于QT4W框架/基于selenium框架),发现前端控件需要自己单独封装,在前端页面控件改版的时候,这套代码基本上就不能再用了,需要自己重新封装一遍。
对于已经开发完成转成测试中的需求,在测试环境中才呈现出完整的开发完成的ui控件,而如果这个时候再去做前端ui自动化,需要投入人力写代码,写代码又需要时间调试,整体下来的ROI并不理想,甚至比手工测试要占用更多的时间。
根据以下公式计算ROI(return on investment):
ROI=(手工测试成本-自动化测试成本)/自动化测试成本*100%
再看看需求一,在业务测试过程中,像一些比较重要的页面(课程详情页,首页,分类搜索页和机构主页等)经常会有一些前端ui的优化和调整,测试评估的时候一般只能评估到需求单中改动的前端ui改动,投入测试可能也只会验证这一块。
但是,对于这些很重要的页面,开发可能会自己改动一些小调整也没有自测,并且也没有知会到测试同学。这一块就会存在一些盲点bug。
再看看需求二,开发同学优化了前端代码,或者改了线上bug,或者加了一些js上报和定位日志,觉得没什么问题就免测发布了(之前就有一个开发在修改移动端的bug的时候加了一段调试代码,导致移动端版本发布后搜索跳机构主页必现空白)。很多问题防不胜防,所以前端自动遍历点击页面所有元素的需求就产生了。
二、技术方案
技术要点包括:获取浏览器驱动权限,模拟链接在真实浏览器中打开情况,获取页面HTML代码,遍历HTML代码中所有a标签元素,多进程加快遍历速度。
前三个问题可以用selenium框架实现,后面两个问题python有很多库支持实现。所以整体项目开发很快可以完成。 具体实现的思路如下图:
三、核心代码
3.1代码结构
1.项目结构:
onlineedulib -项目库文件夹
course_detail.py -封装页面操作方法
course_detail_element.py -元素封装文件
pool.py -进程池实现文件
onlineedutest -项目测试用例文件夹
course_detail.py -页面测试用例(for window system)
course_detail_linux.py -页面测试用例(for Linux system)
settings.py -配置文件
requirements.txt -库文件配置
README.md -操作说明文件
3.2用例模块
# -*- coding: utf-8 -*-
'''
课程详情页测试用例
'''
import sys
import os
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)
from selenium import webdriver # 导入selenium的浏览器驱动库
from webdriver_manager.chrome import ChromeDriverManager # 导入chrome浏览器驱动管理库
import time
from onlineedulib.course_detail import Course_Detail # 导入封装的方法库
from settings import URL, MAX_LEVEL # 导入settings中传进来的url和遍历层级
class Course_Detail_Test():
'''
方法功能:测试函数,程序入口
'''
def run_test(self):
start = time.time() # 获取当前时间
# 初始化一个浏览器对象,打开URL的页面
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get(URL)
# 初始化自己封装的类对象
detail = Course_Detail()
detail.get_page_a_label(driver, MAX_LEVEL) # 获取页面a标签
detail.deduplication() # 去重
detail.processing(driver) # 执行遍历点击a标签
driver.quit() # 关闭浏览器
end = time.time() # 获取当前时间
print(end - start) # 打印程序执行时间
if __name__ == '__main__':
Course_Detail_Test().run_test()
3.3获取HTML代码
使用selenium自带的能力,根据url在浏览器中打开后,可以拿到页面拿到HTML代码。
def get_page_a_label(self, driver = '', max_level = 1, traversal_level = 1):
# 获取页面HTML代码
body_element = driver.page_source
3.4正则查找a标签
导入正则查找的python库re模块,根据a标签特有的属性href来获取,&转码过来变为amp;需要替换回来,再对标签list做去重处理
#利用正则查找所有连接
import re
global cache_history_finall
link_list = re.findall(r"(?<=href=\").+?(?=\")|(?<=href=\').+?(?=\')", body_element)
#替换&转码过来的amp;,替换无效href链接
for url in link_list:
finall_link_list_sub1 = re.sub(r'amp;', "", url)
#去重
for item in finall_link_list:
if not item in finall_link:
finall_link.append(item)
3.5遍历存储
#遍历所有标签,存储所有的标签链接
for url in finall_link:
if traversal_level == 1:
cache_history_finall.append(url)
elif traversal_level <= max_level and url not in cache_history_finall:
cache_history_finall.append(url)
print 'traversal_level:' + str(traversal_level) + ' ' + str(len(cache_history_finall)) + ' url
3.6递归遍历
#递归实现循环遍历
for url in finall_link:
if traversal_level < max_level: # 递归遍历层级
self.exec_script('location.href="%s"' % url)
print 'traversal_level:' + str(traversal_level) + '+' + str(len(cache_history_finall)) + '+' + str(i) + ' url is:' + str(url)
self.get_page_a(max_level, traversal_level + 1, url)
四、实践
为了方便测试和做持续交付,我把脚本放到服务器上面,需要稍微改造一下代码实现在Linux中的Chrome执行selenium脚本。
1.设置遍历层级为1,开始执行获取页面a标签链接:
2.获取完成,工获取到410个a标签链接,执行时间11s。
3.断言完成,共断言410次,执行时间共426s。
五、总结
这里只贴了下关键模块的代码,具体代码实现细节可以看我GitHub工程:github.com/1405942836/…