TouchAction 中 move to 使用相对坐标还是绝对路标的问题
和appium版本号有关,和wait的放置位置有关
在appium1.7中
TouchAction(driver).press.wait.move_to # swipe 绝对坐标
TouchAction(driver).press.move_to.wait # 相对坐标
在appium1.8中
TouchAction(driver).press.wait.move_to #绝对坐标
TouchAction(driver).press.move_to.wait # 绝对坐标
线程
多任务的简单介绍
- 有很多事情在现实生活的场景中是同时进行的,比如开车的时候 手和脚共同来驾驶汽车,再比如唱歌跳舞也是同时进行的。
- 多任务,就是能够在同一时间同时进行多个任务。
import time
import threading
def sing():
for i in range(5):
print("唱歌")
time.sleep(1)
def dance():
for i in range(5):
print("跳舞")
time.sleep(1)
# 主线程在从上往下跑
# 开一个子线程
t1 = threading.Thread(target=sing)
# 又开一个子线程
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
多任务的原理
什么叫“多任务”呢?简单地说,就是操作系统可以同时运行多个任务。打个比方,你一边在用浏览器上网,一边在听MP3,一边在用Word赶作业,这就是多任务,至少同时有3个任务正在运行。还有很多任务悄悄地在后台同时运行着,只是桌面上没有显示而已。
-
单核cpu工作原理
- 现在,多核CPU已经非常普及了,但是,即使过去的单核CPU,也可以执行多任务。由于CPU执行代码都是顺序执行的,那么,单核CPU是怎么执行多任务的呢?
- 答案就是操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。
- 真正的并行执行多任务只能在多核CPU上实现,但是,由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。
-
多核cpu工作原理
- 和单核类似,相当于多了一个干活的人。
并发:指的是任务数多于cpu核数,通过操作系统的各种任务调度算法,实现用多个任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已)
- 并行:指的是任务数小于等于cpu核数,即任务真的是一起执行的
- 并行和并发都算是多任务,但并行实际上才是真正的多任务,并发是假的。
多任务的实现方法有多种,线程只是其中一种
线程的工作原理
以唱歌跳舞的案例说明
-
主线程
- 我们常说的一个程序代码会从上往上执行,默认就是主线程来执行的。
-
子线程
- 人工开启的线程。主线程会等待子线程结束后再结束。
- 子线程的任务完成,这个子线程就会消失了
线程和线程之间会进行资源的抢夺,谁先执行谁后执行是不一定的
线程的两种创建方式
- 直接使用threading模块的Thread类,指定要执行的方法,再调用start
- 使用继承的方式,继承Thread类,重新run方法,创建这个对象后,再调用start
查看当前程序线程数量
- threading.enumerate()
- 获取所有线程,返回的是一个列表。
- 如果需要个数,使用len(threading.enumerate())
为子线程传递参数
- target方式
import time
import threading
def sing(nums):
for i in range(nums):
print("唱歌")
time.sleep(1)
def dance():
for i in range(5):
print("跳舞")
time.sleep(1)
# args后面跟的是参数元组
# kargs后面跟的是参数字典,
# 但在这里,如果用的是字典,字典的keys的名字要和target中的函数的参数名字一致
t1 = threading.Thread(target=sing, args=(3,))
# 或者 t1 = threading.Thread(target=sing, kargs={"nums" : 3})
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
- 类继承方式
import threading
class Work1(threading.Thread):
def __init__(self, nums):
# 要重写父类的__init__方法,首先要在里面继承父类的__init__方法
# 或者super().__init__()
threading.Thread.__init__(self)
self.nums = nums
def run(self):
for i in range(self.nums):
print("haha")
def main():
w = Work1(2)
w.start()
if __name__ == "__main__":
main()
多线程的应用
在下载事件或者请求涉及到网络的时候,会是多线程的形式进行
点下载以后就会开一个线程让它去下载,主线程可以不用等下载完成了再去做别的操作
队列(queue)和栈(stack)的概念
队列:先进先出,在手机应用中有个运行循环,在监听事件操作,不是多线程的话,事件在队列中过来,只有前一个事件运行完了,下一个事件再进去循环,再进行下一个事件
栈:先进后出,----> 名词概念:进==>进栈,出==>出栈 或 弹栈,栈中最上面==>栈顶,栈中最下面==>栈底
appium多端口
目标,让一个脚本去跑到多台手机。
实现的思想:要开多个appium服务(对应多个端口号),然后不同的appium服务去连对应的多个手机(对应多个udid,只是一个唯一标识的字符串)打开多个appium服务:命令行打开appium,
appium -p 4723
,appium -p 4725
打开多个bootstrap服务(bootstrap引导的意思),与多个手机一一对应
打开多个手机:在virtualbox里面,再导入多一个虚拟电脑,在genymotion里面就会多一个手机模拟器,点start就好了
注意点: appium sever端口要不同,开启多个。bootstrap端口要不同,开启多个。udid需要指定,udid表示设备的唯一表示符号,通过 adb devices 查看。 前半部分都是,比如模拟器的(192.168.57.101:5555)。
appium server 和 bootstrap 和 udid 应该是成对出现的。
命令:
appium -p 4723 -bp 4724 -U 192.168.57.101:5555
p 表示 appium的端口
bp 表示 bootstrap的端口
U 表示设备的标识符
修改init_driver让,init_driver接受port的参数。并且进行对应的连接。
记得,创建的是不同的driver对象。因为如果使用threading.Thread的这种形式,需要指定执行的函数,所以,把需要执行的代码,封装成一个函数。然后使用以下代码:
在base_driver中
from appium import webdriver
def init_driver(port="4723"):
# server 启动参数
desired_caps = dict()
# 设备信息
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.164.101:5555'
# app信息
desired_caps['appPackage'] = 'com.android.settings'
desired_caps['appActivity'] = '.Settings'
# 中文
desired_caps['unicodeKeyboard'] = True
desired_caps['resetKeyboard'] = True
# 不重置应用
desired_caps['noReset'] = True
# toast
# desired_caps['automationName'] = 'Uiautomator2'
# 声明对象
driver = webdriver.Remote('http://localhost:' + port + '/wd/hub', desired_caps)
return driver
在test_demo中:
import threading
from selenium.webdriver.common.by import By
from base_driver import init_driver
from base_action import BaseAction
from login_page import LoginPage
def do(port):
driver = init_driver(port)
login_page = LoginPage(driver)
if "4723" == port:
login_page.click((By.XPATH, "text,更多"))
else:
login_page.click((By.XPATH, "text,WLA"))
def main():
ports = ["4723", "4725"]
for i in ports:
threading.Thread(target=do, args=(i,)).start()
# for i in ports:
# driver = init_driver(i)
# login_page = LoginPage(driver)
# login_page.click((By.XPATH, "text,更多"))
if __name__ == '__main__':
main()
来去执行创建多个driver并且进行脚本的操作。
Webview
使用inspect检查元素的好处是可以实时更新你在手机模拟器中的操作,但要翻墙
iOS
测试一个iOS项目的方法
开发ios的应用可以用Xcode软件,相当于开发安卓软件的Android studio,要测试ios应用也要用Xcode,因为Xcode中才有模拟器
拿到这个项目文件,蓝色文件用Xcode打来,选择好模拟器,先运行一下(就会在模拟器中安装这个项目的app了),然后可以在模拟器中做相关操作(home键是键盘中的command+H),也可以在Xcode中我们可以找到一些项目的信息(例如设备信息,app信息,需要在测试脚本的前置代码中填写的)
如果在Xcode中的Products文件夹下的app名字报红了(就是还没有安装这个app),就可以先运行一下(command+r),或者按着那个报红的文件编译一下(command+b)
-
还是在pycharm中写测试脚本,在pycharm的terminal中pytest运行
- 前置信息中,如果没有安装这个app,可以在Xcode中点Products下的已经编译过的app文件右键show in Finder(相当于windows中的资源管理器),然后复制一份里面的.app文件,去到你电脑测试项目文件夹下, 然后在前置代码中的desired_caps['app'] = os.path.abspath("./xxx.app")
- 建议拿到项目后先在Xcode运行,模拟器中安装了这个app就不用上面这种形式了
在iOS中,(View)Controller就相当于安卓中的activity,一个界面对应一个controller
在Xcode中运行iOS项目
iOS前置代码
对于已经安装了这个ios项目,如何在Xcode中获取它的bundleid信息(前置代码中app信息,其实就是bundleid,相当于安卓中的包名)
appium应用的另一个功能,可以查看页面元素
appium查看元素-android
appium左侧三个功能和右侧五个功能
appium查看元素-iOS
点击事件
滑动
Monkey
Monkey介绍
-
monkey 要用命令启动的话,首先要保证安卓模拟器是开着的
Monkey输出日志
-
-p后面是要测试的包名,100是要执行多少次动作
Monkey基本参数介绍
- 课外知识:md5加密算法
- 每次做monkey都建议加上-s seed值
- 延时设置的是每个事件之间的时间间隔,并不是每个动作,这里例子中的参数100,就是动作,100个动作可能就几个事件
-
可以通过-- pct-touch
等去控制想要发生的事件/动作的比例
Monkey日志分析
-
如果出现了Exception,就拿之前设置的seed去复现,看点哪里出现问题,再拿真机去试操作,看是不是真的有问题
MonkeyRunner
- MonkeyRunner是一套工具,一套API,可以用python代码去控制Monkey,告诉它去怎么生成这些随机的事件
- 本质和Monkey做的事情是一样的,但Monkey是用命令行实现的,一个使用代码调用MonkeyRunner API实现的(MonkeyRunner底层也是用Monkey)
分辨率
像素
- 像素是长度单位,一个像素就是一个小方格,一个小方格里面会有几个色块,当你在电脑屏幕上看到一个图片是红色的时候,里面的像素小方格里面的色块就只有红色有数值,其余的色块都是零,这就实现了显示红色了
- 但为什么两台设备有一样的物理尺寸,不一样的分辨率,看到的图片位置大小都一样?
- 这就涉及像素密(密度,pixels for inch)的问题,在同样尺寸,不同分辨率的两台设备中,项目会准备大小不同的图片(1x,2x,3x,安卓项目是在不同的文件夹下有相同的名称的图片,ios项目是在同一个文件夹下有不同名称的图片),让图片会去适配,例如在小分辨率中占30像素的图片,在分辨率大一倍的设备中就会占60像素
- 在功能测试中,如果要测分辨率,就拿对应的图片大小去测主流分辨率的屏幕设备
补充:
- token ---> 在大部分的开发项目中表示身份,就是表示身份信息
测试流程
- 中断测试不常见,但是像游戏这种需求实时性的应用可能要做一下,但人工做就可以了
-
密码MD5算法加密的是不可逆的,存在数据库中的密码也是加密过的,用户请求发送过来的密码(加密了)与数据库中的加密过的密码比对,一样就能登陆