uiautomator2 App自动化测试框架【三】

2023-12-22 02:40

本文主要是介绍uiautomator2 App自动化测试框架【三】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文为博主原创,未经授权,严禁转载及使用。
本文链接:https://blog.csdn.net/zyooooxie/article/details/124176686

之前分享过 使用uiautomator2 来搞APP自动化,分别是 https://blog.csdn.net/zyooooxie/article/details/124415385、 https://blog.csdn.net/zyooooxie/article/details/123916767,现在把 剩下的做个分享。

【实际这篇博客推迟发布N个月】

个人博客:https://blog.csdn.net/zyooooxie

【以下所有内容仅为个人项目经历,如有不同,纯属正常】

本期内容

本期主要是说 测试用例.py、元素定位.py、执行结果。

代码

下面是 按着 pageElements + testCases 来讲述的。

(代码有删改)

@filename: page_membership_interests_1.py

"""
@blog: https://blog.csdn.net/zyooooxie
"""class PageMembershipInterests1(object):"""大陆APP"""SHAOHOU = dict(text="稍后")GENGXIN1 = dict(resourceId="android:id/button1")QUXIAO = dict(description="取消,按钮")QUXIAO2 = '//*[@resource-id="zyooooxie:id/rnRootLayout"]/android.view.ViewGroup[2]/android.view.ViewGroup[2]/android.view.ViewGroup[2]'WO = dict(text="我")TANNENGLIANG = dict(text="")HUIYUANZHONGXIN = dict(text="会员中心")TANCHUANG = dict(text="close")HUIYUANZHONGXIN_BIAOTI = dict(descriptionContains="标题")HUITYANQUANYI = '//*[@resource-id="root"]/android.view.View[1]/android.view.View[1]'JIFENSHANGCHENG = dict(text="积分商城")WODEZHUANGXIANGTEQUAN = dict(text="我的专享特权")CHENGZHANGTIXI = dict(textStartsWith="成长体")ZANKAI = dict(text="展开")BAOJIAYOUHUI = dict(text="")SHOUJIANDUIJIANG = dict(text="")QUANYIJIESHAO = dict(text="权益介绍")QUANYINEIRONG = dict(text="权益内容")LIJIQIANWANG = dict(text="立即前往")LINGQUYOUHUIQUAN = dict(text="领取优惠券")GONGXILINGQUCHENGGONG = dict(textStartsWith='恭喜领取成')TOAST_WUCILIBAO = dict(text="无此礼包或库存不足")TOAST_HUODONGBUCUNZAI = dict(text="活动不存在")if __name__ == '__main__':pass

@filename: test_membership_interests_1.py

