移动测试学习笔记

测试流程

在这里插入图片描述

1、参与需求评审
2、编写测试计划和测试方案
	a. 要测试的功能模块
	b. 测试人员分工和时间安排
	c. 测试环境
	d. 测试策略
	e. 风险评估
3. 编写测试用例并组织用例评审
4. 执行测试用例,跟踪缺陷解决
5. 编写测试报告
	a. 邮件形式
	b. 覆盖功能模块
	c. 测试用例覆盖率
	d. 缺陷攻击/遗留缺陷
	e. 结论:是否允许上线 

熟悉项目

  • 项目的作用
  • 项目的用户和角色
  • 项目的功能架构:功能模块,功能点

测试要点

  • 功能测试⭐️
  • 兼容性测试⭐️
  • 安装、卸载、升级测试⭐️
  • 交叉事件测试⭐️
  • PUSH测试⭐️
  • 性能测试:CPU、内存、流量测试、电量测试、流畅度测试、启动测试
  • 用户体验测试⭐️
  • 稳定性测试

兼容性

云测平台 testin
统计网站:https://gs.statcounter.com/android-version-market-share/mobile-tablet/united-states-of-america

  1. 手机型号
  2. 系统版本:ios15/16/17/18(17和18最多);android 11/12/13/14/15(13和14最多)
  3. 屏幕尺寸、分辨率。
    a. 分辨率:720 x 1280、1440 x 2560、1080 x 1920、2160 x 3840
  4. 网络:3G、4G、5G、WIFI
  5. 应用兼容性
    a. 与手机硬件兼容:home键、电源键、音量调节等
    b. 与外部硬件兼容:耳机、蓝牙
    c. 与操作系统软件兼容:系统时间调节、WLAN设置、LBS定位
    d. 与其他app兼容

安装卸载

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

交叉事件测试

在这里插入图片描述

push消息推送

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

性能测试

常见指标

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

solopi工具

cpu排查

在这里插入图片描述

cpu温度

正常温度:30–40

内存

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

流畅度

在这里插入图片描述

流量测试

在这里插入图片描述

电量

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

冷热启动

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

用户体验

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

一、软件测试知识概述

1. 移动端测试是什么?
  • 移动测试是指对移动应用进行测试,即实体的特性满足需求的程度
2.移动测试分类
  • app功能测试
    1. 业务逻辑正确性测试

      产品文档

    2. 兼容性测试

      系统版本
      分辨率
      网络情况

    3. 异常测试

      热启动应用
      网络切换&中断恢复
      电话&信息中断恢复

    4. 升级&安装&卸载测试
    5. 健壮性测试

      手机资源消耗
      流量消耗
      崩溃恢复等测试

  • app自动化测试

    通过场景数据的预设,把以人为驱动的测试行为转化为机器执行的一种过程
    ps:并不是所有的功能都能进行自动化

  • app安全测试

    通过安全测试技术,保证app尽可能的不存在安全漏洞

二、 环境搭建

三、ADB命令

1. ADB

adb全名:android debug bridge,是一个标准的C/S结构的工具
包含如下几个部分:
1. Client端,运行在开发机器中,用来发送adb命令
2. Daemon守护进程,运行在调试设备中,即手机&模拟器
3. Server端,作为一个后台进程运行在开发机器中,用来管理pc中Client端和手机的Daemon之间的通信
在这里插入图片描述

