杭州软件测试培训有用吗,杭州软件测试培训靠谱吗

小白也能学会的模拟屏幕滑动与手势密码绘制 - 51Testing软件测试网

小白也能学会的模拟屏幕滑动与手势密码绘制

发表于:2019-8-13 13:32  作者:linux超   来源:博客园

前言  App自动化测试中有两个很重要的操作,屏幕滑动与绘制手势密码。目前很多App在启动时,都存在启动时的引导动画或者加载上下文内容时需要手动上滑或者下滑加载页面,所以在自动化测试的过程中模拟手的滑动操作看起来就很重要了;第二个比较重要的是模拟手动绘制九宫格完成手势密码的设置,这种手势密码在我了解的范围内,大多在金融类的app中最常见,还有一些对用户信息保密性较好的app中,所以,模拟绘制手势密码也是app自动化测试中必须掌握的操作,那么接下来我们就开始讲解两种操作该如何实现, 在进入正题之前,你还应该知道,手机中横纵坐标的原点是从屏幕的左上角顶点(0, 0)的位置开始的  滑动屏幕  swipe方法  模拟滑动屏幕的操作,我们通过swipe方法实现,先看一下这个方法的源代码

def swipe(self, start_x, start_y, end_x, end_y, duration=None):  """Swipe from one point to another point, for an optional duration.  Args:  start_x (int): x-coordinate at which to start  start_y (int): y-coordinate at which to start  end_x (int): x-coordinate at which to stop  end_y (int): y-coordinate at which to stop  duration (:obj:`int`, optional): time to take the swipe, in ms.  Usage:  driver.swipe(100, 100, 100, 400)  Returns:  `WebElement`  """  # `swipe` is something like press-wait-move_to-release, which the server  # will translate into the correct action  action = TouchAction(self)  action \  .press(x=start_x, y=start_y) \  .wait(ms=duration) \  .move_to(x=end_x, y=end_y) \  .release()  action.perform()  return self

参数  start_x, start_y : 表示开始滑动时的初始坐标,也就是从哪里开始滑动  end_x,   end_y : 表示滑动后的坐标,也就是滑动到哪里  duration:     : 表示滑动过程的时间间隔,模拟操作时,我们**设置个时间间隔,避免由于代码运行太快,而真机或者模拟器反应比较慢,而操作失败,单位以毫秒计算  通过源码,我们发现swipe方法实际上是使用TouchAction实现的,这个类在后面我们仍然会使用,主要是模拟一些触屏动作  实现思路  大家可以想象一下,平时我们滑动屏幕时,是如何操作的?例如向左滑动屏幕,我们往往是把手放在屏幕的右侧,然后按住屏幕向左滑动,那么代码如何知道我们从屏幕的哪个位置开始讷?那就是坐标了,我们可以先获取屏幕的宽,高,然后按照它的比例计算鼠标的位置坐标,我这里取的起始坐标点为屏幕宽度的0.9倍,高度的0.5倍,大概就是我们实际中滑屏时手指的操作位置。大家可以根据下面播放的动画观察鼠标开始的大概位置和结束位置  接下来我们开始模拟动画中鼠标的操作(人手的操作,我用的模拟器所以有鼠标)  首先我们通过get_window_size()方法获取屏幕的宽和高(这个方法返回一个字典),然后计算鼠标的初始位置和结束为止

def get_phone_size(self):  """获取屏幕的大小"""  width = self.driver.get_window_size()['width']  # 获取屏幕的宽  height = self.driver.get_window_size()['height']  # 获取屏幕的高  return width, height

通过模拟动画不难看出,鼠标大概从起始点坐标(屏幕宽的3/4,高的1/2)位置滑动到结束点坐标(屏幕宽1/4,高1/2),ok,接下来通过swipe()方法实现滑动操作