"""
@blog: https://blog.csdn.net/zyooooxie
"""import pytest
import allure
import os
import time
import cv2
import random
from pypinyin import lazy_pinyin
from uiautomator2 import Direction
from uiautomator2 import Devicefrom membership_interests_app_autotest.page_membership_interests_1 import PageMembershipInterests1
from membership_interests_app_autotest.common_function import my_element, my_assert, my_assert_toast
from membership_interests_app_autotest.common_function import kill_button, screenshot_decorator, get_user_id
from membership_interests_app_autotest.common_variable import dl, common_serial_number, dl_account
from membership_interests_app_autotest.common_variable import diff_pictures_path, now_pictures_path
from membership_interests_app_autotest.common_variable import pictures_path
from membership_interests_app_autotest.yy_function import crop_images, pic_diff
from membership_interests_app_autotest.common_mysql import exe_sql
from membership_interests_app_autotest.user_log import Logprint(dl_account, 'test_membership_interests_1.py')def delete_award_packet_records():# 做数据清理user_id = get_user_id(mobile=dl_account)sql1 = """DELETE FROM table_aprs WHERE USER_ID = '{}';""".format(user_id)sql2 = """DELETE FROM table_aprsd WHERE USER_ID = '{}';""".format(user_id)for s in [sql1, sql2]:exe_sql(sql=s, db_name='zyooooxie_db')# @pytest.mark.skip
@allure.feature('大陆APP')
@pytest.mark.parametrize('device_dl', dl,indirect=True)  # dl传给 device(fixture): indirect=True 表示将参数'before_after'当做一个函数去执行(即参数名要和定义的fixture的函数名一致),而不是一个参数变量,并且将 dl 当做参数传递给该函数
class TestMembershipInterests1(PageMembershipInterests1):@staticmethoddef setup_method():delete_award_packet_records()@staticmethoddef teardown_method():# 为了方便 看日志时确定 报错属于哪条用例Log.info('---------')def in_member_center(self, device: Device):device.sleep(5)  # 有时不稳定【某个升级弹窗 会弹多次】,加个强制等待with allure.step('关闭升级弹窗'):kill_button(device, self.SHAOHOU)kill_button(device, self.QUXIAO)kill_button(device, self.QUXIAO2, wait_time=2)with allure.step('点击会员中心'):my_element(device, self.WO).click()my_assert(device, self.TANNENGLIANG, 'exists', True, 'is_', assert_time=5)my_element(device, self.HUIYUANZHONGXIN).click()with allure.step('关闭会员中心-弹窗'):kill_button(device, self.TANCHUANG, wait_time=8)my_assert(device, self.HUIYUANZHONGXIN_BIAOTI, 'exists', True, 'is_', assert_time=5)with allure.step('进入会员权益'):my_element(device, self.HUITYANQUANYI).click()with allure.step('断言方法 my_assert()'):my_assert(device, self.WODEZHUANGXIANGTEQUAN, 'exists', True, 'is_')my_assert(device, self.CHENGZHANGTIXI, 'get_text', '成长体系', 'eq')# my_assert(device, self.QUXIAO, no_exists=True)# @pytest.mark.skip@screenshot_decorator(connect_addr=common_serial_number)@allure.description('会员权益领取某个权益')@allure.title('会员中心-会员权益-领取')def test_1(self, device_dl: Device):self.in_member_center(device=device_dl)my_element(device_dl, self.ZANKAI).click()device_dl.swipe_ext(Direction.UP)with allure.step(''):my_element(device_dl, self.BAOJIAYOUHUI).click()with allure.step('领取优惠券、断言'):my_element(device_dl, self.LINGQUYOUHUIQUAN).click()# # 现在2是:礼包不足 -> (toast)无此礼包或库存不足# my_assert_toast(device_dl, '包或库', 'contains', element=self.LINGQUYOUHUIQUAN, toast_text='无此礼')# my_assert_toast(device_dl, '库存不足', 'contains', x=0.5, y=0.92, toast_text='无此礼')# 以前1是:活动已正常 -> 正常领取my_assert(device_dl, self.GONGXILINGQUCHENGGONG, 'exists', True, 'is_')# # 以前0是:礼包配置有问题  -> (toast)礼包不存在# # device_dl.double_click(x=0.5, y=0.92)  # 传百分比# # my_assert(device_dl, cls.TOAST_HUODONGBUCUNZAI, 'exists', True, 'is_')  # 断言toast存在,有时成功、有时失败# my_assert_toast(device_dl, '不存', 'contains', element=self.LINGQUYOUHUIQUAN, toast_text='礼包不')# my_assert_toast(device_dl, '存在', 'contains', x=0.5, y=0.92, toast_text='礼包不')if __name__ == '__main__':passpytest.main(['-s', '-v', '{}'.format(__file__)])# pytest.main(['-s', '-m', 'smoke', '-v', '{}'.format(__file__)])

----------------------------------------------

@filename: page_membership_interests_2.py

