赞
踩
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自动化常见的验证点
web自动化框架常见的需求点
收益计算公式:
自动化的收益 = 迭代次数 * 全手动执行成本 - 首次自动化成本 - 维护次数 * 维护成本
每次版本迭代维护成本衡量:
维护用例占比及维护成本耗时
新增用例占比及编写成本耗时
提高回归测试效率,节省人工测试成本。
e2e
测试鼻祖级的框架,有多种编程语言的版本。值得一提的是,它是基于 webdriver
而不是 webkit
内核实现的,所以,Selenium
的浏览器兼容性相对于其他浏览器要好很多。headless
(无头)测试框架,何为 headless
?即没有 UI 界面的浏览器。headless
最大好处在于可以像单元测试一样,在命令行中跑 e2e
测试。 nightmare
:一句话——加强版的 PhantomJS
,相对于 PhantomJS
,无论是开发还是运行效率都得到了很大的提升。nightmare
还有个优点——它提供了一个 Chrome
插件 daydream,该插件可以通过录制屏幕,自动化生成测试代码,懒人福音。nightmare
很像,但是完全不一样的一个 e2e
框架,使用 Node
调用 webdriver
实现。相对于 Selenium
,开发和运行效率更高,最重要的是,迭代很活跃,这点,用开源产品的用户懂得都懂。e2e
测试框架,测试界面和文档做到极致的一个产品,推荐大家可以试一试。Cypress 是在 Mocha API
的基础上开发的一套开箱即用的 E2E
测试框架,并不依赖前端框架,也无需其他测试工具库,配置简单,并且提供了强大的 GUI
图形工具,可以自动截图录屏,实现时空旅行并在测试流程中 Debug
等等。总结一下,Cypress
的优点有:
e2e
测试,集成测试,单元测试等)Debug
DOM
节点Cypress
会在当前节点重试几次再断定测试失败CI
系统中e2e
测试框架的集大成者,默认以 headless
模式运行,但是也可以通过配置变为 Chromium
运行。开发效率以及运行效率一流,最重要的是,它像 nightmare
一样,提供了测试代码生成插件——puppeteer-recorder
。综上所述,如果考虑浏览器兼容性,使用 nightwatch,反之,选择 cypress 或者 puppeteer,如果需要 headless
或者自动化生成代码的功能,那就使用 puppeteer。
腾讯:QTAF
https://github.com/Tencent/QTAF
据说支持mac,但是貌似没开源mac版本
平台支持
Native
, Hybrid
, 移动端Web应用,还在维护,只是换了repo地址macaca
,面向数据的,集mock
和测试一体的框架Macaca
封装,全平台支持当前阶段选用selenium
框架
考虑平台IM登录有一个滑块验证,这块需要单独编写一个过滑块的工具类
基本思路
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()
遇到问题
绕过网页的反爬机制
通过浏览器驱动打开浏览器之后,滑块滑动之后会一直出现出error,经过问题排查
使用自动化软件打开浏览器会有特征码,可以通过在浏览器控制台上输入window.navigator.webdriver 查看
说明当前网站通过检测webdrive的返回值发现我们使用了自动化软件,这是网站的反爬常见手段。
因为现在解决办法就很明确了,需要修改我们的浏览器启动时的特征值
如何解除特征值
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')
再次打开浏览器,查看特征值
再次执行,搞定。
http://www.juzicode.com/image-ocr-python-easyocr/
https://github.com/JaidedAI/EasyOCR
作为新式断言(主要识别文字,中英文)
选用OCR识别精度较高的EasyOCR
~/.EasyOCR
# 子文件名就叫model
直接调用使用
import easyocr
reader = easyocr.Reader(['ch_sim','en'])
result = reader.readtext('test.jpg')
for res in result:
print(res)
默认使用的是CPU,需要有要求用GPU,可以进行单独配置
编写商家客服登录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)
需要前置的初始化方法,比如,我们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 的后置 *****")
那我们知道,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 的后置 *****")
失败的结果展示:
成功的结果展示:
配套的截图
项目中开展web自动化需要考虑问题
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。