def swipe_left(self, duration=300):  """左滑"""  width, height = self.get_phone_size  start = width * 0.9, height * 0.5  end = width * 0.1, height * 0.5  return self.driver.swipe(*start, *end, duration)  def swipe_right(self, duration=300):  """右滑"""  width, height = self.get_phone_size  start = width * 0.9, height * 0.5  end = width * 0.1, height * 0.5  return self.driver.swipe(*start, *end, duration)  def swipe_up(self, duration):  """上滑"""  width, height = self.get_phone_size  start = width * 0.9, height * 0.5  end = width * 0.1, height * 0.5  return self.driver.swipe(*start, *end, duration)  def swipe_down(self, duration):  """下滑"""  width, height = self.get_phone_size  start = width * 0.9, height * 0.5  end = width * 0.1, height * 0.5  return self.driver.swipe(*start, *end, duration)

方法优化  以上每一个方法调用一次只能滑动一次,而且不同的滑动方向需要调用不同的方法,使用时比较麻烦。所以我们可以优化一下代码,通过调用一个函数实现不同次数,不同方向的滑动  使用for循环实现连续的滑动,引入direction参数,结合字典及反射机制,实现根据不同的参数执行不同滑动方向的方法,传递num参数控制滑动的次数,具体代码如下

def skip_welcome_page(self, direction, num=3):  """  滑动页面跳过引导动画  :param direction:  str 滑动方向,left, right, up, down  :param num: 滑动次数  :return:  """  direction_dic = {  "left": "swipe_left",  "right": "swipe_right",  "up": "swipe_up",  "down": "swipe_down"  }  time.sleep(3)  if hasattr(self, direction_dic[direction]):  for _ in range(num):  getattr(self, direction_dic[direction])()  # 使用反射执行不同的滑动方法  else:  raise ValueError("参数{}不存在, direction可以为{}任意一个字符串".  format(direction, direction_dic.keys()))

以上就是所有滑动屏幕的操作了,具体效果,我们后面再看(你也可以先试试)  手势密码  TouchAction类  模拟手势密码的绘制我们使用TouchAction类,这个类提供了短按压press()方法,wait()方法,move_to()方法,release()方法,perform()方法等常用方法,下面我简单说明一下这几个方法的作用  press(element, x, y)  : 其中element参数是一个元素对象,当element不为空时,x和y必须位None,如果element为None时,x如果不为None,那么y也不能位None,也就是说在安卓操作系统中,element和(x,y)必要传递一个,苹果系统可以不传,这里不做介绍  wait(duration) : duration是时间,以毫秒为单位,这个方法的作用是等待一段时间,和sleep的作用类似,**区别sleep不能被TouchAtion对象访问  release() : 这个方法的作用是结合press等按压动作使用的,表示抬起动作  perform():这个方法的作用是使所有的按压及等待,release等动作生效  实现思路  模拟大多app中的手势设置密码操作会遇见两种情况,一种是9宫格中每一个点的元素都可以通过定位表达式定位到,另一种是每个点无法通过定位表达式定位到的,只能定位到整体9宫格元素,每个点只能通过获取坐标的方式定位,那么我们今天模拟绘制手势密码的情况就是第二种,如果这种掌握了,那么第一种更简单,下面我们分析一下该如何获取每一个点的坐标,先来看下面的图  上图中的x轴,y轴是手机的坐标表示方式,请区别数学中的二维坐标,其中x轴方向表示手机屏幕的宽度width,y轴方向表示屏幕的高度height,原点为(0, 0); 蓝色方框代表9宫格手势操作的整体元素(内部包含9个点),start_x, start_y 代表9宫格元素的起始坐标点,start_x也是9宫格起始点距离y轴的距离,start_y也是9宫格起始点距离x轴的距离,请大家一定理解这几个值的关系,下面我们可以通过WebElement对象的rect方法获取9宫格元素的宽,高及起始点坐标

def get_element_size_location(element):  width = element.rect["width"]  # 9宫格元素的宽度  height = element.rect["height"]  # 9宫格坐标的高度  # 9宫格元素的起始坐标点  start_x = element.rect["x"]  start_y = element.rect["y"]  return width, height, start_x, start_y