"""
@blog: https://blog.csdn.net/zyooooxie
"""class PageMembershipInterests2(object):"""香港APP"""vConsole = dict(resourceId="__vconsole")HUIYUAN = dict(text="會員")JIFENZONGSHULIANG = '//*[@resource-id="app"]/android.view.View[4]'HUIYUANDUXIANG = dict(text="會員獨享")JIFENGUIZE = dict(text="積分規則")ZHUYI = dict(text="注意")SHUNFENGDIANZITAOPIAOYOUHUI = dict(text="")QUQIANGGOU = dict(text='去搶購')SHUNFENGDIANZITAOPIAOXIANGQING = dict(text='')LIJIGOUMAI = dict(text="立即購買")WODELIPIN = dict(text="my-gift.9c48adc5")KUAIGUOQI = dict(text="快過期")XINLINGQU = dict(text="新領取")JIFENHUANLING = dict(text="積分換領")LIJIDUIHUAN = dict(text='立即兌換')LIPINXIANGQING = dict(text='禮品詳情')LIPINJIANJIE = dict(text="禮 品 簡 介")YINGYESHIJIAN = dict(textStartsWith='營業時間')QUEDINGDUIHUAN = dict(text="確定兌換")SUOXUJIFEN = dict(textStartsWith='所需積分')QUEDINGSHIYONG = dict(textStartsWith='確定使用')QUXIAO = dict(text="取消")QUEREN = dict(text="確認")DUIHUANCHENGGONG = dict(text="兌換成功")JIXUDUIHUAN = dict(text="繼續兌換")KEYONG = dict(textStartsWith='可用')JIAZAIGENGDUO = dict(text="加載更多")CHANPIN_QUQIANGGOU = '//*[@text="不要下架要跑APP自动化的谢谢"]/../android.view.View[5]'CHANPIN_1 = dict(text="不要下架要跑APP自动化的谢谢")TONGYI = dict(text="同意")GOUMAITONGYI = '//android.widget.CheckBox'SHUNFENGCHUZHIKA = dict(text="")QUERENFUKUAN = dict(text="確認付款")ZHIFUJINE = dict(text="支付金額")ZHIFUCHENGGONG = dict(text="支付成功")WANCHENG = dict(text="完成")LIJISHIYONG = dict(text="立即使用")TEST = dict(text="TEST")if __name__ == '__main__':pass

@filename: test_membership_interests_2.py

