第二节-UI自动化测试-项目方案调研-新方案的设计

新方案的设计

上文回顾

一、通用的方案概要

在这里插入图片描述

自动化的实施,基本都是覆盖用例、调度执行、结果检测、结果上报。什么时候通过什么途径执行什么场景用例,执行的检测结果是什么,测试结果需要同步到哪里。
自动化的实施有很多需要挑战的内容:就如脚本的稳定性、脚本编写的效率、脚本的维护成本、断言的有效性…。在此之上我理解最难的挑战还是怎么让团队接受自动化实施的价值。

二、方案拆解(基础部分:事件能力、最小单元、测试用例)

为了加快节奏,本节的拆解我计划介绍的是最基层的内容,不包含CI/CD模块,在后续的章节中会继续升级。

①事件能力

①.①概述

最小单元事件设计的基准为单个最小函数,这里的函数为关键字函数,就如点击操作、输入操作、滑动操作。在此我觉得上一段简单的demo代码更加容易清楚它的定位:

    def click(self,coor :tuple,msg=None):
        """
        坐标点击事件
        :param coor: 元组坐标(x,y)
        :param msg:
        :return:
        """
        touch(coor)

在这里插入图片描述

②单元模块

②.①概述

本次方案以.yml文件配置代替实例化的单元模块,后续可规划以web界面、GUI界面呈现编排,其用意也是想抽象出来,以便单元模块公共化,可以支撑脚本用例的快速组装。本设计的单元模块的与PageObject类似,但也支持更加定制的跨页面特殊处理定制。
单元模块案例:在登录页面中包含账号输入框、密码输入框、登录按钮,此场景可以设计单元模块包含:
1.一整个用户的登录流程
2.单个输入框的操作、单个按钮的操作

②.②单元模块的设计设想及场景

单元模块的支持依赖事件能力:如上文①中的各类事件。
在我的构想中一个单元模块的设计步骤如下(以输入登录账号为demo):
#step-1:识别输入框位置,获得输入框的中心坐标(输入框通过文本识别,没有文案可以精准识别,可能无法通过文字识别获得,可以通过训练自己的ocr实验,对输入框进行打标标记。在我的专题文章中有关于自己训练ocr模型的介绍,具体可以参考训练自己的ocr模型(直跳)),当然还有别的方案,后续会陆续介绍。
#step-2:点击识别的中心位置

#step-3:操作输入事件

在这里插入图片描述

③用例组装

用例组装的核心就是将yml配置解析完成后进行动态引包,通过关键字驱动将对应的函数进行调用执行。在不做配置化的时候,testcase代码大概是这样:

class LuckySign:

    def __init__(self):
        self.openMiniProgeamElem = OpenMiniProgeamElem()
        self.homeElem = HomeElem()
        self.personalCenterElem = PersonalCenterElem()
        self.settingElem = SettingElem()
        self.loginElem = LoginElem()
        self.smallXingXingElem =SmallXingXingElem()
        self.signElem = SignElem()
        self.wechatElem = WechatElem()

    def initConsumerAccount(self):
        self.wechatElem.restartWechat()
        self.loginElem.initConsumerAccount()


    def doSign(self):
        # 执行签到
        self.homeElem.openPersonalCenter()
        # 处理个人中心引导
        self.personalCenterElem.guideOperation()
        # 弹窗处理
        self.personalCenterElem.checkWindowsAndClose()
        # 打开签到页面
        self.personalCenterElem.openSmallXingXing()
        # 签到页面渲染校验
        self.signElem.checkSignPageLoad()
        # 签到操作
        self.signElem.clickSignBtn()
        # 防止订阅
        self.personalCenterElem.subScribe()
        # 签到明细校验
        self.signElem.openSignDetailed()

    def dotest(self):
        self.personalCenterElem.guideOperation()

luckySign = LuckySign()
luckySign.initConsumerAccount()
luckySign.doSign()

现在我们做的是将一个个的step转换成了yml配置节点。其核心就是动态引入,动态执行。将事件函数的路径与关键字做哈希映射。如下:

import importlib
# 定义关键字和对应的函数
keywords = {
    'keyword1': 'ymlFunc.func_a',
    'keyword2': 'ymlFunc.func_b',
}
def func_a():
    print('这是一个函数:func_a')
def func_b():
    print('这是一个函数:func_b')
# 测试调用
def call_function(keyword):
    func_name = keywords.get(keyword)
    if func_name:
        module_name, function_name = func_name.rsplit('.', 1)
        module = importlib.import_module(module_name)
        func = getattr(module, function_name)
        func()
    else:
        print(f"Function not found for keyword: {keyword}")

call_function('keyword1')

改造一下上面动态引入的用法,不再去动态引包,直接继承函数封装类,动态调用父类的函数。
关于动态引包可能存在的性能问题说明:
动态引入开始的用意是支持配置文件函数动态调用,模块在实际需要时才导入,可以减少启动时间和内存占用,但每次动态导入都需要进行模块的查找和加载,可能会增加一些性能开销以及运行时延迟。在我们的项目中存在一个case反复调用某个事件,难道每次都去动态引包一次?如果这样操作的话,可能会产生不必要的开销,因而引入了变量缓存、继承父类解决这个问题。也考虑过静态函数,但是为了后续扩展性,现状暂时不做该处理。

class KeyFunc:
    def printTest1(self, name):
        print(name)
    def printTest2(self, name):
        print(name)

class Muban(KeyFunc):
    def __init__(self):
        self.cache={}
    def runParentFunc(self):
        ## 模拟读取配置
        key_method={
            'step1':['printTest1','value1'],
            'step2':['printTest1','value2'],
            'step3':['printTest1', 'value3'],
            'step4':['printTest1', 'value4'],
            'step5':['printTest2', 'value5'],
            'step6':['printTest2', 'value6']
        }
        for key,value in key_method.items():
            method = self.cache.get(value[0])
            if callable(method):
                print('进入了缓存')
                method(value[1])
            else:
                method = getattr(self, value[0])
                self.cache[value[0]] = method
                method(value[1])

Muban().runParentFunc()

在这里插入图片描述

三、本节结束语

本节就基础部分:事件能力、最小单元、测试用例进行了介绍,初期设计可能还比较粗糙,后面的章节中会不断地打磨、完善。相信任何有意义的事情都不是一蹴而就,需要循循渐进。

不同阶段的认知都不一样,在现在前面几个章节中,重点就带大家一起看看基础设计,在我的UI自动化实施的生涯中,期间也遇到了不少的坎坷、本专题重点就是介绍我在不断打磨后的结果。
后续的章节中会将CI/CD、如果推广UI自动化、如果识别UI自动化的投入回报率(怎么辨别UI自动化的实施是有意义)的方法向大家介绍。

参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hi,heng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值