昨天在家安装好了环境,今天来星巴克发现使用cmd和git bash执行adb,报错:不是内部命令
解决:(1)、cmd使用管理员权限运行,可以执行adb命令了
(2)、将sdk所在的目录权限降级然后重启电脑,git bash 执行adb命令可以使用不再报错
1、app弹框处理
"autoGrantPermissions": "true"
2、appium隐式等待(无条件等待)
driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
driver.implicitly_wait(6)
截图方法(get_screenshot_as_file):
TestXueqiuAndroid.driver.get_screenshot_as_file(str(i)+'.png')
3、appiumdesktop=appium server+client,我们正真使用的是appium server(没有录制功能,安装起来后面使用appium server).官网的方法不太好装appium server
使用淘宝的cnpm安装appium是最稳定快速的方法
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install -g appium
cnpm install appium@11.1 #将老版本装在本地命令
#全局安装并执行
cnpm install -g appium
appium #查看appium是否安装成功及安装的目录,也可以用些命令直接打开appium server
#只安装到当前目录并执行
cnpm install appium@1.11
./node_modules/appium/build/lib/main.js #安装的1.11版本的目录
4、 输入法拦截
unicodeKeyboard=true
5、测试用例结构(测试步骤三要素:定位、交互、断言,)
1)caps={
app apk地址
appPackage包名
appActivity Activity名字
automationName 默认使用uiautomator
noReset fullReset 是否清理之前的数据,true不清理,false清理
unicodeKeyBoard resetKeyBoard是否重新输入
}
2)appium server配置
driver = webdriver.Remote("http://localhost:4723/wd/hub", caps) #localhost可以使用其他Ip地址
driver.implicitly_wait(10)
3)定位方式(比较两个文件的命令:vimdiff /temp/1.txt /temp/2.txt)
(1)cont-desc ---》 find_element_by_accessibility_id()
(2)class name---》find_element_by_class_name()
(3)resource-id---》 find_element_by_id()
(4)xpath----》driver.find_element_by_xpath()
雪球首页-》基金
id:跟据id反定位界面元素
xpath:
/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.view.ViewGroup/android.widget.LinearLayout/android.widget.LinearLayout/android.widget.LinearLayout/android.widget.RelativeLayout[4]/android.widget.TextView
//*[@text='基金' and @instance='4'] #改造后的xpath
//*[@resource-id='com.xueqiu.android:id/public_timeline_header_container']//*[@text='基金'] #借助父节点,/前面的内容可以省略掉
//*[contains(@resource-id,'buttons_container')]//*[@text='基金'] #借助父节点,使用contains
作业:
1)//*[@text='基金' and @instance='9'] #instance不太稳定,instance的值基本不会变
2)//*[@resource-id='com.xueqiu.android:id/indicator']//*[@text='基金']
3)//*[contains(@resource-id,'indicator')]//*[@text='基金']
需要先安装Pytest,
from appium import webdriver
from appium.webdriver.webdriver import WebDriver
class Testxueqiuan(object):
driver=WebDriver #不写这句,识别不出find方法,也可以写成driver:WebDriver
#driver=String #这个就变成String的方法
@classmethod
def setup_class(cls): #整体初始化
print('setup class')
cls.driver=cls.initapp()
def setup_method(self): #每一个方法
print('setup method')
Testxueqiuan.driver=self.restartapp()
self.driver=Testxueqiuan.driver
def test_login(self):
el1 = Testxueqiuan.driver.find_element_by_id("com.xueqiu.android:id/user_profile_icon")
el1.click()
el2 = self.driver.find_element_by_id("com.xueqiu.android:id/tv_login")
el2.click()
el3 = Testxueqiuan.driver.find_element_by_id("com.xueqiu.android:id/tv_login_by_phone_or_others")
el3.click()
def test_基金(self):
el1=Testxueqiuan.driver.find_element_by_xpath("//*[contains(@resource-id,'indicator')]//*[@text='基金']").click()
@classmethod
def initapp(cls)->WebDriver:
caps = {}
caps["platformName"] = "android"
caps["deviceName"] = "demo"
caps["app"] = "com.xueqiu.android"
caps["appActivity"] = "view.WelcomeActivityAlias"
caps["autoGrantPermissions"] = "true"
driver = webdriver.Remote("http://localhost:5723/wd/hub", caps)
driver.implicitly_wait(10) # 隐式等待
return driver
@classmethod
def restartapp(cls) -> WebDriver:
caps = {}
caps["platformName"] = "android"
caps["deviceName"] = "demo"
caps["app"] = "com.xueqiu.android"
caps["appActivity"] = "view.WelcomeActivityAlias"
caps["autoGrantPermissions"] = "true"
caps['noreset'] = 'true' # 这个选项默认为false
driver = webdriver.Remote("http://localhost:5723/wd/hub", caps)
driver.implicitly_wait(10) # 隐式等待
return driver
def teardown_method(self):
Testxueqiuan.driver.quit()
6)滑动手机模拟器屏幕:(3种不一样的写法)
from appium import webdriver
from appium.webdriver.common.touch_action import TouchAction
from appium.webdriver.webdriver import WebDriver
import time
class Testxueqiuan(object):
driver:WebDriver #说明driver的类型是WebDriver
@classmethod
def setup_class(cls): #整体初始化
print('setup class在当前class中只执行一次')
cls.driver=cls.install_app() #安装一个app
def setup_method(self): #每一个方法
print('setup method在每个方法执行前中执行一次')
TestXueqiuAndroid.driver=self.restart_app()
self.driver=TestXueqiuAndroid.driver #后面的driver都来自这里
#下面三个方法是上下滑动手机或模拟器屏幕的
def test_swipe(self):
TestXueqiuAndroid.driver.find_element_by_xpath("//*[contains(@resource-id,'indicator')]//*[@text='基金']")
for i in range(5):
TestXueqiuAndroid.driver.swipe(1000,1000,200,200) #如果屏幕没有1000那么大就有可能执行失败
time.sleep(2)
def test_action(self):
TestXueqiuAndroid.driver.find_element_by_xpath("//*[contains(@resource-id,'indicator')]//*[@text='基金']")
action=TouchAction(TestXueqiuAndroid.driver) #如果屏幕没有1000那么大就有可能执行失败
for i in range(5):
action.press(x=1000,y=1000).move_to(x=200,y=200).release().perform()
time.sleep(2)
def test_action_p(self): #按百分比来滑动
resc=TestXueqiuAndroid.driver.get_window_rect() #获取手机屏幕的width和height
TestXueqiuAndroid.driver.find_element_by_xpath("//*[contains(@resource-id,'indicator')]//*[@text='基金']")
action=TouchAction(self.driver)
for i in range(5):
action.press(x=resc['width']*0.8,y=resc['height']*0.8).move_to(x=resc['width']*0.2,y=resc['height']*0.2).release().perform()
time.sleep(5)
TestXueqiuAndroid.driver.get_screenshot_as_file(str(i)+'.png') #每滑动一次屏幕就截图一张
def test_login(self):
el1 = TestXueqiuAndroid.driver.find_element_by_id("com.xueqiu.android:id/user_profile_icon")
el1.click()
el2 = TestXueqiuAndroid.driver.find_element_by_id("com.xueqiu.android:id/tv_login")
el2.click()
el3 = TestXueqiuAndroid.driver.find_element_by_id("com.xueqiu.android:id/tv_login_by_phone_or_others")
el3.click()
def test_jijin(self):
el1=TestXueqiuAndroid.driver.find_element_by_xpath("//*[contains(@resource-id,'indicator')]//*[@text='基金']").click()
@classmethod #初始化app与restartapp有不同
def install_app(cls)->WebDriver:
caps = {}
#caps['app']='' #如果有必要需要安装和权限
caps["platformName"] = "android"
caps["deviceName"] = "demo"
caps["app"] = "com.xueqiu.android"
caps["appActivity"] = "view.WelcomeActivityAlias"
#解决第一次启动时赋值权限
caps["autoGrantPermissions"] = "true"
driver = webdriver.Remote("http://localhost:5723/wd/hub", caps)
driver.implicitly_wait(10) # 隐式等待
return driver
@classmethod #为了更快的启动
def restart_app(cls) -> WebDriver:
caps = {}
caps["platformName"] = "android"
caps["deviceName"] = "demo"
caps["app"] = "com.xueqiu.android"
caps["appActivity"] = "view.WelcomeActivityAlias"
caps["autoGrantPermissions"] = "true"
caps['noreset'] = 'true' # 这个选项为true,保留之前的操作数据
driver = webdriver.Remote("http://localhost:5723/wd/hub", caps)
driver.implicitly_wait(10) # 隐式等待
return driver
def teardown_method(self):
TestXueqiuAndroid.driver.quit()
appium的操作可以查看appium官网文档,像command:http://appium.io/docs/en/commands/element/actions/click/
简化以后的代码:
from appium import webdriver
from appium.webdriver.common.touch_action import TouchAction
from appium.webdriver.webdriver import WebDriver
import time
class TestXueqiuAndroid(object):
@classmethod
def setup_class(cls):
print("class setup")
def setup_method(self):
print("method setup")
self.driver=self.restart_app() #下面的driver来自动这里
def test_login(self):
el1=self.driver.find_element_by_id("com.xueqiu.android:id/home_search")
el1.click()
el3=self.driver.find_element_by_id("com.xueqiu.android:id/search_input_text")
el3.send_keys("alibaba")
def test_jijin(self):
el1=self.driver.find_element_by_xpath("//*[contains(@resource-id,'buttons_container')]//*[@text='基金']")
el1.click()
#三种滑动屏幕的方法
def test_swipe(self):
self.driver.find_element_by_xpath("//*[contains(@resource-id,'buttons_container')]//*[@text='基金']")
for i in range(5):
self.driver.swipe(800,800,200,200)
time.sleep(2)
def test_action(self):
self.driver.find_element_by_xpath("//*[contains(@resource-id,'buttons_container')]//*[@text='基金']")
action=TouchAction(self.driver)
for i in range(5):
action.press(x=800,y=800).move_to(x=200,y=200).release().perform()
time.sleep(2)
def test_action_p(self):
rect=self.driver.get_window_rect()
self.driver.find_element_by_xpath("//*[contains(@resource-id,'buttons_container')]//*[@text='基金']")
action=TouchAction(self.driver)
for i in range(5):
action.press(x=rect['width']*0.8,y=rect['height']*0.8).move_to(x=rect['width']*0.2,y=rect['height']*0.2).release().perform()
time.sleep(2)
@classmethod
def install_app(cls)-> WebDriver:
caps = {}
#caps['app']='app存放的位置' #安装app
caps["platformName"] = "android"
caps["deviceName"] = "hogwarts"
caps["appPackage"] = "com.xueqiu.android"
caps["appActivity"] = ".view.WelcomeActivityAlias"
caps["autoGrantPermissions"] = "true" # 自动授权
#caps["noReset"] = True
driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
driver.implicitly_wait(20) # 隐式等待
return driver
@classmethod
def restart_app(cls) -> WebDriver:
caps = {}
caps["platformName"] = "android"
caps["deviceName"] = "hogwarts"
caps["appPackage"] = "com.xueqiu.android"
caps["appActivity"] = ".view.WelcomeActivityAlias"
#caps["autoGrantPermissions"] = "true" # 启动的时候将,noReset设置成True就不需要这一句代码自动授权
caps["noReset"] = True
driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
driver.implicitly_wait(20) # 隐式等待
return driver
#不加这段teardown的代码也没关系,如果不quit(),启动appium会自动quit之前的session
"""
def teardown_method(self):
self.driver.quit()
"""
整个代码的迭代思想:
(1)先用appium自带的inspector录制了一段代码
(2)pycharm上面新建一个test头或者结尾的py文件,加上一个Test开关的类,一个test开头或者结尾的方法,然后拷贝(1)中录制的代码到方法中去,此次形成了初步的代码
(3)优化代码:添加setup_class\setup_method\teardown_method这些方法,把重复公用的方法,如启动app定义成类方法封装到restart_app()方法中,然后在setup_method中调用
(4)添加三种滑动屏幕的方法
(5)只需要一次的操作封装到setup_class中,每个方法都需要操作的封装到setup_method
7)不用每次退出
思路:不停的分解,将相同的操作都写在setup_class或者setup_method中,不同的操作再定义到具体的方法中去
from appium import webdriver
from appium.webdriver.webdriver import WebDriver
import time
class Testxueqiuan(object):
driver = WebDriver # 不写这句,识别不出find方法
@classmethod
def setup_class(cls): # 整体初始化
print('setup class在当前class中只执行一次')
cls.driver = cls.installap() #加上cls变成类变量
el1 = cls.driver.find_element_by_id("com.xueqiu.android:id/user_profile_icon")
el1.click() #到点击登陆的页面
def setup_method(self): # 每一个方法
print('setup method在每个方法执行前中执行一次')
self.driver=Testxueqiuan.driver #局部变量
el2 = self.driver.find_element_by_id("com.xueqiu.android:id/tv_login")
el2.click() #选择登陆的页面
def test_login_phone(self):
el3 = self.driver.find_element_by_id("com.xueqiu.android:id/tv_login_by_phone_or_others")
el3.click() #手机登陆的页面
def test_login_passwd(self):
el3 = self.driver.find_element_by_id("com.xueqiu.android:id/tv_login_by_phone_or_others")
el3.click()
self.driver.find_element_by_xpath("//*[@text='邮箱手机号密码登陆']").click() #手机登陆页面的密码登陆
def test_login_error_username(self):
el4=self.driver.find_element_by_id() #手机登陆页手机号错面误密码
def test_login_eror_passwd(self):
el4=self.driver.find_element_by_xpath()#手机登陆页面密码错误
@classmethod
def installap(cls) -> WebDriver:
caps = {}
# caps['app']='' #安装apk
caps["platformName"] = "android"
caps["deviceName"] = "demo"
caps["app"] = "com.xueqiu.android"
caps["appActivity"] = "view.WelcomeActivityAlias"
# 解决第一次启动时赋值权限
caps["autoGrantPermissions"] = "true"
driver = webdriver.Remote("http://localhost:5723/wd/hub", caps)
driver.implicitly_wait(10) # 隐式等待
return driver
@classmethod
def restartapp(cls) -> WebDriver:
caps = {}
caps["platformName"] = "android"
caps["deviceName"] = "demo"
caps["app"] = "com.xueqiu.android"
caps["appActivity"] = "view.WelcomeActivityAlias"
caps["autoGrantPermissions"] = "true"
caps['noreset'] = 'true' # 这个选项为true,保留之前的操作数据
driver = webdriver.Remote("http://localhost:5723/wd/hub", caps)
driver.implicitly_wait(10) # 隐式等待
return driver
def teardown_method(self):
self.driver.back()
注:实际中的app都存在动态加载,需要使用显示等待作判断
8)截图:
self.driver.get_screenshot_as_file(str(i)+".png")