"""
@blog: https://blog.csdn.net/zyooooxie
"""import pytest
import allure
import random
import string
import re
import osfrom uiautomator2 import Device
from uiautomator2 import Directionfrom membership_interests_app_autotest.user_log import Logfrom membership_interests_app_autotest.common_variable import xg, common_serial_number, xg_account, request_headers
from membership_interests_app_autotest.common_variable import pictures_path
from membership_interests_app_autotest.common_function import screenshot_decorator, my_element, my_assert, get_user_id
from membership_interests_app_autotest.common_function import kill_button, send_request, join_url
from membership_interests_app_autotest.common_mysql import fetch_sql
from membership_interests_app_autotest.page_membership_interests_2 import PageMembershipInterests2print(xg_account, 'test_membership_interests_2.py')def update_user_point(available_points: str, login_account: str):"""修改用户的积分:param available_points::param login_account::return:"""add_point_url = '/zyooooxie/addPointOperate'if int(available_points) <= 100:user_id = get_user_id(login_account)if user_id:source = ''.join(random.sample(string.zy, 10))data = {'userId': user_id, 'mobile': login_account, 'pointValue': 100}send_request('post', url=join_url(add_point_url), json=data, headers=request_headers)Log.info('addPoint-100')return str(int(available_points) + 100)else:return available_points# @pytest.mark.skip
@allure.feature('香港APP')
@pytest.mark.parametrize('before_after_xgtw_module', xg, indirect=True)
@pytest.mark.parametrize('device_xgtw', xg, indirect=True)
class TestMembershipInterests2(PageMembershipInterests2):@staticmethoddef teardown_method():Log.info('---------')@pytest.mark.skip@screenshot_decorator(common_serial_number)@allure.description('积分规则')@allure.title('香港会员2')def test_2(self, device_xgtw: Device):my_element(device_xgtw, self.HUIYUAN).click()my_element(device_xgtw, self.JIFENGUIZE).click()my_assert(device_xgtw, self.ZHUYI, 'exists', True, 'is_')my_assert(device_xgtw, self.TEST, 'exists', True, 'is_')  # 不存在的元素@pytest.mark.smoke@screenshot_decorator(common_serial_number)@allure.description('积分换领-兑换礼品')@allure.title('香港会员10')def test_10(self, device_xgtw: Device):my_element(device_xgtw, self.HUIYUAN).click()my_assert(device_xgtw, self.HUIYUANDUXIANG, 'exists', True, 'is_')with allure.step('可用积分'):available_points = my_element(device_xgtw, self.JIFENZONGSHULIANG).get_text()Log.info(available_points)# 可用积分 有bug,所以每次都截个图img_name = ''.join(['available_points', '.png'])fn = os.path.join(pictures_path, img_name)device_xgtw.screenshot(filename=fn)allure.attach.file(source=fn, name=img_name, attachment_type=allure.attachment_type.PNG)available_points = update_user_point(available_points=available_points, login_account=xg_account)Log.info(available_points)with allure.step('某商品-立即兑换'):device_xgtw.swipe_ext(Direction.UP)device_xgtw.swipe_ext(Direction.UP)my_element(device_xgtw, self.LIJIDUIHUAN).click()my_assert(device_xgtw, self.LIPINXIANGQING, 'exists', True, 'is_')my_assert(device_xgtw, self.LIPINJIANJIE, 'exists', True, 'is_')with allure.step('vConsole'):my_element(device_xgtw, self.vConsole).drag_to(x=0.35, y=0.15, duration=0.5)with allure.step('某商品详情-获取point'):point0 = my_element(device_xgtw, self.SUOXUJIFEN).get_text()re_str = r'\d+'res0 = re.findall(re_str, point0)Log.info(res0)assert len(res0) == 1ke_yong_points1 = my_element(device_xgtw, self.KEYONG).get_text()ava1 = re.findall(re_str, ke_yong_points1)Log.info(ava1)assert len(ava1) == 1assert ava1[0].startswith(available_points) is Truewith allure.step('某商品兑换'):my_element(device_xgtw, self.LIJIDUIHUAN).click()kill_button(device_xgtw, self.YINGYESHIJIAN, wait_time=5)kill_button(device_xgtw, self.QUEDINGDUIHUAN, wait_time=5)my_assert(device_xgtw, self.QUXIAO, 'exists', True, 'is_')point1 = my_element(device_xgtw, self.QUEDINGSHIYONG).get_text()res1 = re.findall(re_str, point1)Log.info(res1)assert len(res1) == 1assert res1[0] == res0[0]with allure.step('某商品兑换-确认'):my_element(device_xgtw, self.QUEREN).click()my_assert(device_xgtw, self.DUIHUANCHENGGONG, 'exists', True, 'is_')my_assert(device_xgtw, self.JIXUDUIHUAN, 'exists', True, 'is_')device_xgtw.press('back')with allure.step('某商品兑换后-断言'):ke_yong_points2 = my_element(device_xgtw, self.KEYONG).get_text()ava2 = re.findall(re_str, ke_yong_points2)Log.info(ava2)assert len(ava2) == 1assert ava2[0] == str(int(available_points) - int(res1[0]))@pytest.mark.smoke@screenshot_decorator(common_serial_number)@allure.description('购买超值福利-特定产品')@allure.title('香港会员11')def test_11(self, device_xgtw: Device):user = get_user_id(xg_account)with allure.step('特定产品-获取购买记录'):sql = """SELECT  COUNT(order_code) FROM table_oo WHERE user_id = '{}' AND commodity_name = '不要下架要跑APP自动化的谢谢' ORDER BY order_time DESC;""".format(user)res = fetch_sql(sql, db_name='zyooooxie_db', fetch_mode='fetchone')Log.info(res)sql2 = """SELECT COUNT(id) FROM table_oppr WHERE user_id = '{}' AND pay_status = '1' ORDER BY create_tm DESC;""".format(user)res2 = fetch_sql(sql2, db_name='zyooooxie_db', fetch_mode='fetchone')Log.info(res2)my_element(device_xgtw, self.HUIYUAN).click()my_element(device_xgtw, self.WODELIPIN).drag_to(x=0.35, y=0.15, duration=0.5)device_xgtw.swipe_ext(Direction.UP)with allure.step('特定产品-购买、付款'):my_element(device_xgtw, self.JIAZAIGENGDUO).click()my_element(device_xgtw, self.CHANPIN_QUQIANGGOU).click()my_assert(device_xgtw, self.CHANPIN_1, 'exists', True, 'is_')my_assert(device_xgtw, self.TONGYI, 'exists', True, 'is_')my_element(device_xgtw, self.GOUMAITONGYI).click()my_element(device_xgtw, self.LIJIGOUMAI).click()my_assert(device_xgtw, self.SHUNFENGCHUZHIKA, 'exists', True, 'is_')# 確認付款 有时候不稳定my_element(device_xgtw, self.QUERENFUKUAN).click()kill_button(device_xgtw, self.QUERENFUKUAN, wait_time=2)with allure.step('特定产品-输入支付密码'):my_assert(device_xgtw, self.ZHIFUJINE, 'exists', True, 'is_')# 支付密码1234my_element(device_xgtw, dict(text="1")).click()my_element(device_xgtw, dict(text="2")).click()my_element(device_xgtw, dict(text="3")).click()my_element(device_xgtw, dict(text="4")).click()with allure.step('特定产品-支付完成'):my_assert(device_xgtw, self.ZHIFUCHENGGONG, 'exists', True, 'is_')my_element(device_xgtw, self.WANCHENG).click()with allure.step('特定产品-购买后断言'):sql3 = """SELECT  COUNT(order_code) FROM table_oo WHERE user_id = '{}' AND commodity_name = '不要下架要跑APP自动化的谢谢' ORDER BY order_time DESC;""".format(user)res3 = fetch_sql(sql3, db_name='zyooooxie_db', fetch_mode='fetchone')Log.info(res3)assert res3[0] == res[0] + 1sql4 = """SELECT COUNT(id) FROM table_oppr WHERE user_id = '{}' AND pay_status = '1' ORDER BY create_tm DESC;""".format(user)res4 = fetch_sql(sql4, db_name='zyooooxie_db', fetch_mode='fetchone')Log.info(res4)assert res4[0] == res2[0] + 1if __name__ == '__main__':pass

