news 2026/4/3 2:58:33

Appium+Python+pytest自动化测试框架的实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Appium+Python+pytest自动化测试框架的实战

本文主要介绍了Appium+Python+pytest自动化测试框架的实战,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

先简单介绍一下目录,再贴一些代码,代码里有注释

Basic目录下写的是一些公共的方法,Data目录下写的是测试数据,image存的是测试失败截图,Log日志文件,Page测试的定位元素,report测试报告,Test测试用例,pytest.ini是pytest启动配置文件,requirements.txt需要安装的py模块,run.py运行文件


Basic/base.py

里面封装了 一些方法,元素的点击,输入,查找,还有一些自己需要的公共方法也封装在里面,如果你们有别的需要可以自己封装调用

Basic/deiver.py
APP启动的前置条件,一个是普通的app,一个是微信公众号,配置微信公众号自动化测试和一般的APP是有点区别的,微信需要切换webview才能定位到公众号

from appium import webdriver def init_driver(): desired_caps = {} # 手机 系统信息 desired_caps['platformName'] = 'Android' desired_caps['platformVersion'] = '9' # 设备号 desired_caps['deviceName'] = 'emulator-5554' # 包名 desired_caps['appPackage'] = '' # 启动名 desired_caps['appActivity'] = '' desired_caps['automationName'] = 'Uiautomator2' # 允许输入中文 desired_caps['unicodeKeyboard'] = True desired_caps['resetKeyboard'] = True desired_caps['autoGrantPermissions'] = True desired_caps['noReset'] = False # 手机驱动对象 driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps) return driver def driver_weixin(): desired_caps = {} # 手机 系统信息 desired_caps['platformName'] = 'Android' desired_caps['platformVersion'] = '9' # 设备号 desired_caps['deviceName'] = '' # 包名 desired_caps['appPackage'] = 'com.tencent.mm' # 启动名 desired_caps['appActivity'] = '.ui.LauncherUI' # desired_caps['automationName'] = 'Uiautomator2' # 允许输入中文 desired_caps['unicodeKeyboard'] = True desired_caps['resetKeyboard'] = True desired_caps['noReset'] = True # desired_caps["newCommandTimeout"] = 30 # desired_caps['fullReset'] = 'false' # desired_caps['newCommandTimeout'] = 10 # desired_caps['recreateChromeDriverSessions'] = True desired_caps['chromeOptions'] = {'androidProcess': 'com.tencent.mm:tools'} # 手机驱动对象 driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps) return driver

Basic/get_data.py

这是获取测试数据的方法

import os import yaml def getData(funcname, file): PATH = os.getcwd() + os.sep with open(PATH + 'Data/' + file + '.yaml', 'r', encoding="utf8") as f: data = yaml.load(f, Loader=yaml.FullLoader) # 1 先将我们获取到的所有数据都存放在一个变量当中 tmpdata = data[funcname] # 2 所以此时我们需要使用循环走进它的内心。 res_arr = list() for value in tmpdata.values(): tmp_arr = list() for j in value.values(): tmp_arr.append(j) res_arr.append(tmp_arr) return res_arr

Basic/Log.py

日志文件,不多介绍

# -*- coding: utf-8 -*- """ 封装log方法 """ import logging import os import time LEVELS = { 'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARNING, 'error': logging.ERROR, 'critical': logging.CRITICAL } logger = logging.getLogger() level = 'default' def create_file(filename): path = filename[0:filename.rfind('/')] if not os.path.isdir(path): os.makedirs(path) if not os.path.isfile(filename): fd = open(filename, mode='w', encoding='utf-8') fd.close() else: pass def set_handler(levels): if levels == 'error': logger.addHandler(MyLog.err_handler) logger.addHandler(MyLog.handler) def remove_handler(levels): if levels == 'error': logger.removeHandler(MyLog.err_handler) logger.removeHandler(MyLog.handler) def get_current_time(): return time.strftime(MyLog.date, time.localtime(time.time())) class MyLog: path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) log_file = path+'/Log/log.log' err_file = path+'/Log/err.log' logger.setLevel(LEVELS.get(level, logging.NOTSET)) create_file(log_file) create_file(err_file) date = '%Y-%m-%d %H:%M:%S' handler = logging.FileHandler(log_file, encoding='utf-8') err_handler = logging.FileHandler(err_file, encoding='utf-8') @staticmethod def debug(log_meg): set_handler('debug') logger.debug("[DEBUG " + get_current_time() + "]" + log_meg) remove_handler('debug') @staticmethod def info(log_meg): set_handler('info') logger.info("[INFO " + get_current_time() + "]" + log_meg) remove_handler('info') @staticmethod def warning(log_meg): set_handler('warning') logger.warning("[WARNING " + get_current_time() + "]" + log_meg) remove_handler('warning') @staticmethod def error(log_meg): set_handler('error') logger.error("[ERROR " + get_current_time() + "]" + log_meg) remove_handler('error') @staticmethod def critical(log_meg): set_handler('critical') logger.error("[CRITICAL " + get_current_time() + "]" + log_meg) remove_handler('critical') if __name__ == "__main__": MyLog.debug("This is debug message") MyLog.info("This is info message") MyLog.warning("This is warning message") MyLog.error("This is error") MyLog.critical("This is critical message")

AI写代码bash

Basic/Shell.py

执行shell语句方法

