其他测试框架 一次基于实际项目的测试框架优化经验与总结

饶凯 · 2023年09月02日 · 最后由 饶凯 回复于 2023年10月07日 · 5970 次阅读

从去年末开始,除了日常的测试任务外,还被分配全权负责一个端到端 UI 自动化项目,因此这是一个从 0 开始构建起 APP ->服务端 ->硬件执行端项目的总结文,主要为了记录这个项目的变化,以及从中的收获,希望也能对大家有所帮助

1.跑起来

第一阶段,经历了一周的准备和了解之后,确立的首要的目标就是迅速跑通一个冒烟,所以紧赶慢赶终于写好了一个冒烟流程的 case。

1.测试框架选型:pytest,将不同操作封装在不同层

2.APP 测试工具:基于 Uiautomator2 封装的 UI 测试框架

3.将公共数据放到统一的 py 文件管理,数据读取方法抽提到一个独立的类,同时这个类也放置其他的公共操作方法

具体结构如下

2.多起来

第一条冒烟用例跑过了,但是随着后续增加其他类型的用例,每写一个用例,就要多加一个 py 文件,然后把 setup\teardown\test 方法都写一遍,中间存在大量的冗余代码,而且稍有改动,跟着要改的地方很多。因此,想到了要对结构进行细化分层,主要改动如下:

  1. 采用 PO 模式,以页面维度,将页面操作封装起来,方便调用和组合

  2. 抽提所有测试执行的共同点,为一个测试基类,测试类继承基类然后进行扩展,方便维护和优化

  3. 将公共方法的维度细化,将涉及移动设备操作、接口通用请求操作单独拆分为不同文件,方便区分和调用

这一时间结构如下:

3.方便管理

经过 1、2 步骤,现在对于多个页面的多个功能的操作,都可以有效组织起来,而且对于单个页面或者功能的改动对其他页面、功能的影响也达到减少

但是,新的问题又出现了:一个页面可能存在多个用例执行的动作模式都一样的(打开页面 -- 点击元素 -- 获取执行结果 -- 写入执行结果 --- 结束本次执行),区别只是依赖的数据不同,最初采用的每次手动变更数据,时间异常繁琐而且易错,并且不能一次执行多个相同行为模式不同数据的用例,所以说到这里,变更之道呼之欲出,需要对用例的数据采取参数话的方式:

@pytest.mark.parametrize(

​ "p1","p2" [(p11,p21),(p12,p22)]

)

具体参数话方式,这里我不班门弄斧了,大家可以自行百度学习

4.方便执行

呃,没错,和方便管理数据一起产生的新的问题:如何方便快捷选的用例执行范围?

每次执行需要选择用例集合的某一种或者某几个来执行,最开始,我采用的执行前注释掉不执行的用例,后来发现实在太麻烦了,而且有疏漏风险,所以查阅资料,最终选择的方案是,给用例打标签

@pytest.mark.m1_xx

然后执行命令的时候,只需要在 pytest 命令后加 “-k 'm1'”,就可以选定标记含有 “m1” 的用例了(这里想说的一点是,不用 -m ,是我需要模糊匹配这个参数是精确匹配标记的)

5.方便分享

前面说了这么多,天花乱坠的,结果也只能在我一人的本地看到,领导同事每次都要询问我获取执行情况,因此在领导的建议下,还是接入了公共平台,实现的云端发送任务到本地执行,然后回收结果至云端,具体的平台不做过多介绍,大家使用 Jenkins 即可达到相同效果,这个过程想要提及的其实是获取云端下发参数作为用例的启动参数的经验,

举个例子:测试基类支持 2 种运行模式: p1\p2,主要靠实例变量 C1 的 2 个枚举值进行判断切换,在本地运行时,我们可以手动修改不同的枚举,但是现在上云了,我们想通过命令行给用例方法传参,到达动态控制的效果,这周情况下,就可以利用 pytest_addoption + pytest.feature

大致的思路,就是使用 pytest_addoption 指定读取我们自定义的参数对于的参数值,而用 pytest.feature 将参数做处理并传递给测试方法

# 读取指定参数
def pytest_addoption(parser):
    parser.addoption("--param", default= "False", action="store", help="need background wake up before run case", dest="para")

# 获取参数作为返回值
@pytest.fixture(autouse=True)
def read_param(request):
    logger.info(f"read param:{request.config.getoption('--need_wake_up')}", )
    return request.config.getoption("--need_wake_up")

# 将参数进一步处理获得最终可使用的值
@pytest.fixture(autouse=True)
def set_param(request, read_param):
    read_need_wake_up = get_target_from(read_param, bool_pattern).title()
    if read_need_wake_up == "True":
        param = True
    else:
        param = False    
    logger.info(f"set param :{param}" )
    return param

def get_target_from(s: str, pattern: str) -> str:
    match = re.search(pattern, s)
    if match:
        return match.group(1)
    return ""

# 测试方法
def test_1(set_need_wake_up):
    print(f"need_wake_up:{set_need_wake_up}")
    pass

具体使用教程可查看 : https://blog.51cto.com/u_15688254/5391586

6.方便可视化

关于数据可视化,这个是正在接洽的内容,大概规划也是利用已有的轮子,即 生成 allure 报告,然后将报告上传到平台上查看,这个只需要在 pytest 命令后面加上

--alluredir=.\temps

7.总结

罗马不是一天建成的,同样自己在做这个项目的时候,也是一步步摸索着前进,慢慢优化的,我想任何一个好的项目也多少这样不断迭代出来的,工作最是让人成长,这个话真是干的越久越有体验。

从非计算机科班转行到测试行业,从最简单的手工测试到自动化测试,自己在上一个公司是做 Java 的 web 自动化,现在的工作切换到 APP + WEB + 端,工作内容变多变杂,强度变大,但是也学到了更多东西,就这个项目而言,做下来,对 python 的基础语法、UIautomator 的使用,pytest 的强大与灵活都有了更深刻的了解,未来也希望参与更多测试框架和工作的学习和创造,加油!希望各位大佬也不吝赐教

共收到 3 条回复 时间 点赞

我之前都是一个项目里面写接口自动化,ui 自动化😂 ,后面发现太杂,后续就一个项目对应一个端,然后直接挂到 Jenkins 上进行定时任务,生成 allure 报告。

根据我多年做自动化测试的经验来提醒一下,不要把各种自动化都放到一个项目中,虽然感觉这样做的话一个项目非常强大;有个页面化管理的话,那就非常牛 X 了。但是你有没有在业界看到有这样成熟的方案呢?各大公司也没有这么做的,因为后期的维护成本高的吓人,会让使用者放弃对自动化的使用的。还是把不同的自动化拆解成不同的项目,不同的项目甚至可以采取不同的框架,后期做统计的调度分析即可!

爱偷懒的QA 回复

嗯嗯,是的,确实是倾向于每个项目单独维护。其实我记录这个也是针对一个项目的,这个项目大部分使用 UI 自动化,少部分为了方便用到了 api,主要是记录自己对于项目的多轮迭代

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册