----------------------------------------------

@filename: page_membership_interests_3.py

"""
@blog: https://blog.csdn.net/zyooooxie
"""class PageMembershipInterests3(object):"""台湾APP"""HUIYUAN = dict(text="會員")LiJILINGQU_close = dict(text="U+e1ILO3mKM256VjE9oujfgGk5zsYyFvRKAAAAABJRU5ErkJggg==")WODEHUIYUAN = dict(text="我的會員")HUIYUANGUIZE = dict(text="會員規則")

@filename: test_membership_interests_3.py

"""
@blog: https://blog.csdn.net/zyooooxie
"""import allure
import pytestfrom uiautomator2 import Devicefrom membership_interests_app_autotest.user_log import Log
from membership_interests_app_autotest.common_variable import tw, common_serial_number, tw_account
from membership_interests_app_autotest.common_function import my_element, my_assert, screenshot_decorator, kill_button
from membership_interests_app_autotest.page_membership_interests_3 import PageMembershipInterests3print(tw_account, 'test_membership_interests_3.py')# @pytest.mark.skip
@allure.feature('台湾APP')
@pytest.mark.parametrize('before_after_xgtw_module', tw, indirect=True)
@pytest.mark.parametrize('device_xgtw', tw, indirect=True)
class TestMembershipInterests3(PageMembershipInterests3):@staticmethoddef teardown_method():Log.info('---------')@pytest.mark.smoke@screenshot_decorator(common_serial_number)@allure.description('会员中心页面')@allure.title('台湾会员1')def test_1(self, device_xgtw: Device):my_element(device_xgtw, self.HUIYUAN).click()kill_button(device_xgtw, self.LiJILINGQU_close, wait_time=5)my_assert(device_xgtw, self.WODEHUIYUAN, 'exists', True, 'is_')my_assert(device_xgtw, self.HUIYUANGUIZE, 'exists', True, 'is_')if __name__ == '__main__':passpytest.main(['-s', '-v', '{}'.format(__file__)])

