appium V1.10 centos7.4 安裝
安裝步驟
1. 安裝node
為了得到npm(node package manager,nodejs的安裝包管理工具,可以通過npm來下載appium)
一定要去官網下載最新的node,否則用yum install可能拿到較舊版本,導致后面安裝出問題:https://nodejs.org/en/download/
如我是linux系統,選擇最新的node-v10.15.0-linux-x64.tar.xz 下載,解壓:tar -xvf node-v10.15.0-linux-x64.tar.xz
由於node是免安裝版,又不是放在$PATH目錄,所以要做個軟鏈接,或者把當前路徑加到$PATH,我選擇第一種
[clouder@ana53 soft]$ cd node-v10.15.0-linux-x64/bin/
[clouder@ana53 bin]$ sudo ln -s `pwd`/node /usr/bin/
[clouder@ana53 bin]$ sudo ln -s `pwd`/npm /usr/bin/
2.安裝cnpm
由於npm的服務器在國外,由於長城防火牆原因,下載會超時,使用cnpm(npm.org的完整鏡像)
官方網址:http://npm.taobao.org
-g 表示全局安裝
npm install cnpm -g --registry=https://registry.npm.taobao.org
3.安裝appium
現在我們就可以用cnpm安裝,用法跟npm一樣
cnpm install -g appium
cnpm install -g appium-doctor
4.安裝appium-desktop
Appium Desktop是一款用於Mac、Windows和Linux的開源應用。它是Appium更為優化的圖形界面和appium相關的工具的組合:Appium-server的圖形界面。可以設置選項、啟動/停止服務器、查看日志等功能;且無須提前安裝Node / NPM,因為Node運行時直接與Appium Desktop綁定。可以使用Inspector來查看應用程序的元素,並進行基本的交互。
Appium Desktop與Appium不是同一個東西。Appium Desktop是對於Appium而言,是一個擁有更多相關工具的圖形化界面。它們各自有各自的Cadence和版本控制系統。
https://github.com/appium/appium-desktop/releases/tag/v1.10.0 下載appium-desktop-1.10.0-x86_64.AppImage,
chmod +x appium-desktop-1.10.0-x86_64.AppImage
sudo ln -s `pwd`/appium-desktop-1.10.0-x86_64.AppImage /usr/bin/appium-desktop
appium-desktop 即可運行
troubleshooting
1.運行報錯
selenium.common.exceptions.WebDriverException: Message: An unknown server-side error occurred while processing the command. Original error: Could not find aapt Please set the ANDROID_HOME environment variable with the Android SDK root directory path.
修改,並source一下 ~/.bashrc,
export ANDROID_HOME=/home/clouder/soft/android/android-sdk-linux
export ANDROID_SDK_HOME=/home/clouder/soft/android/android-sdk-linux
export BREW_HOME=/home/linuxbrew/.linuxbrew/bin
export PATH=$ANDROID_HOME:$ANDROID_SDK_HOME:$BREW_HOME:$ANDROID_SDK_HOME/tools:$ANDROID_SDK_HOME/platform-tools:$PATH:/home/clouder/soft/android/android-sdk-linux/build-tools/28.0.3/
發現輸入aapt命令是找得到命令的,修改代碼,把desire_caps['automationName'] = 'UiAutomator2' 一行注釋,根據https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md
的介紹,該參數默認值是appium,android是非必須的,可能因為androd8.0以上無法用uiautomatorview導致的。
desire_caps = {}
desire_caps['platformName'] = 'Android'
desire_caps['platformVersion'] = '8.1.0'
desire_caps['deviceName'] = '35eb25e5'
desire_caps['appPackage'] = 'onecloud.cn.xiaohui.qa'
desire_caps['appActivity'] = 'onecloud.cn.xiaohui.main.LoadingActivity'
#desire_caps['automationName'] = 'UiAutomator2'
desire_caps['noReset'] = 'True'
2.swipe滑動的介紹
https://www.cnblogs.com/dsy-sun/p/6595164.html
3.send_keys()輸入中文
在desired_caps加入一個參數"unicodeKeyboard = True ",如
[honor9]
platformName = Android
platformVersion = 8.0.0
deviceName = 37KRX18926031940
appPackage = onecloud.cn.xiaohui.qa
appActivity = onecloud.cn.xiaohui.main.LoadingActivity
noReset = True
unicodeKeyboard = True
4.獲取toast提示:
但是在我環境,可能因為toast出現太快,不到1秒就消失,來不及定位.所以總是報超時.在linux環境下,由於desired_caps加了automationName=Uiautomator2會報錯:
[debug] [MJSONWP] Encountered internal error running command: Error: Could not sign with default certificate. Original error Command '/usr/local/jdk1.8.0_151/bin/java -jar /tmp/.mount_appiumNtacdY/resources/app/node_modules/appium-adb/jars/sign.jar /tmp/.mount_appiumNtacdY/resources/app/node_modules/appium-uiautomator2-server/apks/appium-uiautomator2-server-debug-androidTest.apk --override' exited with code 1
[debug] [MJSONWP] at ADB.apkSigningMethods.signWithDefaultCert (/tmp/.mount_appiumNtacdY/resources/app/node_modules/appium-adb/lib/tools/apk-signing.js:124:13)
在我的windows環境,加此參數不會有此問題,但是也是拿不到toast內容.於是放棄.
網上別人的方法:
toast_loc=("xpath",".//*[contains(@text,'默認')]")
e1=WebDriverWait(self.driver,20,0.1).until(EC.presence_of_element_located(toast_loc))
def get_toast_text(self, text, timeout=5, poll_frequency=0.01):
"""
########################################
描述:獲取Toast的文本信息
參數:text需要檢查的提示信息 time檢查總時間 poll_frequency檢查時間間隔
返回值:返回與之匹配到的toast信息
異常描述:none
########################################
"""
toast_element = (By.XPATH, "//*[contains(@text, " + "'" + text + "'" + ")]")
toast = WebDriverWait(self.driver, timeout, poll_frequency).until(EC.presence_of_element_located(toast_element))
return toast.text
5.configparser.ConfigParser解析配置文件
cf = configparser.ConfigParser()
current_dir = os.path.dirname(os.path.realpath(__file__))
config_dir = os.path.join(current_dir,'../../conf/config.cnf')
cf.read(config_dir)
cf.items('honor9')
需要重寫ConfigParser.optionXform()方法,因為該方法會把option全部改為小寫,具體參考文章說明:https://blog.csdn.net/Ha_hha/article/details/78965011
# -*- coding:utf-8 -*-
from configparser import ConfigParser
class MyConfigParser(ConfigParser):
def __init__(self, defaults = None):
ConfigParser.__init__(self, defaults = defaults)
def optionxform(self, optionstr):
return optionstr
代碼改為使用自己的模塊創建一個對象.
cf = myconfigparser.MyConfigParser()
current_dir = os.path.dirname(os.path.realpath(__file__))
config_dir = os.path.join(current_dir,'../../conf/config.cnf')
cf.read(config_dir)
cf.items('honor9')
6.定位元素,找到多個元素.
如果是用xpath定位,有多個,則可以用()[n]來獲取第n個
driver.find_element(by=By.XPATH, value='(//android.widget.ImageView[@resource-id="onecloud.cn.xiaohui.qa:id/main_tabitem_pic"])[2]')
如果用id定位,有多個,則用find_elements()[n-1]來獲取第n個
driver.find_elements(by=By.ID, value='onecloud.cn.xiaohui.qa:id/main_tabitem_pic')[1]
7.visibility_of_element_located()
//判斷該元素是否被加載在DOM中,並不代表該元素一定可見
new WebDriverWait(driver,5).until(ExpectedConditions.presenceOfElementLocated(By.xpath("//*[@id='kw']")));
參數中有字符串和變量組成,用'+'連接字符串,注意xpath屬性值要用''括起:
a = driver.find_elements(by=By.XPATH, value='//*[@text='+'''+desktop_name+'''+']')
// *[ @ resource - id = onecloud.cn.xiaohui.qa:id / my_cloud_account_listitem_txt = 'test20190213171']
8.python3 使用HTMLTestRunner模塊.
由於HTMLTestRunner模塊不適合python3的語法,所以不能用pip命令安裝.需要到官網下載后放到自己常用的第三方模塊路徑下,再做些修改后才能正常用.
http://tungwaiyip.info/software/HTMLTestRunner.html
下載HTMLTestRunner.py,test_HTMLTestRunner.py 到自己的python的第三方模塊安裝目錄下,如何查看:在終端輸入python3 ,import appium,help(appium),按shift+g,翻到最后一行,看到:
FILE
/opt/python36/lib/python3.6/site-packages/appium/__init__.py
就下載的2個py放到/opt/python36/lib/python3.6/site-packages/目錄,執行
-rw-rw-r-- 1 clouder clouder 24360 Feb 15 12:05 HTMLTestRunner.py
-rw-rw-r-- 1 clouder clouder 6620 Feb 15 12:05 test_HTMLTestRunner.py
[clouder@ana53 site-packages]$ python3 test_HTMLTestRunner.py
File "test_HTMLTestRunner.py", line 58
print self.MESSAGE
^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(print self.MESSAGE)?
參考:https://www.cnblogs.com/qiaoxin/articles/7928290.html
修改匯總:
第94行,將import StringIO修改成import io
第539行,將self.outputBuffer = StringIO.StringIO()修改成self.outputBuffer = io.StringIO()
第642行,將if not rmap.has_key(cls):修改成if not cls in rmap:
第766行,將uo = o.decode('latin-1')修改成uo = e
第775行,將ue = e.decode('latin-1')修改成ue = e
第631行,將print >> sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime)修改成print(sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime))
在Python3.4下使用HTMLTestRunner,開始時,引入HTMLTestRunner模塊報錯。
做了修改,可以導入成功了.
9.logging打印日志出現重復
2019-02-15 16:54:21,826 - login - INFO - [line:39] - 個人用戶驗證碼登錄:
2019-02-15 16:54:40,104 - login - INFO - [line:49] - 個人用戶驗證碼登錄成功
2019-02-15 16:54:49,175 - login - INFO - [line:105] - 退出登錄:
2019-02-15 16:54:49,175 - login - INFO - [line:105] - 退出登錄:
2019-02-15 16:54:52,672 - login - INFO - [line:111] - 退出登錄成功
2019-02-15 16:54:52,672 - login - INFO - [line:111] - 退出登錄成功
2019-02-15 16:55:00,502 - login - INFO - [line:54] - 企業用戶驗證碼登錄:
2019-02-15 16:55:00,502 - login - INFO - [line:54] - 企業用戶驗證碼登錄:
2019-02-15 16:55:00,502 - login - INFO - [line:54] - 企業用戶驗證碼登錄:
2019-02-15 16:55:30,105 - login - INFO - [line:68] - 企業用戶驗證碼登錄成功
2019-02-15 16:55:30,105 - login - INFO - [line:68] - 企業用戶驗證碼登錄成功
2019-02-15 16:55:30,105 - login - INFO - [line:68] - 企業用戶驗證碼登錄成功
2019-02-15 16:55:39,277 - login - INFO - [line:105] - 退出登錄:
2019-02-15 16:55:39,277 - login - INFO - [line:105] - 退出登錄:
2019-02-15 16:55:39,277 - login - INFO - [line:105] - 退出登錄:
2019-02-15 16:55:39,277 - login - INFO - [line:105] - 退出登錄:
https://blog.csdn.net/huilan_same/article/details/51858817
# 這里進行判斷,如果logger.handlers列表為空,則添加,否則,直接去寫日志
if not logger.handlers:
streamhandler = logging.StreamHandler() streamhandler.setLevel(logging.ERROR)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s')
streamhandler.setFormatter(formatter)
logger.addHandler(streamhandler)
10.運行unittest執行結果總是有報錯:<_io.TextIOWrapper name='
' mode='w' encoding='UTF-8'>
/opt/python36/bin/python3 /home/clouder/workspace/pycharm/xiaohui/runall.py
a
<_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>
Time Elapsed: 0:00:31.583516
..s
----------------------------------------------------------------------
Ran 2 tests in 31.599s
OK (skipped=1)
Process finished with exit code 0
修改HTMLTestRunner.py 第631行
print(sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime))
改成
sys.stderr.write('\nTime Elapsed: %s\n' % (self.stopTime -self.startTime))
解決了~
/opt/python36/bin/python3 /home/clouder/workspace/pycharm/xiaohui/main.py
a
.
Time Elapsed: 0:00:30.968873
.s
----------------------------------------------------------------------
Ran 2 tests in 30.983s
OK (skipped=1)
11.切割字符串及列表轉字符串
case_auto_name = a[2].split('_')[0] + "_" + a[3] + "_" + "_".join(a[2].split('_')[1:])
12.suite.addTest()時報錯
我是用另外一個腳本生成要執行的testcase列表,傳遞給suite.addTest(),直接傳遞一個值可以,但是list[0]就不行,
Error
Traceback (most recent call last):
File "/opt/python36/lib/python3.6/unittest/case.py", line 59, in testPartExecutor
yield
File "/opt/python36/lib/python3.6/unittest/case.py", line 605, in run
testMethod()
File "/home/clouder/workspace/pycharm/xiaohui/runall.py", line 40, in test_run_by_csv_defined
suite.addTest(cases_list[0])
File "/opt/python36/lib/python3.6/unittest/suite.py", line 47, in addTest
raise TypeError("{} is not callable".format(repr(test)))
TypeError: 'test_login.TestLogin("test_login_indivial_by_code")' is not callable
13.pycharm 常用快捷鍵
1.批量添加/取消備注:選中多行,按ctrl+/
2.批量縮進:選擇多行,按tab向右縮進,按shift+tab向左縮進
3.調試:
進入調試:shift+F9
step over:F8
step into:F7
step into my code:ctrl+alt+F7
4.運行當前窗口程序:ctrl+shift+F10
5
13.driver.window_handles
記得要sleep一下,否則剛打開的標簽頁,可能沒拿到新的handle,如下例,不sleep,只拿到2個handle,sleep可以拿到3個。
sleep(3)
print("進入項目詳情,總的handle:",driver.window_handles)
進入項目詳情,總的handle: ['2147483649', '2147483660', '2147483667']
#sleep(3)
print("進入項目詳情,總的handle:",driver.window_handles)
進入項目詳情,總的handle: ['2147483649', '2147483660']
- 打開瀏覽器標簽
driver_m.find_element_by_tag_name('html').send_keys(Keys.CONTROL+'t')
20191226更新
發現appium-desktop 1.10用不了,無法連接到appium server,使用appium-desktop的inspect工具,提示 ENETUNREACH。
更新需要上github下載,一天都下不來,所以使用無界面的appium
參考 https://www.cnblogs.com/windhome/p/8024835.html
1、nodeJs安裝
apt-get install node.js
2、npm安裝
apt-get install npm
3、cnpm安裝
npm install -g cnpm --registry=https://registry.npm.taobao.org // -g全局安裝
4、appium安裝
在非root用戶權限下安裝
cnpm install -g appium //appium server安裝
cnpm install wd //appium client安裝
