首先感谢白月黑羽和imhelloworld提供的在线教程和视频教程。是你们的教程伴我度过了疫情期间的漫漫长夜。
uiautomatorviewer:用来做APP界面定位用的。
这个文件位于androidsdk\tools\bin\uiautomatorviewer.bat,但是从白月黑羽提供的网盘链接下载软件后,它没办法使用jdk11,需要改安装jdk8。可能是androidsdk版本比较老,不想太折腾,所以我也没有再尝试最新的androidsdk是否支持jdk11。
附上环境变量(还需要有nodejs、python环境)设置:
JAVA_HOME C:\Program Files\Java\jdk1.8.0_211
CLASSPATH .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
ANDROID_HOME D:\Programs\androidsdk
path D:\Programs\Python37\Scripts\;D:\Programs\Python37\;C:\Program Files\nodejs\;%JAVA_HOME%\bin;D:\Programs\androidsdk\platform-tools
如果依旧报错,也有可能是androidsdk\tools\lib\find_java.bat文件问题,因为r17 以上的版本重写了这个文件,我们只需要把这个文件替换成r16的版本文件即可。老版本的find_java.bat可以从这下载:
链接:https://pan.baidu.com/s/1ng2EeMJ_jjF_QAbNa0s5LQ
提取码:16b3
androidsdk的下载可以直接去官网先下载Android Studio:Download Android Studio & App Tools - Android Developers
然后通过Android Studio去下载sdk。也可以直接去这个网站下载:Download SDK Platform for Android SDK Manager
我尝试了夜神模拟器,做得真不错!但是公司的笔记本配置还是6年前的,有点扯后腿,玩不转。后来我改用数据线连接真机了。需要说明的是,华为手机或者分家之前的荣耀手机,即使升级了HarmonyOS,照样还是可以使用安卓这一套来测试,我看网上很多人都说HarmonyOS底层还是安卓,大概多多少少和这也有点关系吧。
不过从HarmonyOS的开发者文档来看,以及HarmonyOS万物互联的设计思路,我更多的是觉得安卓这块只是为了兼容,HarmonyOS应该是有自己的一套底层逻辑的,说到底,安卓和HarmonyOS都是在linux内核上面做文章。这就像是容器技术一样,一个linux内核,跑两个不同的docker容器,一个是安卓,一个是HarmonyOS,嗯,这么理解应该没错。(扯远了
如果执行adb devices报错,需要将夜神模拟器中nox_adb.exe替换掉。先将Nox\bin\nox_adb.exe重命名为nox_adb.exe.bak备份下,再将androidsdk\platform-tools\adb.exe复制一份,改名为nox_adb.exe,直接放到Nox\bin\下。
建议直接连接真机或者模拟器输入命令。不建议通过apk文件来查找,原因在于:一个要考虑apk版本,一个是网上给的命令并不一定能查到结果。而且你最终还是程序还是要在真机或模拟器上面运行的。
真机或模拟器连接成功,且打开APP的某页面。然后在cmd输入命令:
方法一
adb shell dumpsys activity recents | find "intent={"
方法二
adb shell dumpsys activity activities
两个方法大同小异,方法二输出的信息更多,得自己过滤。
SyntaxError: Non-UTF-8 code starting with ‘\xba‘ in file
这个报错我相信大部分人都不会遇到。只有我这种用着6年前配置的电脑,开不起一个Pycharm,只能在nodepad++上写代码才会遇到这样的辛酸。
将程序文件在nodepad++打开后,全选复制一下,然后菜单栏编码处选择使用UTF-8编码,再粘贴覆盖,保存即可。
我的荣耀V20升级了HarmonyOS,为了防止意外,我特地翻出了那根原厂USB线(线皮都破了露出了铜丝),连接到笔记本后,颤抖着手,用管理员权限打开命令行窗口,输入了adb devices -l,然后给我下面的反馈:
网上找了下原因,ADB Interface找不到驱动程序。
通过 右击计算机-->点击 “管理” --> 找到 “设备管理器” --> 找到 “其他设备”:
驱动程序有感叹号,得重新安装驱动程序。双击带黄色感叹号的ADB Interface更新驱动程序,选择Windows自动搜索更新驱动程序软件,结果发现驱动程序无法正常安装。手动选择电脑上的文件安装驱动程序,参考谷歌文档:
安装原始设备制造商 (OEM) USB 驱动程序 | Android 开发者 | Android Developers
我用的是荣耀,只能安装通用的驱动程序。可以使用文档中下载的驱动,也可以选择Android SDK中的驱动。
重新拔插换个USB接口试试,如果还不行,看下报错信息,里面有这样一句话:
Try 'adb kill-server' if that seems wrong.
在命令行窗口输入adb kill-server 然后直接 adb devices -l 命令,手机上弹出了授权提示框,点击允许,这个问题就解决了!
这个问题其实很简单,能从错误提示中解决。但是设备未授权的原因确实没找出来,而且不执行adb kill-server,手机上就不会弹出授权的对话框,所以容易浪费时间。
必须在开发者模式下勾选USB调试,和“仅充电”模式下允许ADB调试。手机有adb网络调试的也可以打开。
无线调试不建议使用,我尝试下来,每次断开后都要重新设置一遍,还不如插上USB线来得快。
Encountered internal error running command: UnknownError: An unknown server-side error occurred while processing the command. Original error: Could not proxy command to the remote server. Original error: timeout of 240000ms exceeded
在手机的设置——应用与服务——应用管理下,卸载掉自动安装的Appium Settings、io.appium.uiautomator2.server、io.appium.uiautomator2.server.test,然后手机关机重启,再次执行就正常了。该情况不会多次出现,一般只会出现一次。
resetKeyboard=True, # 执行完程序恢复原来输入法
从两位自动化测试的前辈那里拿来的代码,注释上写的这段其实并不奏效。在测试完之后,还是需要在设置-高级设置-语言和输入法,然后把默认输入法改成自己常用的那个,这样手机在手动输入时,输入法才能调用出来。
appium -g 日志文件名称.log
我使用下来,这里是可以使用相对路径的。并且这个日志文件,不是使用append的方式写入的,而是每次使用时,都是覆盖上次的日志文件。所以如果需要保留上次的日志,日志文件的名称需要注意保持唯一性。
网上资料说:Python导入模块的方法有两种:import module 和 from module import,区别是前者所有导入的东西使用时需加上模块名的限定,而后者不要。
我给的建议是,无论你是用import module 还是 from module import,都尽量加上模块名限定,这样代码不会报错,但是可读性会高很多。
from tasks.TaskUtils import *
from tasks.TiaoZhanDaTi import *
# 不含__init__函数
TaskUtils.get_task_btn(driver, '挑战答题').click()
# 含__init__函数,直接调用
TiaoZhanDaTi(driver, db).da_ti()
python的初始化方法 __init__(self, ...) 就很类似java的构造函数。
python导入自定义模块,对比java其实就是导入一个类的事情,但在python里面,要复杂得多。我尝试下来,相对最简单,也最灵活的方式,先展示项目目录结构:
+---py_project
| +---utils| +---BasePage.py
| +---tasks
| +---TaskUtils.py
TaskUtils.py需要引入BasePage.py,代码如下:
import sys
from os.path import join, dirname
sys.path.append(join(dirname(__file__), '..'))
from utils.BasePage import *
None是一个对象,而NULL是一个类型。
Python中没有NULL,只有None,None有自己的特殊类型NoneType。
None不等于0、任何空字符串、False等。
在Python中,None、False、0、""(空字符串)、[](空列表)、()(空元组)、{}(空字典)都相当于False。判断变量是否为空的高效方法是:
if X is None
if not X:当X为None、False、""、0、[]、()、{}时,not X为真,无法分辨
if not X is None:等价于if not (X is None)、if X is not None
————————————————
版权声明:本文为CSDN博主「小小的刀」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:python中的None与NULL_小小的刀的博客-CSDN博客_python的none和null
f表示字符串内支持大括号内的python表达式,如:logger.info(f"Total time taken: {time.time() - start_time}");
r表示去掉反斜杠的转移机制,如:logger.info(r"Test\n\n\n") 表示单纯字符串而不表示换行;
u一般出现在中文字符串前,防止出现乱码;
b表示这是一个bytes类型对象,在网络编程中,服务器和浏览器只认bytes类型数据,如:response=b'Hello World
'————————————————
版权声明:本文为CSDN博主「小小的刀」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:Python 字符串前加f,r,u,b的含义_努力搬砖的刷刷碗的博客-CSDN博客_python字符串前加f
我要的元素需要通过屏幕下滑才能找到,然后可能还不止滑一次,swipe其实有点不稳定,勉强够用。截取部分代码如下:
"""
查找任务按钮
"""
def get_task_btn(driver, task):
print("准备进行> %s <任务" % task)
code = '//android.view.View[@text="' + task + '"]/../../android.view.View[@index=3]'
i = 0
ele = None
while i < 3:
try:
ele = driver.find_element(AppiumBy.XPATH, code)
except NoSuchElementException:
i = i + 1
print("当前屏幕未找到 %s 按钮,第 %d 次滑动屏幕" % (task, i))
BasePage(driver).swipe_up(0.3)
else:
print(task + "==>" + ele.text)
break
return ele
"""获取x轴宽度"""
@property
def x(self):
return self.get_window_size['width']
"""获取y轴高度"""
@property
def y(self):
return self.get_window_size['height']
"""
手指向上滑动
scale: 滑动距离所占比例
duration: 滑动从起点到终点坐标所耗费的时间ms
起点: 0.5x, (1+scale)*y/2
终点: 0.5x, (1-scale)*y/2
"""
def swipe_up(self, scale=0.8, duration=800):
print('swipe_up')
self.driver.swipe(self.x*0.5, self.y*(1+scale)/2, self.x*0.5, self.y*(1-scale)/2, duration)
这种滑动操作可以封装到一个模块就行,参考博客:App自动化测试(五)之swipe滑动操作_DesireYang的博客-CSDN博客
如果一个页面遇到多个滚动窗口,参考这个:Multiple scroll views - Appium
# first scrollView
# FindElement
MobileElement element = (MobileElement) driver.findElement(MobileBy.AndroidUIAutomator(
"new UiScrollable(new UiSelector().scrollable(true).instance(0))" +
".scrollIntoView(new UiSelector().text(\"exact_text\"))"));
# second scrollView
# FindElement
MobileElement element = (MobileElement) driver.findElement(MobileBy.AndroidUIAutomator(
"new UiScrollable(new UiSelector().scrollable(true).instance(1))" +
".scrollIntoView(new UiSelector().text(\"exact_text\"))"));
# FindElement
MobileElement element = (MobileElement) driver.findElement(MobileBy.AndroidUIAutomator(
"new UiScrollable(new UiSelector().resourceIdMatches(\".*part_id.*\").scrollable(true))" +
".scrollIntoView(new UiSelector().text(\"exact_text\"))"));
1. 创建表时,主键要创建为 INTEGER PRIMARY KEY,其实我觉得最好再加上自增 AUTOINCREMENT ,这样最简单最完美。
2. 带有 INTEGER PRIMARY KEY 列的SQLite 数据库表,其 rowid 就是 该INTEGER PRIMARY KEY 列。所以,使用 cursor.lastrowid 得到就是我们的ID值了。
注意:INTEGER PRIMARY KEY 不要写成了 int primary key。大小写无所谓,但是 integer 不要写成了 int,因为 int 不是 sqlite 的基本数据类型。
————————————————
版权声明:本文为CSDN博主「qilei2010」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:【Python】SQLite3获取新插入的记录ID及ROWID探究_qilei2010的博客-CSDN博客_sqlite3 获取自增id