----------------------------------------------

@filename: page_membership_interests_4.py

"""
@blog: https://blog.csdn.net/zyooooxie
"""import time
import random
import datetime
import jsonpathfrom membership_interests_app_autotest.user_log import Logfrom membership_interests_app_autotest.common_function import my_element, send_request, join_url, get_user_id
from membership_interests_app_autotest.common_mysql import fetch_sql
from membership_interests_app_autotest.common_variable import dl_account, request_headersclass PageMembershipInterests4(object):QINGSHURUSHOUJIHAO = '//*[@resource-id="root"]//android.widget.EditText[1]'HUOQUYANZHENGMA = dict(text="获取验证码")QINGSHURUYANZHENGMA = '//*[@text="请输入发送至手机的验证码"]/../android.view.View[2]'QINGSHURUYANZHENGMA2 = dict(text="请输入发送至手机的验证码")TONGYIBENTIAOKUAN = dict(text="同意本条款,下次不再提醒")DENGLU = dict(text="登录")TANCHUANG = dict(text="close")@staticmethoddef add_task_and_open(action_type: str = '浏览'):url_add = '/task/add'abc = datetime.datetime.now().strftime('%y%m%d%H%M%S')task_id = "TASK{}{}".format(abc, random.randint(1000, 9999))if action_type == '浏览':add_dict = {"actionName": "浏览/浏览会员中心"}else:assert action_type == '点击'add_dict = {"actionName": "点击"}send_request('post', url=join_url(url_add), json=add_dict, headers=request_headers)Log.info('任务:{} 已新建'.format(task_id))return task_id@staticmethoddef get_visit_url(task_id: str):url_addTaskCodes = '/task/addTaskCodes'task_code_list = list()			# 暂不提供 task_code_list 生成逻辑user_id = get_user_id(dl_account)url_openTask = '/task/openTask'open_dict = {'mobile': dl_account, 'userId': user_id,'taskInfos': [{'taskCode': random.choice(task_code_list), 'callBackUrl': ''}]}res = send_request('post', json=open_dict, headers=request_headers, url=join_url(url_openTask))url = jsonpath.jsonpath(res, '$..jumpTo')Log.info('openTask返回的url:{}'.format(url))assert len(url) == 1return url[0]if __name__ == '__main__':pass

@filename: test_membership_interests_4.py

"""
@blog: https://blog.csdn.net/zyooooxie
"""import allure
import pytest
import uiautomator2 as u2from uiautomator2 import Devicefrom membership_interests_app_autotest.common_variable import dl_account, common_serial_number
from membership_interests_app_autotest.page_membership_interests_4 import PageMembershipInterests4
from membership_interests_app_autotest.common_function import my_element, screenshot_decorator
from membership_interests_app_autotest.common_function import my_assert, kill_button
from membership_interests_app_autotest.user_log import Logprint(dl_account, 'test_membership_interests_4.py')# @pytest.mark.skip
@allure.feature('大陆会员-任务相关')
class TestMembershipInterests4(PageMembershipInterests4):def h5_login(self, account: str, device: Device):login_url = 'https://zyooooxie/Login'with allure.step('浏览器打开login地址'):device.open_url(login_url)with allure.step('输入手机号、获取验证码'):my_element(device, self.QINGSHURUSHOUJIHAO).click()device.send_keys(account, clear=True)my_element(device, self.HUOQUYANZHENGMA).click()with allure.step('输入验证码'):my_element(device, self.QINGSHURUYANZHENGMA).set_text('123456')with allure.step('登录'):my_element(device, self.TONGYIBENTIAOKUAN).click()my_element(device, self.DENGLU).click()kill_button(device, self.TANCHUANG, wait_time=5)my_assert(device, self.SHENGHUOTEQUAN, 'exists', True, 'is_')@classmethoddef setup_class(cls):print('setup_class')cls.device = u2.connect(addr=common_serial_number)cls.device.implicitly_wait(10)TestMembershipInterests4().h5_login(dl_account, cls.device)@classmethoddef teardown_class(cls):print('teardown_class')del cls.device@staticmethoddef setup_method():print(__class__.__name__)@staticmethoddef teardown_method():Log.info('---------')@pytest.mark.smoke@screenshot_decorator(common_serial_number)@allure.description('用户领取任务、完成任务、断言')@allure.title('用户领取页面浏览任务')def test_1(self):task_id = self.add_task_and_open()url = self.get_visit_url(task_id=task_id)self.device.open_url(url=url)self.device.sleep(3)  # 看下效果# TODO 因为不是白名单,始终没法跑通if __name__ == '__main__':pass