除了使用rect方法外,你还可以使用location和size方法分别获取元素的起始点坐标和宽,高,两个方法同样返回字典  element.location ->{"x": start_x, "y": start_y}  element.size ->{"width": width, "height": height}  接下来我们通过9宫格元素的width,height,start_x, start_y分别计算每个点的坐标, 我们按照上图,把9宫格元素的width和height分别等分为6等分  前3个点(1, 2, 3)的坐标分别是

width, height, start_x, start_y = self.get_element_size_location(element)  point_1 = {"x": int(start_x + width * (1 / 6) * 1), "y": int(start_y + height * (1 / 6) * 1)}  point_2 = {"x": int(start_x + width * (1 / 6) * 3), "y": int(start_y + height * (1 / 6) * 1)}  point_3 = {"x": int(start_x + width * (1 / 6) * 5), "y": int(start_y + height * (1 / 6) * 1)}

中间3个点(4, 5, 6)的坐标分别为

point_4 = {"x": int(start_x + width * (1 / 6) * 1), "y": int(start_y + height * (1 / 6) * 3)}  point_5 = {"x": int(start_x + width * (1 / 6) * 3), "y": int(start_y + height * (1 / 6) * 3)}  point_6 = {"x": int(start_x + width * (1 / 6) * 5), "y": int(start_y + height * (1 / 6) * 3)}

最后3个点(7, 8, 9)的坐标分别为

point_7 = {"x": int(start_x + width * (1 / 6) * 1), "y": int(start_y + height * (1 / 6) * 5)}  point_8 = {"x": int(start_x + width * (1 / 6) * 3), "y": int(start_y + height * (1 / 6) * 5)}  point_9 = {"x": int(start_x + width * (1 / 6) * 5), "y": int(start_y + height * (1 / 6) * 5)}

下面我们使用TouchAction类中的move_to,wait,release,perform方法实现从一个点移动到另一个点,进而实现模拟手势密码的连线操作(链接1-2-3-6-9)

TouchAction(driver).press(x=point_1["x"], y=point_1["y"]).wait(300)\  .move_to(x=point_2["x"], y=point_2["y"]).wait(500)\  .move_to(x=point_3["x"], y=point_3["y"]).wait(500)\  .move_to(x=point_6["x"], y=point_6["y"]).wait(500)\  .move_to(x=point_9["x"], y=point_9["y"]).wait(500).release().perform()

完整代码  不包含滑动屏幕的代码  base.py

"""  ------------------------------------  @Time : 2019/8/6 20:22  @Auth : linux超  @File : base.py  @IDE  : PyCharm  @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!  @QQ   : 28174043@qq.com  @GROUP: 878565760  ------------------------------------  """  from appium.webdriver import WebElement  from appium.webdriver.common.touch_action import TouchAction  from appium.webdriver.webdriver import WebDriver  from selenium.webdriver.support.wait import WebDriverWait  from selenium.common.exceptions import NoSuchElementException, TimeoutException  class Base(object):  def __init__(self, driver: WebDriver):  self.driver = driver  @staticmethod  def get_element_size_location(element):  width = element.rect["width"]  height = element.rect["height"]  start_x = element.rect["x"]  start_y = element.rect["y"]  return width, height, start_x, start_y  def gesture_password(self, element: WebElement):  width, height, start_x, start_y = self.get_element_size_location(element)  point_1 = {"x": int(start_x + width * (1 / 6) * 1), "y": int(start_y + height * (1 / 6) * 1)}  point_2 = {"x": int(start_x + width * (1 / 6) * 3), "y": int(start_y + height * (1 / 6) * 1)}  point_3 = {"x": int(start_x + width * (1 / 6) * 5), "y": int(start_y + height * (1 / 6) * 1)}  point_4 = {"x": int(start_x + width * (1 / 6) * 1), "y": int(start_y + height * (1 / 6) * 3)}  point_5 = {"x": int(start_x + width * (1 / 6) * 3), "y": int(start_y + height * (1 / 6) * 3)}  point_6 = {"x": int(start_x + width * (1 / 6) * 5), "y": int(start_y + height * (1 / 6) * 3)}  point_7 = {"x": int(start_x + width * (1 / 6) * 1), "y": int(start_y + height * (1 / 6) * 5)}  point_8 = {"x": int(start_x + width * (1 / 6) * 3), "y": int(start_y + height * (1 / 6) * 5)}  point_9 = {"x": int(start_x + width * (1 / 6) * 5), "y": int(start_y + height * (1 / 6) * 5)}  TouchAction(self.driver).press(x=point_1["x"], y=point_1["y"]).wait(300) \  .move_to(x=point_2["x"], y=point_2["y"]).wait(500) \  .move_to(x=point_3["x"], y=point_3["y"]).wait(500) \  .move_to(x=point_6["x"], y=point_6["y"]).wait(500) \  .move_to(x=point_9["x"], y=point_9["y"]).wait(500).release().perform()  def find_element(self, locator: tuple, timeout=30) -> WebElement:  wait = WebDriverWait(self.driver, timeout)  try:  element = wait.until(lambda driver: driver.find_element(*locator))  return element  except (NoSuchElementException, TimeoutException):  print('no found element {} by {}', format(locator[1], locator[0]))  if __name__ == '__main__':  pass