# -*- coding: utf-8 -*- # @Time : 2018/8/1 下午2:54 # @Author : WangJuan # @File : Shell.py """ 封装执行shell语句方法 """ import subprocess class Shell: @staticmethod def invoke(cmd): output, errors = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() o = output.decode("utf-8") return o

Page/page.py

class Page: def __init__(self, driver): self.driver = driver @property def initloginpage(self): return Login_Page(self.driver)

Test/test_login.py

登陆的测试用,我贴一条使用数据文件的用例

class Test_login: @pytest.mark.parametrize("args", getData("test_login_error", 'data_error_login')) def test_error_login(self, args): """错误登陆""" self.page.initloginpage.input_user(args[0]) self.page.initloginpage.input_pwd(args[1]) self.page.initloginpage.click_login() toast_status = self.page.initloginpage.is_toast_exist(args[2]) if toast_status == False: self.page.initpatientpage.take_screenShot() assert False

pytest.ini

pytest配置文件,注释的是启动失败重试3次,因为appium会因为一些不可控的原因失败,所有正式运行脚本的时候需要加上这个

[pytest] ;addopts = -s --html=report/report.html --reruns 3 addopts = -s --html=report/report.html testpaths = ./Test python_files = test_*.py python_classes = Test* python_functions = test_add_prescription_list requirements.txt 框架中需要的患教,直接pip install -r requirements.txt 安装就可以了,可能会失败,多试几次 ```python adbutils==0.3.4 allure-pytest==2.7.0 allure-python-commons==2.7.0 Appium-Python-Client==0.46 atomicwrites==1.3.0 attrs==19.1.0 certifi==2019.6.16 chardet==3.0.4 colorama==0.4.1 coverage==4.5.3 decorator==4.4.0 deprecation==2.0.6 docopt==0.6.2 enum34==1.1.6 facebook-wda==0.3.4 fire==0.1.3 humanize==0.5.1 idna==2.8 importlib-metadata==0.18 logzero==1.5.0 lxml==4.3.4 more-itertools==7.1.0 namedlist==1.7 packaging==19.0 Pillow==6.1.0 pluggy==0.12.0 progress==1.5 py==1.8.0 PyMySQL==0.9.3 pyparsing==2.4.0 pytest==5.0.0 pytest-cov==2.7.1 pytest-html==1.21.1 pytest-metadata==1.8.0 pytest-repeat==0.8.0 pytest-rerunfailures==7.0 PyYAML==5.1.1 requests==2.22.0 retry==0.9.2 selenium==3.141.0 six==1.12.0 tornado==6.0.3 uiautomator2==0.3.3 urllib3==1.25.3 wcwidth==0.1.7 weditor==0.2.3 whichcraft==0.6.0 zipp==0.5.1

​​​​​​​

到此这篇关于Appium+Python+pytest自动化测试框架的实战的文章就介绍到这了

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/29 7:46:12

练习(递归)

练1.根据下面递归函数: 调用函数Fun(2),求 返回值 int Fun(int n) { if (n 5) return 2; else return 2 * Fun(n 1); } int main() { int ret Fun(2); printf("%d\n", ret); return 0; } 练2.字符串逆序(递归实…

作者头像 李华
网站建设 2026/4/2 5:05:31

Ice:彻底解放你的Mac菜单栏 - 免费开源管理工具完全指南

Mac用户们,是否曾经为菜单栏上密密麻麻的图标而烦恼?Wi-Fi、电池、时间被挤到角落,各种第三方应用的图标占据着宝贵的空间。今天,我要向大家推荐一款能够彻底解决这个问题的神奇工具——Ice。 【免费下载链接】Ice Powerful menu …

作者头像 李华
网站建设 2026/3/31 22:05:14

PictureBox控件怎么用?三大场景助你上手

在Windows窗体应用开发中,PictureBox控件是一个基础但功能强大的工具,用于显示图像。它不仅仅是一个简单的“图片框”,更是一个可以集成多种交互功能的容器。掌握其核心属性与方法,能有效提升应用程序的用户体验和功能性。本文将从…

作者头像 李华
网站建设 2026/3/30 8:26:54

NLP协议解析技术:供应商条款与实际用法的自动比对逻辑

NLP协议解析技术:供应商条款与实际用法的自动比对逻辑开头:解决用户的核心痛点在当今企业采购与供应链管理过程中,合同与供应商条款的审核和执行是至关重要的一环。面对海量的合同文本,企业内部的法务、采购和运营人员常常感到力不…

作者头像 李华
网站建设 2026/4/1 17:26:20

【拯救HMI】工业HMI设计中常见的几大误区及避坑指南

在实践中,许多HMI设计不知不觉陷入了误区。本文将盘点常见设计陷阱,如“屏幕就像飞行员座舱”、“滥用动画和颜色”等,并提供具体的解决方案。误区一:过度设计,信息过载。现象: 主界面布满密密麻麻的数据和…

作者头像 李华
网站建设 2026/3/26 16:33:19

从布谷用户到AI推荐官:制造业企业如何抢占AI搜索红利

当客户的采购决策从百度搜索转向询问DeepSeek、Kimi或豆包时,您的品牌是否还在“隐身”?GEO(生成式引擎优化)正是解决这一痛点的关键。与传统SEO优化网页排名不同,GEO旨在让您的品牌信息直接被AI“理解”并“引用”在答…

作者头像 李华