# 基于行为驱动的自动化测试
# 背景
有多个平台的小程序渠道,测试还是传统的手工测试,一次改动测试回归成本很高,效率相对较低。
同时本身业务迭代还是很频繁,传统的自动化测试方案,维护UI脚本本身成本也很高,对测试人员本身的要求也不一样。
# 技术选型
由当下情况得出的核心诉求:
1. UI 元素不通过脚本获取,降低需要频繁变更的可能
2. 即适合测试人员也适合研发人员,可以支持和当前系统结合
3. 多端的支持,web,android,ios
条件1,3 就抛弃了现在大部分依赖xpath的自动化框架
工具 | 优点 | 缺点 |
---|---|---|
Appium | 编写测试脚本时间较短,可预装,支持多种语言以及可跨平台进行,由谷歌社区支持和维护。 | 不能处理flash和web组件,由于不支持iOS设备,当自动化测试同时覆盖Android和iOS的情况时,测试会被中断,Appium server桌面应用程序的发布常常不稳定,在旧设备上变得很慢。 |
Robotium | 自动化app,Android自动跟随,简单易学的教程,且不需要访问源代码。 | 仅支持Android4.1及以上,不支持脚本记录,不支持web视图,不能跨多个app。 |
UIAutomation | Android自动化测试工具类,通过脚本开发,由于运行绑定到GUI组件,相比Appium,它的测试执行更快更强大。 | 对测试人员来说编写代码能力要求较高,需要对Android相关知识有一定的了解。 |
Instrumentation | 可以模拟按键按下,抬起,屏幕点击,滚动事件等,第三方支付集成了基于云计算的测试管理。 | 仅支持Android |
条件2就抛弃现有大部分rpa工具,目前已有的rpa应用都偏向低代码的形式,更偏向业务人员
# 核心思路
airtest(处理移动端) + rpa-python(处理桌面端)
- 实现一个dsl解析器(dsl参考simplerpa (opens new window))
- 用rpa-python重写airtest-selenium插件(存在兼容性问题,编辑器无法执行)
- 用chatgpt 将 Cucumber 测试用例转成 yaml配置文件
- 用chatgpt 将 Cucumber 测试用例转成 airtest 代码,通过airtest编辑器做UI元素调整
Cucumber是一个测试框架,可以用来建立软件开发人员和业务经理之间沟通的渠道。测试脚本基于行为驱动开发(BDD)风格词语编写,如“假如”,“当”、“那么”,或在英文中的Given, When, Then,这样任何非专业人员都能理解。然后将测试用例放入覆盖一个或多个测试场景的剧本(gherkin)文件中。 Cucumber将测试解释成指定的编程语言,然后执行。典型的用法是使用Selenium驱动浏览器中进行测试。
# 屏幕自动化任务
- 检查当前桌面上是否显示了需要的页面(比如查看特定位置的图像,或者比对OCR识别出的文字)
- 如果确实是,就收集一些文字或图像的信息(这一步未必会有,要看具体任务类型,有些自动化只要把页面流程走通就可以)
- 查找页面上特定的控件(比如某个按钮),对它进行操作(如点击)
- 软件元素识别
- 获取鼠标所在屏幕坐标
- 获取鼠标位置的窗体控件
- 获取控件类型
from pywinauto import Desktop
# 获取当前鼠标位置
mouse_pos = Desktop().mouse.position()
# 获取鼠标位置的窗体控件
control = Desktop().from_point(*mouse_pos)
# 获取控件类型
control_type = control.friendly_class_name()
print('Control type:', control_type)
在 Mac 上,获取鼠标位置的窗体控件和控件类型是一个复杂的任务,因为它需要使用到底层的 Accessibility API。Python 并没有直接提供这样的功能,但是你可以使用一些第三方库来实现。
其中一个可能的选择是 pyobjc
库,它提供了 Python 到 Objective-C 的桥接,可以让你在 Python 中使用 Cocoa 和其他 Mac OS X 的原生 API。
以下是一个使用 pyobjc
来获取鼠标位置的窗体控件和控件类型的基本示例:
from Quartz import CGWindowListCopyWindowInfo, kCGWindowListOptionOnScreenOnly, kCGNullWindowID
from AppKit import NSWorkspace
from PyObjCTools import Conversion
import time
def get_active_window():
# 获取当前活动的窗口
active_app = NSWorkspace.sharedWorkspace().activeApplication()
for window in CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID):
# 转换 Objective-C 的 NSDictionary 到 Python 的字典
window = Conversion.pythonCollectionFromPropertyList(window)
if window['kCGWindowOwnerName'] == active_app['NSApplicationName']:
return window
while True:
window = get_active_window()
if window:
print('Window name:', window.get('kCGWindowName', 'Unknown'))
print('Window owner:', window['kCGWindowOwnerName'])
time.sleep(1)
这个脚本会每秒打印一次当前活动窗口的名称和所有者。然而,这只是获取窗口信息的一部分,获取鼠标位置的窗体控件和控件类型可能需要更深入的使用 Accessibility API,这可能需要更多的 Objective-C 或 Swift 的知识和经验。 请注意,使用 Accessibility API 可能需要用户授予你的应用特定的权限。在 "System Preferences" -> "Security & Privacy" -> "Privacy" -> "Accessibility" 中添加你的应用或脚本,以允许它控制你的电脑。
- 浏览器元素识别
document.addEventListener('mousemove', function (event) {
// 获取鼠标所在的屏幕坐标
var x = event.clientX;
var y = event.clientY;
console.log('Mouse coordinates:', x, y);
// 获取鼠标位置的元素
var element = document.elementFromPoint(x, y);
// 获取元素类型
var elementType = element.tagName;
console.log('Element type:', elementType);
});
- 图像识别定位(opencv)
- 屏幕截取
- 匹配模版
- 获取元素位置
- 图像识别的准确性和稳定性相对较低,且受到环境因素的影响较大,例如屏幕分辨率、颜色设置等
import cv2
import numpy as np
from PIL import ImageGrab
# 截取屏幕图像
screen = np.array(ImageGrab.grab())
# 读取模板
template = cv2.imread('template.png', 0)
# 转换颜色空间
screen_gray = cv2.cvtColor(screen, cv2.COLOR_BGR2GRAY)
# 匹配模板
res = cv2.matchTemplate(screen_gray, template, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
# 如果匹配度大于 80%
if max_val > 0.8:
print('Element found at', max_loc)
- 跳转到下一个页面,回到步骤1,反复循环,直到最终页面出现
← 分支管理规范CI部署优化 素材合成服务 →