【测试入门必备】细说Sqlserver与第三方工具相互间的关系

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/442169.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

priority_queue(优先队列)的简单构造与用法

priority_queuepriority_queue 优先队列,其底层是用堆来实现的。在优先队列中,队首元素一定是当前队列中优先级最高的那一个。在优先队列中,没有 front() 函数与 back() 函数,而只能通过 top() 函数来访问队首元素(也可…

局域网服务器文件夹隐藏,局域网服务器共享文件夹访问权限设置win7隐藏无权限共享文件夹方法.docx...

局域网服务器共享文件夹访问权限设置win7隐藏无权限共享文件夹方法??局域网服务器共享文件夹访问权限设置、win7隐藏无权限共享文件夹的方法在局域网文件管理中,文件服务器共享文件的管理一直是当前网络管理的重要工作。尤其是很多单位的服务器共享文件常常是单位…

关于时间复杂度(持续更新.....)

数据范围小于100W的(1e6),nlogn是1000w左右,可以卡时。 数据范围小于1000的,勉强可以o(n^2)。 数据范围1000W左右的(1e7),只能考虑o(n)或者o(logn) 数据范围大于1000W的(1e7)&…

三星电视出现服务器未响应,三星电视遥控器失灵怎么办

feng1054592015-09-26 23:22解决办法一:(三星电视用户专用)1、检查遥控器到三星电视机接收位置中间是否有障碍物;2、在同一房间使用无线路由器、手机等设备的无线功能,可能会干扰红外信号的发送与接收;3、对遥控器进行复位操作&am…

sdut 2074 区间覆盖问题(贪心)

区间覆盖问题Time Limit: 1000MS Memory limit: 65536K题目描述用i来表示x坐标轴上坐标为[i-1,i]的长度为1的区间,并给出n(1≤M≤200)个不同的整数,表示n个这样的区间。现在要求画m条线段覆盖住所有的区间,…

http协议与服务器通信,iPhone应用用HTTP协议和服务器通信

iPhone应用用HTTP协议和服务器通信是本文要介绍的内容,主要是来学习iphone应用中的通信协议,具体内容来看本文详解。iPhone用http协议和服务器通信有两种方式,一种是同步一种是异步的,所谓同步是指当客户端调用post/get的方式的函…

[sicily]【1001】 会议安排(田忌赛马类贪心)

题干&#xff1a; N个会议要同时举行&#xff0c;参会人数分别为A[0], A[1], ...,A[N-1]. 现有M个会议室&#xff0c;会议室可容纳人数分别为B[0], B[1], ...,B[M-1]. 当A[i]<B[j]时&#xff0c;可以把会议i安排在会议室j&#xff0c;每间会议室最多安排一个会议&#xff0c…

设备怎样开启位置服务器,开启设备服务器

开启设备服务器 内容精选换一换购买Windows弹性云服务器后&#xff0c;通过MSTSC远程连接&#xff0c;发现没有声音。通过MSTSC远程连接的Windows弹性云服务器如何播放音频&#xff1f;本节内容适用于Windows Server 2008 R2、Windows Server 2016系统的弹性云服务器。Windows弹…

高端又易学的vbs表白程序了解一下

第一个、 打开txt文件&#xff0c;复制以下代码粘贴进去&#xff08;可以修改中文部分&#xff0c;其它代码不要动&#xff01;&#xff09;。保存并关闭txt文件。 msgbox("做我女朋友好吗&#xff1f;") msgbox("房产证上写你名字") msgbox("保大&qu…

离散化处理 模板

离散化模板&#xff1a; #include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int maxn100000; int a[maxn]; int b[maxn]; int n,m; void lisan(); int main() {cin>>n;//元素个数for(int i1;i<n;i) {scanf(&qu…

cf#401(Div. 2)B. Game of Credit Card(田忌赛马类贪心)

题干&#xff1a;After the fourth season Sherlock and Moriary have realized the whole foolishness of the battle between them and decided to continue their competitions in peaceful game of Credit Cards. Rules of this game are simple: each player bring his fa…

NYOJ-14 会场安排问题(经典贪心,区间完全不覆盖模板)

附另一&#xff1a;此类问题选题总结&#xff1a;https://blog.csdn.net/qq_41289920/article/details/81001357 题干&#xff1a; 会场安排问题时间限制&#xff1a;3000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;4描述学校的小礼堂每天都会有许多活动&#xff0c;有…

可以使用田忌赛马类贪心问题的前提(或说 如何判断题目符合田忌赛马类贪心问题)

前提就是&#xff0c;首先&#xff0c;需要两个数组&#xff01;&#xff01;两个数组&#xff01;&#xff01;两个数组&#xff01;&#xff01;才可以考虑这个&#xff01; 其次&#xff0c;A和B这两个数组的个数是相同的。也正因为如此&#xff0c;所以从大到小排序或者从小…

【nyoj 270】数的分解(统计因子模板)

题干&#xff1a; 数的分解时间限制&#xff1a;1000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;1描述你的任务是找到一个最小的正整数Q&#xff0c;使Q的各位数的乘积等于N。输入最多450组测试数据。数据以EOF结尾。输入一个整数N&#xff08;0 ≤ N ≤ 400)。输出…

asp.net mvc 地址栏传输信息报错:window.location.pathname

asp.net mvc 地址栏传输信息报错&#xff1a;window.location.pathname 前端cshtml代码内容 代码片. // 页面跳转 window.location.pathname /Home/Index?cc123;“/”应用程序中的服务器错误 从客户端(?)中检测到有潜在危险的 Request.Path 值。 如何解决 web.config中添…

区间覆盖全部类型及部分精选习题汇总详解(贪心策略)

内容如下&#xff1a; 1&#xff09;区间完全覆盖问题 问题描述&#xff1a;给定一个长度为m的区间&#xff0c;再给出n条线段的起点和终点&#xff08;注意这里是闭区间&#xff09;&#xff0c;求最少使用多少条线段可以将整个区间完全覆盖 样例&#xff1a; 区间长度8&#…

数据库提示:正在还原中,无法访问 应该怎么办?

Sql语句 restore database 数据库名 with recovery

数据库工具一段时间后打开报错:远程过程调用失败0x800706be

1.原因可能是安装vs时自带更高版本的sql server服务造成的&#xff0c;只需要卸载Microsoft SQL Server 2012 Express LocalDB或 Microsoft SQL Server 2012 LocalDB就行了 2.先安装vs工具&#xff0c;然后安装数据库工具

【POJ - 1328】Radar Installation(贪心+计算几何)安装雷达辐射岛屿

题干&#xff1a;Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. Each small island is a point locating in the sea side. And any radar installation, locating on the coasting, can only cover d distance, so …

sql语句实现分页查询

2005及以上版本 -- 分页查询&#xff08;通用型&#xff09; select top pageSize * from (select row_number() over(order by sno asc) as rownumber,* from student) temp_row where rownumber>((pageIndex-1)*pageSize);2012及以上版本 select * from student orde…