执行结果

allure报告

在这里插入图片描述

日志文件、手机截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

本文链接:https://blog.csdn.net/zyooooxie/article/details/124176686

uiautomator2的这3篇博客,应该是真实分享时 代码‘马赛克’ 最少的几次。

此外,我这也用了 图像对比:有些用例是 某些H5页面 想做文案对比。我是不想一个一个字去对 + 大佬本就写了这些方法,我就‘拿来主义’ 优化下,搞了搞。 (非我原创 所以就没有做任何展示)

交流技术 欢迎+QQ 153132336 zy
个人博客 https://blog.csdn.net/zyooooxie

这篇关于uiautomator2 App自动化测试框架【三】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/522332

相关文章

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

Python GUI框架中的PyQt详解

《PythonGUI框架中的PyQt详解》PyQt是Python语言中最强大且广泛应用的GUI框架之一,基于Qt库的Python绑定实现,本文将深入解析PyQt的核心模块,并通过代码示例展示其应用场... 目录一、PyQt核心模块概览二、核心模块详解与示例1. QtCore - 核心基础模块2. QtWid

Python实现自动化接收与处理手机验证码

《Python实现自动化接收与处理手机验证码》在移动互联网时代,短信验证码已成为身份验证、账号注册等环节的重要安全手段,本文将介绍如何利用Python实现验证码的自动接收,识别与转发,需要的可以参考下... 目录引言一、准备工作1.1 硬件与软件需求1.2 环境配置二、核心功能实现2.1 短信监听与获取2.

Python实现Microsoft Office自动化的几种方式及对比详解

《Python实现MicrosoftOffice自动化的几种方式及对比详解》办公自动化是指利用现代化设备和技术,代替办公人员的部分手动或重复性业务活动,优质而高效地处理办公事务,实现对信息的高效利用... 目录一、基于COM接口的自动化(pywin32)二、独立文件操作库1. Word处理(python-d

Python使用DrissionPage中ChromiumPage进行自动化网页操作

《Python使用DrissionPage中ChromiumPage进行自动化网页操作》DrissionPage作为一款轻量级且功能强大的浏览器自动化库,为开发者提供了丰富的功能支持,本文将使用Dri... 目录前言一、ChromiumPage基础操作1.初始化Drission 和 ChromiumPage

Python实现自动化表单填写功能

《Python实现自动化表单填写功能》在Python中,自动化表单填写可以通过多种库和工具实现,本文将详细介绍常用的自动化表单处理工具,并对它们进行横向比较,可根据需求选择合适的工具,感兴趣的小伙伴跟... 目录1. Selenium简介适用场景示例代码优点缺点2. Playwright简介适用场景示例代码

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式

最新Spring Security实战教程之Spring Security安全框架指南

《最新SpringSecurity实战教程之SpringSecurity安全框架指南》SpringSecurity是Spring生态系统中的核心组件,提供认证、授权和防护机制,以保护应用免受各种安... 目录前言什么是Spring Security?同类框架对比Spring Security典型应用场景传统

Python结合Flask框架构建一个简易的远程控制系统

《Python结合Flask框架构建一个简易的远程控制系统》这篇文章主要为大家详细介绍了如何使用Python与Flask框架构建一个简易的远程控制系统,能够远程执行操作命令(如关机、重启、锁屏等),还... 目录1.概述2.功能使用系统命令执行实时屏幕监控3. BUG修复过程1. Authorization