web自动点击遍历(入口检查)
导语 web自动化的存在问题有:前端ui经常变化,自动化运行速度慢,代码稳定性随着生产环境的变化变得更差。所以常规的web自动化不可避免的需要大量的人力成本来维护,每次需求变更的时候或者前端页面大重构的时候,自动化代码基本上要重写一遍了。针对上面的问题,尝试用自动点击遍历的方式,实现对web页面的自动点击遍历检查。
一、背景
之前做过关于web前端自动化测试(基于QT4W框架),发现前端控件需要自己单独封装,在前端页面控件改版的时候,这套代码基本上就不能再用了,需要自己重新封装一遍。
对于已经开发完成转成测试中的需求,在测试环境中才呈现出完整的开发完成的ui控件,而如果这个时候再去做前端ui自动化,需要投入人力写代码,写代码又需要时间调试,整体下来的ROI并不理想,甚至比手工测试要占用更多的时间。
根据以下公式计算ROI(return on investment):
ROI=(手工测试成本-自动化测试成本)/自动化测试成本*100%
再看看需求一,在业务测试过程中,像一些比较重要的页面(课程详情页,首页,分类搜索页和机构主页等)经常会有一些前端ui的优化和调整,测试评估的时候一般只能评估到需求单中改动的前端ui改动,投入测试可能也只会验证这一块。
但是,对于这些很重要的页面,开发可能会自己改动一些小调整也没有自测,并且也没有知会到测试同学。这一块就会存在一些盲点bug。
再看看需求二,开发同学优化了前端代码,或者改了线上bug,或者加了一些js上报和定位日志,觉得没什么问题就免测发布了(之前就有一个开发在修改移动端的bug的时候加了一段调试代码,导致移动端版本发布后搜索跳机构主页必现空白)。很多问题防不胜防,所以前端自动遍历点击页面所有元素的需求就产生了。
二、技术方案
技术要点包括:获取浏览器驱动权限,模拟链接在真实浏览器中打开情况,获取页面HTML代码,遍历HTML代码中所有a标签元素,多进程加快遍历速度。
前三个问题可以用QT4W框架实现,后面两个问题python有很多库支持实现。所以整体项目开发很快可以完成。
具体实现的思路如下图:
三、核心代码
3.1代码结构
每个用例包括下面两个部分:onlineedulib中的course_detail和onlineedutest中的course_detail
3.2用例模块
onlineedutest中的course_detail代表用例初始化文件
from qt4w.browser.browser import Browser
from onlineedulib.testcase import OnlineEducationTestCase
from onlineedulib.course_detail import Course_Detail
from settings import URL, MAX_LEVEL # 导入settings中传进来的url和遍历层级
class EDU_Course_Detail_Test(OnlineEducationTestCase):
'''课程详情页测试用例
'''
owner = "xxx"
timeout = 30 # 超时时间30分钟
priority = OnlineEducationTestCase.EnumPriority.High
status = OnlineEducationTestCase.EnumStatus.Ready
def run_test(self):
self.startStep('1.设置信息并提交')
browser = Browser("Chrome") # 初始化Chrome浏览器
page = browser.open_url(URL, Course_Detail)
page.get_page_a(MAX_LEVEL) # 遍历层级可配置
if __name__ == '__main__':
EDU_Course_Detail_Test().debug_run()
3.3获取HTML代码
使用QT4W自带的能力,根据url在浏览器中打开后,可以拿到页面拿到HTML代码。
def get_page_a(self, max_level = 1, traversal_level = 1, a_url = ''):
body_element = self.control('body').inner_html
attributes = self.control('body').attributes
print attributes
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)