2.简单命令
  1. 启动 adb 服务

    adb start-server

  2. 关闭 adb 服务

    adb kill-server

  3. 获取设备号

    adb devices

  4. 获取系统版本

    adb -s 设备号 shell getprop ro.build,version.release(多个设备)
    adb shell getprop ro.build.version.release(单个设备)

  5. 发送文件到手机

    adb push PC端路径/需要发送的文件 手机端存储的路径

    C:\Users\liliai>adb push C:\Users\Eric\Desktop\push.txt /sdcard/push.txt
    
  6. 从手机拉去文件

    adb pull 手机端路径/拉去文件名 PC存储文件路径

    C:\Users\liliai>adb pull /sdcard/push.txt C:\Users\Eric\Desktop\push.txt
    
  7. 查看手机运行日志

    adb logcat

    代码实现:将通讯录的日志输出到桌面上

    # 此处使用find 对通讯录包名(com.android.contacts) 过滤
    C:\Users\liliai>adb logcat | find "com.android.contacts" >>C:\Users\liliai\Desktop\log.txt
    
  8. 手机 shell 命令行

    adb shell

    代码实现:查看cpu

    adb shell top
    
  9. 获取app启动包名&启动名

    adb shell pm list packages # 查看所有的包名
    adb shell pm list packages -3 # 列出第三方包
    adb shell pm list packages -3 | findstr "girafit" # 根据app名过滤
    adb shell dumpsys package <包名> # 查看应用的详细信息
    
  10. 安装 app 到手机

    adb install 路径/xx.apk

  11. 卸载 app

    adb uninstall 包名

  12. 获取启动时间

    adb shell am start -W 包名/启动名
    解释:
    TotalTime:app自身启动时间
    WaitTime:系统启动应用时间

    代码实现:查看网易云音乐的启动时间

    C:\Users\Eric>adb shell am start -W com.netease.cloudmusic/.activity.MainActivity
    Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.netease.cloudmusic/.activity.MainActivity }
    Status: ok
    Activity: com.netease.cloudmusic/.activity.MainActivity
    ThisTime: 3748
    TotalTime: 3748
    Complete
    	```
    
    
    

四、appium学习

第一个例子
	#导入webdriver
	from appium import webdriver
	import time
	
	# --------------------------------->server 启动参数
	desired_caps = {}
	# 系统
	desired_caps['platformName'] = 'Android'
	# 版本
	desired_caps['platformVersion'] = '5.1'
	# 设备号
	desired_caps['deviceName'] = '192.168.52.104:5555'
	
	# app信息
	# 包名
	desired_caps['appPackage'] = 'com.android.settings'
	# 启动名
	desired_caps['appActivity'] = '.Settings'
	
	desired_caps['unicodekeyboard']True
	desired_caps['resetkeyboard']True
	# ------------------------------------>启动参数end
	# 声明手机驱动对象
	driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)
	
	# 关闭app,不关闭驱动
	driver.close_app()
	
	# 打开app
	driver.start_activity("com.android.dialer", ".DialtactsActivity")
	
	# 关闭驱动
	driver.quit()
App基本操作API
1. 前置代码

可以将此封装起来,用时候直接调用

	from appium import webdriver
	
	desired_caps = {}
	desired_caps['platformName'] = 'Android'
	desired_caps['platformVersion'] = '5.1'
	desired_caps['deviceName'] = '192.168.52.104:5555'
	desired_caps['appPackage'] = 'com.android.settings'
	desired_caps['appActivity'] = '.Settings'
	
	driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)
2.API基础
  • 安装app到手机

    driver.install_app(app_path)
    app_path:脚本机器中.apk的文件路径

  • 手机中移除app

    driver.remove_app(app_id)
    app_id:app的包名

  • 判断app是否已安装

    driver.is_app_installed(app_id)
    app_id: app包名;
    返回结果为True(已安装) / False(未安装)

  • 发送文件到手机

    import base64
    data = str(base64.b64encode(data.encode(‘utf-8’)),‘utf-8’)
    driver.push_file(path,data)
    参数:
    path:手机设备上的路径(例如:/sdcard/a.txt)
    data:文件内数据,要求base64编码
    Python3.x中字符都为unicode编码,而b64encode函数的参数为byte类型,需要 先转码;
    生成的数据为byte类型,需要将byte转换回去。

  • 从手机中拉去文件

    import base64
    data = driver.pull_file(path) # 返回数据为base64编码
    print(str(base64.b64decode(data),‘utf-8’)) # base64解码
    参数:
    path: 手机设备上的路径
    ps:此处在 str 与 betys 的转换,总是出现错误

  • 获取当前屏幕内元素结构

    driver.page_source

3.定位API
方式语法描述
idfind_element_by_id(id_value)通过id定位一个元素
find_elements_by_id(id_value)通过id定位一组元素
classfind_element_by_class_name(class_value)通过class定位一个元素
find_elements_by_class_name(class_value)通过class定位一组元素
xpathfind_element_by_xpath(xpath_value)通过xpath定位一个元素
find_elements_by_xpath(xpath_value)通过xpath定位一组元素

android端常用xpath的定位:

  1. id: //*[contains(@resource-id,‘id值’)]
  2. class: //*[contains(@class,‘class值’)]
  3. text: //*[contains(@text,‘text的部分值’)]
4.显示等待操作

在一个超时时间范围内,每隔一段时间去搜索一次元素是否存在,如果存在返回定位对象,如果不存在知道时间到达,报超时异常

导入:
from selenium.webdriver.support.wait import WebDriverWait

方法:WebDriverWait(driver, timeout, poll_frequency).until(method)
参数:
1. driver:手机驱动对象
2. timeout:搜索超时时间
3. poll_frequency:每次搜索间隔时间,默认时间为0.5s
4. method:定位方法(匿名函数)
5. 匿名函数: ambda x: x
等价于python函数:
def test(x)
return x

实例:

WebDriverWait(driver, timeout, poll_frequency).until(lambda x: x.find_elements_by_id(id_value))
解释:
1. x传入值为:driver,所以才可以使用定位方法.
函数运行过程:
1. 实例化WebDriverWait类,传入driver对象,之后driver对象被赋值给WebDriverWait的一个类变量:self._driver
2. until为WebDriverWait类的方法,until传入method方法(即匿名函数),之后method方法会被传入self._driver
3. 搜索到元素后until返回定位对象,没有搜索到函数until返回超时异常错误.

代码实现:

        from selenium.webdriver.support.wait import WebDriverWait # 导入WebDriverWait类
        # 超时时间为30s,每隔1秒搜索一次元素是否存在,如果元素存在返回定位对象并退出
        search_button = WebDriverWait(driver, 30, 1).until(lambda x: x.find_elements_by_id(com.android.settings:id/search))
        search_button.click()
        driver.quit()
5. app元素信息操作API
  • 点击元素

.click()

  • 发送数据到输入框

send_key(val)

代码实现:

 # 点击搜索按钮
 driver.find_element_by_id("com.android.settings:id/search").click()
 # 定位到输入框并输入abc
 driver.find_element_by_id("android:id/search_src_text").send_keys("abc")
 # 将 *abc*改成中文,输入框不会输入任何值,也不会报错

解决输入中文问题:
server 启动参数增加两个参数设置:
desired_caps[‘unicodeKeyboard’] = True
desired_caps[‘resetKeyboard’] = True

  • 清空输入框内容

    .clear()

  • 获取元素的文本内容

    .text

  • 获取元素的属性值

    get_attribute(属性)
    value = ‘name’------> 返回content-desc/text属性值
    value = ‘text’------->返回text的属性值
    value = ‘className’----->返回 calss 属性值,只有API=>才支持
    value = ‘resourceId’------>返回 resource-id属性值,只有API=>18才支持

  • 获取元素在屏幕上的坐标

    .location

    代码实现

    # 定位到搜索按钮
    get_value = driver.find_element_by_id("com.android.settings:id/search")
    # 打印搜索按钮在屏幕上的坐标
    print(get_value.location)
    
    执行结果:
          {'y': 44, 'x': 408}
    
  • 获取app包名和启动名

    获取包名:current_package
    获取启动名:current_activity
    代码实现:

    print(driver.current_package)
    print(driver.current_activity)
    执行结果:
     com.tencent.news
     .activity.SplashActivity
    
6. APP元素事件操作API
  • swip滑动事件

    swipe(start_x, start_y, end_x, end_y, duration=None)
    ps:从一个坐标滑动到另一个坐标
    参数:
    1. start_x:起点X轴坐标
    2. start_y:起点Y轴坐标
    3. end_x: 终点X轴坐标
    4. end_y,: 终点Y轴坐标
    5. duration: 滑动这个操作一共持续的时间长度,单位:ms

    # 1.swipe(开始坐标,结束坐标)
    # 注意,两个坐标的x轴要一样
    driver.swipe(198,872,198,321,5000)
    
  • scroll滑动事件

    scroll(origin_el, destination_el)
    ps:从一个元素滑动到另一个元素
    参数:
    1. origin_el:滑动开始的元素
    2. destination_el:滑动结束的元素

    代码实现

    end_ele = driver.find_element_by_xpath("//*[contains(@text,('WLAN'))]")
    start_ele = driver.find_element_by_xpath("//*[contains(@text,('电池'))]")
    driver.scroll(start_ele, end_ele)
    
  • drag拖拽事件

    drag_and_drop(origin_el, destination_el)
    ps:将一个元素拖动到另一个元素上,并替代原本的位置
    参数:
    1.origin_el:滑动开始的元素
    2.destination_el:滑动结束的元素

    end_ele = driver.find_element_by_xpath("//*[contains(@text,('WLAN'))]")
    start_ele = driver.find_element_by_xpath("//*[contains(@text,('电池'))]")
    driver.drag_and_drop(start_ele,end_ele)
    
  • 应用置于后台事件

    APP放置后台,模拟热启动
    background_app(seconds)
    参数:
    seconds:停留在后台的时间,单位:秒

7. APP模拟手势高级操作
  • tap():手指轻敲操作

    方法:tap(element=None, x=None, y=None).perform()
    参数:
    1. element:被定位到的元素
    2. x:相对于元素左上角的坐标,通常会使用元素的X轴坐标
    3. y:通常会使用元素的Y轴坐标
    4.perform():发送命令到服务器执行操作

    代码实现

     # 通过元素定位方式敲击屏幕
     el = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]")
     TouchAction(driver).tap(el).perform()
    
     # 通过坐标方式敲击屏幕,WLAN坐标:x=155,y=250
     TouchAction(driver).tap(x=155,y=250).perform()
    
  • press()手指按操作

    方法:press(el=None, x=None, y=None)
    方法:release() # 结束动作,手指离开屏幕
    参数:
    1.element:被定位到的元素
    2.x:通常会使用元素的X轴坐标
    3.y:通常会使用元素的Y轴坐标

    代码实现

     # 通过元素定位方式按下屏幕
     el = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]")
     TouchAction(driver).press(el).release().perform()
    
     # 通过坐标方式按下屏幕,WLAN坐标:x=155,y=250
     TouchAction(driver).tap(x=155,y=250).release().perform()
    
  • 等到操作

    wait(ms)

    代码实现:

    # 点击WLAN
    driver.find_element_by_xpath("//*[contains(@text,'WLAN')]").click()
    # 定位到WiredSSID
    el =driver.find_element_by_id("android:id/title")
    # 通过元素定位方式长按元素
    TouchAction(driver).press(el).wait(5000).perform()
    
  • 手指长按操作

    方法:long_press(el=None, x=None, y=None, duration=1000)
    参数:
    1. element:被定位到的元素
    2. x:通常会使用元素的X轴坐标
    3. y:通常会使用元素的Y轴坐标
    4. duration:持续时间,默认为1000m

    代码实现:
    进入设置,点击WLAN选项,长按WiredSSID选项5秒

     # 点击WLAN
      driver.find_element_by_xpath("//*[contains(@text,'WLAN')]").click()
      # 定位到WiredSSID
      el =driver.find_element_by_id("android:id/title")
      # 通过元素定位方式长按元素
      TouchAction(driver).long_press(el,duration=5000).release().perform()
    
      # 通过坐标方式长按元素,WLAN坐标:x=161,y=242
      # TouchAction(driver).long_press(x=161,y=242).perform() # ⚠️ 通过这个方法定位时报服务端错误,怀疑是appium1.7.1版本bug
    
  • 手指移动操作

    方法:move_to(el=None, x=None, y=None)
    **ps**:move_to在使用坐标进行多次移动时不再像以前一样:使用与前一个坐标的相对坐标,直接输入自己的就行了!!!!
    参数:
    1. el:定位的元素
    2. x:x坐标
    3. y:y坐标

    代码实现:
    进入设置,向上滑动屏幕

     # 定位到存储
     el = driver.find_element_by_xpath("//*[contains(@text,'存储')]")
      # 定位到更多
      el1 = driver.find_element_by_xpath("//*[contains(@text,'更多')]")
      # 元素方式滑动
      TouchAction(driver).press(el).move_to(el1).release().perform()
      # 坐标的方式滑动
      # TouchAction(driver).press(x=240,y=600).wait(100).move_to(x=100,y=100).release().perform()
    

    练习:
    进入设置,向上滑动屏幕到可见“安全”选项,进入到安全,点击屏幕锁定方式,点击图案,绘制图案
    代码实现:

    from appium import webdriver
    from appium.webdriver.common.touch_action import TouchAction
    from selenium.webdriver.support.wait import WebDriverWait
    import time
    
    desired_caps = {}
    desired_caps['platformName'] = 'Android'
    desired_caps['platformVersion'] = '5.1'
    desired_caps['deviceName'] = '192.168.236.102:5555'
    desired_caps['appPackage'] = 'com.android.settings'
    desired_caps['appActivity'] = '.Settings'
    desired_caps['unicodeKeyboard'] = True
    desired_caps['resetKeyboard'] = True
    driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
    time.sleep(1)
    
    
    def wait_element(xpa):
        return WebDriverWait(driver, 5, 0.5).until(lambda x: x.find_element_by_xpath(xpa))
    
    
    try:
    
        ele_dc = wait_element("//*[contains(@text,('电池'))]")
        time.sleep(1)
        ele_wl = wait_element("//*[contains(@text,('WLAN'))]")
        driver.scroll(ele_dc, ele_wl, 2000)
        time.sleep(1)
        wait_element("//*[contains(@text,('安全'))]").click()
        time.sleep(1)
        wait_element("//*[contains(@text,('屏幕锁定方式'))]").click()
        wait_element("//*[contains(@text,('图案'))]").click()
        time.sleep(2)
        # (127,360)(127,617)(384,617)
        TouchAction(driver).press(x=127,y=360).move_to(x=127,y=617).move_to(x=384,y=617).perform()
        time.sleep(2)
        driver.find_element_by_id("com.android.settings:id/footerLeftButton").click()
    except Exception as e:
        print(e)
    finally:
        driver.quit()
    
    
  • 获取手机时间

    .device_time

    print(driver.device_time)
    
  • 获取手机的宽高

    通过手机的宽高,可以做一些坐标的操作
    get_window_size()

    代码实现:

     print(driver.get_window_size())
     # 执行结果:
     {'height': 800, 'width': 480}
    
  • 发送键到设备

    方法:keyevent(keycode, metastate=None):
    参数:
    keycode:发送给设备的关键代码
    metastate:关于被发送的关键代码的元信息,一般为默认值

    代码实现:
    打开设置,按多次音量增加键

    for i in range(3):
          driver.keyevent(24)
    
  • 手机操作通知栏

    open_notifications()

    代码实现:
    启动设置,打开通知栏

    driver.open_notifications()
    
  • 获取手机当前的网络

    network_connection

    代码实现:

    print(driver.network_connection)
    执行结果:
          6
    

    网络对照表:
    在这里插入图片描述

  • 设置手机网络

    方法:set_network_connection(connectionType)
    参数:
    connectionType:需要被设置成为的网络类型

    代码实现:
    启动设置,设置手机网络为飞行模式

     driver.set_network_connection(1)
    
  • 手机截图

    截取手机当前屏幕,保存指定格式图片到设定位置

    方法:get_screenshot_as_file(filename)
    参数:
    filename:指定路径下,指定格式的图片.

    代码实现:
    打开设置,截图当前页面保存到当前目录

    	import os
        driver.get_screenshot_as_file(os.getcwd() + os.sep + './screen.png')
      执行结果:
          当前目录下会生成screen.png文件
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值