1.测试设备
adb shell start -n 要启动的页面:这样可以把你要启动的页面启动起来
start session是创建一个新的session
使用应用宝官网下载到电脑
安装应用:adb install -r xxx.apk
或者通过拖拽到模拟器中
多个模拟器或手机安装应用,使用以下命令:
adb uninstall …卸载
2.app文件
- 下载安装
三种方式:
- 去应用商店或者app store下载安装
- 去网上下载(比如应用宝等平台),然后拖拽到手机上
- 将下载下来的应用,使用命令安装:
adb install **.apk
- 卸载
卸载方式:
- 直接在模拟器上卸载,长按应用,拖拽删除
- 使用命令卸载:
adb uninstall apk的包名
例如企业微信:
adb uninstall com.tencent.wework
3. Appium Desktop
点击 Start Server 启动服务
配置DesireCapability
{
"platformName": "android”,
"deviceName": "emulator-5554”,
"appPackage": "com.tencent.wework”,
"appActivity": ".launch.LaunchSplashActivity”,
"autoGrantPermissions": "true", #这个参数为true的时候 noReset参数不生效
"noReset": "true" #noReset 防止清除app的数据
}
adb 常用命令
adb devices
adb logcat | grep -i Displayed
adb shell am start -n 启动 activity
com.tencent.wework/.launch.LaunchSplashActivity
com.tencent.wework/.launch.WwMainActivity
注意:启动页与直接启动主页是不同的。 理论上任何一个页面都可以直接进去,但开发做了限制,不允许这么操作。只能从启动页开始,模拟真实用户使用场景。
3.分析常用端口的意义
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
0.0.0.0等同于localhost,是与脚本中的端口号是一致的,4723是seerver端与客户端建立连接的端口
UIAutomator2
Server APK
手机端(UI)会默认开启一个端口号,接收server端发送的请求,可以通过查看日志可以看到端口号是8200,只不过平时没有注意,也不用去配置它
5037
adb概念 是android跟pc端建立连接的一条指令 android debug bridge,通过它电脑就可以操纵手机的
底层,adb client就是我们输入的adb命令
adb server与客户端进行通讯的端口5037
server通过usb跟手机连接,手机里有adbd这样一个服务,它可以跟adb server建立一个连接,adb connect 端口号,这个端口号是可以修改的
800*的都是chromedriver即webview进行通讯的端口号
所以一定要注意端口号是干嘛的
4.元素定位
小技巧:appium desktop还可以保存之前的设置
定位元素的时候,如果名字一致怎么解决,通过兄弟节点查找到通讯录,By.XPATH和MobileBy都可以使用,当查找ID、或者xpath时
对于列表页内容很多需要滑动查询的时候,比如企业微信添加联系人,当联系人很多的时候,添加成员按钮在页面底部
可以通过滚动查找
'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("添加成员").instance(0))'
定位元素的原则, 如果有ID就一定使用ID
强制的等待不建议多加,但是平时调试啥的还是可以加个1s2s的
例如查找姓名的输入框元素, 通过姓名去查找对应的元素是比较合理的,而不是通过输入框中的text=必填,姓名和必填是兄弟节点的关系
使用@text查找xpath中的姓名找不到,可以用contains⚠️❗️👍
因为这个姓名 开发后面多写了一个空格,就是姓名(空格),所以可以使用contains容易查找到
最后定位元素的的表达式如下:另外注意元素里面是单引号,外面要使用双引号,不然会报错!!
"//*[contains(@text,'姓名')]/..//*[@resource-id='com.tencent.wework:id/ase']"
两个点是代表他的父节点,就是查找父节点的子节点为id=。。。的元素
性别也是同样的方式去查找
appium中有一个官方文档可以去查看如何具体的使用, new UiSelector.text或者.resource-id .contains(text)等,可以查看文档中的使用方法
添加成功toast,一闪而过,是系统给的提示消息,打印pagesource,可以发现在xml文件最后,也就是最后在dom树中插入了
一个wiget toast,所以可以通过他的class属性去获取它或者使用xpath定位方式
toast = self.driver.find_element(MobileBy.XPATH, "//*[@class='android.widget.Toast']").text
assert '添加成功' in toast
如果屏幕中有多个相同的text,是默认定位第一个吗?是的
5.获取到当前页面activity
第一种方式:使用appium desktop
还有一种方式获取到当前页面activity
断言这个activity就是当前运行的activity
6.排错
通过行数查找出错位置,添加打印信息,期望值和实际值不一样才会出错,为什么不一样,哪儿不一样,通过打印一目了然,如果提供的信息仍旧查找不出错误来,我们可以结合服务端来查看报错信息
点击报错的行数,就可以直接定位到哪一行报错
7.参数化用例
由于参数化每执行一个参数会重新启动一次,因此为了使他不重新启动再改造一下,这里改成类方法, 然后在teardown中添加点击返回按钮,返回至通讯录页面
代码如下:
from time import sleep
from appium import webdriver
import yaml
import pytest
from appium.webdriver.common.mobileby import MobileBy
class Test_addmem():
def setup_class(self):
desired_caps = {}
desired_caps['platformName'] = 'android'
desired_caps['platformVersion'] = '6.0'
desired_caps['deviceName'] = 'emulator-5554'
desired_caps['appPackage'] = 'com.tencent.wework'
desired_caps['appActivity'] = '.launch.LaunchSplashActivity'
desired_caps['noReset'] = 'true'
desired_caps['dontStopAppOnReset'] = 'true'
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
self.driver.implicitly_wait(5)
def setup(self):
pass
def teardown(self):
self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/gpp').click()
def teardown_class(self):
self.driver.quit()
#注意这里参数必须要加双引号,加单引号会报错
@pytest.mark.parametrize("mobile,name,sex", [('17801153312', '测试账号12', '男'), ('17801153311', '测试账号11', '女')])
def test_search(self, mobile, name, sex):
# 查找通讯录
el1 = self.driver.find_element_by_xpath("//*[@text='通讯录']")
el1.click()
# 添加成员
el2 = self.driver.find_element_by_android_uiautomator(
'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("添加成员").instance(0))')
el2.click()
# self.driver.find_element_by_id('com.tencent.wework:id/c56')
self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/c56').click()
sleep(2)
# 输入姓名
self.driver.find_element(MobileBy.XPATH,
"//*[contains(@text,'姓名')]/..//*[@resource-id='com.tencent.wework:id/ase']").send_keys(
name)
# 输入手机号
self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/emh').send_keys(mobile)
# 选择性别
self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/ate').click()
#注意引号外面要加f
self.driver.find_element(MobileBy.XPATH, f"//*[@text='{sex}']").click()
# 点击保存
self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/gq7').click()
# print(self.driver.page_source)
# self.driver.find_element(MobileBy.XPATH, "//*['@text=添加成功']")
sleep(2) #
toast = self.driver.find_element(MobileBy.XPATH, "//*[@class='android.widget.Toast']").text
assert '添加成功' in toast
也可以直接使用fixture,这样不至于显得很累赘,修改代码如下: