Android APP 自動(dòng)化測(cè)試

自動(dòng)化測(cè)試環(huán)境安裝

Android APP 自動(dòng)化測(cè)試框架

Unittest框架

使用unittest編寫(xiě)用例肤寝,必須遵守以下規(guī)則:

1、測(cè)試文件必須先import unittest;

2阀圾、測(cè)試類必須繼承unittest.TestCase;

3狗唉、測(cè)試方法必須以“test_”開(kāi)頭初烘;

4、測(cè)試類必須要有unittest.main()方法分俯。

Test Fixture

A test fixture represents the preparation needed to perform one or more tests, and any assoicate cleanup actions.

  • setUp() : 進(jìn)行測(cè)試前的初始化工作肾筐。
  • testCase() : 進(jìn)行測(cè)試工作,可以有很多個(gè)
  • tearDown() : 執(zhí)行測(cè)試后的清除工作缸剪。
Test Case & Test Suite &Test Runner

官網(wǎng)的含義介紹:

A test case is the smallest unit of testing. It checks for a specific response to a particular set of inputs. 測(cè)試用例是最小的測(cè)試單元吗铐。它檢查對(duì)特定輸入集的特定響應(yīng)。

A test suite is a collection of test cases, test suites, or both. It is used to aggregate tests taht should be executed together. 測(cè)試套件是測(cè)試用例杏节、測(cè)試套件或兩者的集合唬渗。它用于聚合應(yīng)該一起執(zhí)行的測(cè)試典阵。

A test runner is a component thich orchestrates the execution of tests and provides the outcome to the user. 測(cè)試運(yùn)行器是一個(gè)組件,它協(xié)調(diào)測(cè)試的執(zhí)行并向用戶提供結(jié)果镊逝。

應(yīng)用Test Suite 和Test Runner 運(yùn)行自動(dòng)化腳本
import unittestdemo
import unittest


# 以一個(gè)類的維度去執(zhí)行
cases = unittest.TestLoader.loadTestsFromTestCase(unittestdemo.MyTestCase)
# 可以一次添加多個(gè)cases
my_suite = unittest.TestSuite([cases])

# 添加單個(gè)測(cè)試用例壮啊,在使用ddt后,將會(huì)不可用
# my_suite = unittest.TestSuite()
# my_suite.addTest(unittestdemo.MyTestCase("test_something"))

my_runner = unittest.TextTestRunner(verbosity=2)
my_runner.run(my_suite)
數(shù)據(jù)驅(qū)動(dòng)DDT

官網(wǎng)

DDT(Data-Driven Tests) allows you to multiply one test case by runing it with different test data, and make it appear as multiple test cases.

DDT(數(shù)據(jù)驅(qū)動(dòng)測(cè)試)允許您將一個(gè)測(cè)試用例與不同的測(cè)試數(shù)據(jù)一起運(yùn)行撑蒜,從而使它顯示為多個(gè)測(cè)試用例他巨。

數(shù)據(jù)驅(qū)動(dòng)DDT的使用
  • 準(zhǔn)備第三方庫(kù)

    首先安裝ddt庫(kù), 其次在腳本中引入ddt

    pip install ddt

  • 使用

    import unittest
    from ddt import ddt, data, unpack
    
    # 聲明該測(cè)試類采用ddt
    @ddt
    class MyTestCase(unittest.TestCase):
    
        # 使用元祖存放被測(cè)試的數(shù)據(jù)减江,一次只有一個(gè)參數(shù)的情況染突,每一組數(shù)據(jù)都會(huì)執(zhí)行一次測(cè)試用例
        @data(1, 2, 3)
        def test_something(self, value):
            print value
            self.assertEqual(value, 2)
    
        # 使用元祖存放被測(cè)試的數(shù)據(jù),一次有多個(gè)參數(shù)的情況辈灼,每一組數(shù)據(jù)都會(huì)執(zhí)行一次測(cè)試用例
        @data((1, 2), (2, 3))
        @unpack
        def test_something(self, value1, value2):
            print value1, value2
            self.assertEqual(value2, value1 + 1)    
    
    if __name__ == '__main__':
        unittest.main()
        
    

    APP API自動(dòng)化測(cè)試

    API

    API (Application Programming Interface份企, 簡(jiǎn)稱API),又稱為應(yīng)用編程接口巡莹,就是軟件系統(tǒng)不同組成部分銜接的約定司志。

    API種類:

    • 面向?qū)ο笳Z(yǔ)言的API
    • 庫(kù)與框架的API
    • API與協(xié)議
    • API與設(shè)備接口
    • Web API - 就是APP API測(cè)試中要測(cè)試的HTTP API
    HTTP API

    HTTP中的8種不同方法:

    • GET:表示客戶端需要請(qǐng)求服務(wù)器的某個(gè)資源,對(duì)應(yīng)DB中的Select操作降宅,為http請(qǐng)求常用方法
    • POST: 一般用于向系統(tǒng)中更新數(shù)據(jù)骂远,對(duì)應(yīng)DB中的Update操作,為http請(qǐng)求常用方法腰根;參數(shù)在Requet-Body中傳遞 激才;相比較Get,較為安全
    • PUT:一般用于向系統(tǒng)中插入數(shù)據(jù)(當(dāng)然额嘿,其功能Post也能實(shí)現(xiàn)瘸恼,與Post有很多相似之處),對(duì)應(yīng)DB中的Insert操作;傳輸內(nèi)容放在Request-Body中册养;不安全东帅,不帶驗(yàn)證機(jī)制,故一般不使用該方法
    • DELETE:一般用于向系統(tǒng)中刪除數(shù)據(jù)球拦,對(duì)應(yīng)DB中的Delete操作靠闭;不帶驗(yàn)證機(jī)制,故不安全
    • OPTIONS: 一般用來(lái)詢問(wèn)URI支持的方法坎炼;查詢服務(wù)器的性能
    • HEAD:用法與Get一樣愧膀,只不過(guò)Head只返回Http-Responce頭部信息;由于Head只返回頭部信息(相對(duì)于Get点弯,輕量級(jí))扇调,故一般被用于確認(rèn)URI的有效性矿咕,資源更新的日期時(shí)間等
    • TRACE:追蹤路徑抢肛,如追蹤一個(gè)資源請(qǐng)求中間所經(jīng)過(guò)的代理狼钮;回顯服務(wù)器收到的請(qǐng)求,主要用于測(cè)試或診斷
    • CONNECT:隧道協(xié)議連接代理

抓包神奇Fiddler

環(huán)境準(zhǔn)備
  • Fiddler安裝 - 官網(wǎng)下載地址

  • 基本設(shè)置

    打開(kāi)Fiddler Tool->Fiddler Options->HTTPS 捡絮。 (配置完后記得要重啟Fiddler)

    設(shè)置https

    截獲HTTPS請(qǐng)求熬芜,第一次會(huì)彈出證書(shū)安裝提示,若沒(méi)有彈出提示福稳,勾選Actions-> Trust Root Certificate涎拉,另外发笔,如果你要監(jiān)聽(tīng)的程序訪問(wèn)的 HTTPS 站點(diǎn)使用的是不可信的證書(shū)娜睛,則請(qǐng)接著把下面的 “Ignore servercertificate errors” 勾選上。

    trust_root_certificate

注意:Fiddler 是以代理web服務(wù)器的形式工作的娜扇,它使用代理地址:127.0.0.1越妈,端口:8888季俩。當(dāng)Fiddler退出的時(shí)候它會(huì)自動(dòng)注銷,這樣就不會(huì)影響別的 程序梅掠。不過(guò)如果Fiddler非正常退出酌住,這時(shí)候因?yàn)镕iddler沒(méi)有自動(dòng)注銷,會(huì)造成網(wǎng)頁(yè)無(wú)法訪問(wèn)阎抒。解決的辦法是重新啟動(dòng)下Fiddler酪我。

基本界面
用戶界面
設(shè)置斷點(diǎn)修改Request/Response
  • Rules - Automatic BreakPoints - Before Requests/After Requests(但是這樣會(huì)攔截所有請(qǐng)求)

  • 通過(guò)工具欄設(shè)置斷點(diǎn)

    工具欄斷點(diǎn)

如圖,箭頭所指的位置時(shí)可以點(diǎn)擊的且叁。共三種狀態(tài):
空白:不設(shè)置斷點(diǎn)都哭。
箭頭向上:表示斷點(diǎn)請(qǐng)求。此時(shí)客戶端的請(qǐng)求是無(wú)法直接到達(dá)目標(biāo)服務(wù)器的逞带,需要手動(dòng)控制质涛。
箭頭向下:表示斷點(diǎn)響應(yīng)。此時(shí)目標(biāo)服務(wù)器的響應(yīng)是無(wú)法直接到達(dá)客戶端的掰担,需要手動(dòng)控制汇陆。

  • 通過(guò)命令設(shè)置斷點(diǎn)

    在上圖框起來(lái)的上方的黑色區(qū)域就是命令行,在命令行中輸入命令:

    bpu www.baidu.com  (斷點(diǎn)請(qǐng)求)
    bpu (清除攔截的請(qǐng)求斷點(diǎn))
    bpuafter www.baidu.com(斷點(diǎn)響應(yīng))
    bpuafter (清除攔截的響應(yīng)斷點(diǎn))
    這種方法只會(huì)中斷指定的域名带饱,如示例命令中的www.baidu.com
    
  • AutoResponder標(biāo)簽 - Fiddler 的AutoResponder tab允許你從本地返回文件毡代,而不用將http request 發(fā)送到服務(wù)器上。

構(gòu)造HTTP請(qǐng)求

Composer允許自定義請(qǐng)求發(fā)送到服務(wù)器勺疼,可以手動(dòng)創(chuàng)建一個(gè)新的請(qǐng)求教寂,也可以在會(huì)話表中,拖拽一個(gè)現(xiàn)有的請(qǐng)求执庐。

Parsed模式下你只需要提供簡(jiǎn)單的URLS地址即可(如下圖酪耕,也可以在RequestBody定制一些屬性,如模擬瀏覽器User-Agent)轨淌。

構(gòu)造get請(qǐng)求
抓取手機(jī)數(shù)據(jù)包
手機(jī)抓包設(shè)置

fiddler監(jiān)聽(tīng)端口默認(rèn)是 8888迂烁,你可以把它設(shè)置成任何你想要的端口看尼。勾選上 “Allow remote computersto connect” ,允許遠(yuǎn)程設(shè)備連接盟步。

為了減少干擾藏斩,可以去掉 “Act assystem proxy on startup” 。

手機(jī)端(客戶端)設(shè)置
  • 首先查看電腦的 IP 地址却盘,確保手機(jī)和電腦在同一個(gè)局域網(wǎng)內(nèi)狰域。(cmd命令行內(nèi)輸入ipconfig)

  • 將 Fiddler 代理服務(wù)器的證書(shū)導(dǎo)到手機(jī)上才能抓這些 APP 的包。導(dǎo)入的過(guò)程:打開(kāi)瀏覽器黄橘,在地址欄中輸入代理服務(wù)器的 IP 和端口(即電腦的IP加fiddler的端口)兆览,會(huì)看到一個(gè)Fiddler 提供的頁(yè)面,然后確定安裝就好了塞关。

下載證書(shū)

中拓颓,選擇“修改網(wǎng)絡(luò)”。在接下來(lái)彈出的對(duì)話框中描孟,勾選“顯示高級(jí)選項(xiàng)”驶睦。在接下來(lái)顯示的頁(yè)面中,點(diǎn)擊“代理”匿醒,選擇“手動(dòng)”场航。代理服務(wù)器主機(jī)名設(shè)為 PC 的 IP ,代理服務(wù)器端口設(shè)為 Fiddler 上配置的端口 8888廉羔,點(diǎn)”保存”溉痢。

數(shù)據(jù)驅(qū)動(dòng)DDT實(shí)現(xiàn)API接口自動(dòng)化測(cè)試

  • 安裝requests模塊
pip install requests
  • 使用requests模塊和ddt完成自動(dòng)化api測(cè)試

    import unittest
    import requests
    from ddt import ddt, data, unpack
    import sys
    
    reload(sys)
    sys.setdefaultencoding('utf-8')
    
    @ddt
    class HttpTestCase(unittest.TestCase):
        def setUp(self):
            print "開(kāi)始"
    
        def tearDown(self):
            print "結(jié)束"
    
        @data('101010100', '101250101', '101250301', '101250603', '101251003')
        def testGet(self, city_id):
            # headers = {
            #     "User-Agent": "test"
            # }
            # cookies = {}
    
            result = requests.get("http://www.weather.com.cn/data/sk/" + city_id + ".html")
            result.encoding = 'utf-8'
            print result.text
    
            self.assertTrue(city_id in result.text)
    
    
    if __name__ == '__main__':
        unittest.main()
    
    

    post和get類似,post請(qǐng)求會(huì)多一個(gè)params憋他,也是一個(gè)字典孩饼,key和value的形式,調(diào)用requests.post(url, data=params, headers = headers, cookies = cookies)竹挡。

Android Native APP自動(dòng)化(Python)

自動(dòng)化測(cè)試工具Appium

Appium 是一個(gè)開(kāi)源镀娶、跨平臺(tái)的自動(dòng)化測(cè)試工具,用于測(cè)試Native(原生)Hybrid(混合)應(yīng)用揪罕,支持iOS梯码,Android和FirefoxOS平臺(tái)。

在Android平臺(tái)好啰,是基于UIAutomator 框架轩娶。

Appium的理念
  • 無(wú)需重新編譯應(yīng)用
  • 不局限于語(yǔ)言和框架
  • 無(wú)需重復(fù)造輪子,接口統(tǒng)一
  • 無(wú)論精神上框往,還是名義上鳄抒,必須開(kāi)源(免費(fèi))
Appium的特點(diǎn)
  • 跨架構(gòu),Native、Hybrid许溅、Webview
  • 跨設(shè)備瓤鼻,Android、iOS闹司、Firefox OS
  • 跨語(yǔ)言,Java沐飘、Python游桩、Ruby、PHP耐朴、JavaScript
  • 跨進(jìn)程借卧,不依賴源碼(基于UIAutomator)
appium.jpg
腳本設(shè)計(jì)原則

LOVE原則

  • L:Locate 定位元素
  • O:Operate 操作元素
  • V:Verify 驗(yàn)證結(jié)果
  • E:Exception 處理異常
自動(dòng)化測(cè)試腳本demo編寫(xiě)

下面的demo是對(duì)系統(tǒng)自帶的計(jì)算器APP進(jìn)行測(cè)試的,界面元素的id和包名都是通過(guò)UIAutomator viewer獲取的筛峭。

import unittest
from appium import webdriver


class MyTestCase(unittest.TestCase):

    def setUp(self):
        desired_caps = {}
        desired_caps['platformName'] = 'Android'
        desired_caps['platformVersion'] = '9.0'
        desired_caps['deviceName'] = '192.168.115.101:5555'
        desired_caps['appPackage'] = 'com.android.calculator2'
        desired_caps['appActivity'] = '.Calculator'
        desired_caps["unicodeKeyboard"] = "True"
        desired_caps["resetKeyboard"] = "True"
        self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)

    def test_something(self):
        self.driver.find_element_by_id("digit_1").click()
        self.driver.find_element_by_id("digit_3").click()
        self.driver.find_element_by_id("digit_5").click()
        self.driver.find_element_by_id("op_add").click()
        self.driver.find_element_by_id("digit_8").click()
        self.driver.find_element_by_id("digit_9").click()
        self.driver.find_element_by_id("op_mul").click()
        self.driver.find_element_by_id("digit_3").click()
        self.driver.find_element_by_id("digit_9").click()
        self.driver.find_element_by_id("digit_2").click()
        self.driver.find_element_by_id("eq").click()

        result = self.driver.find_element_by_id("result").text
        self.assertEqual(result, "35,023")

    def tearDown(self):
        # 一定記得退出driver铐刘,不然下次運(yùn)行會(huì)直接報(bào)錯(cuò),除非在Appium中手動(dòng)停止連接
        self.driver.quit()


if __name__ == '__main__':
    unittest.main()

先運(yùn)行Appium影晓,點(diǎn)擊android圖標(biāo)進(jìn)行設(shè)置镰吵,主要設(shè)置platformVersion,我是用的Appium版本為appium1.4.16挂签,由于appium1.4.16版本最高只支持安卓6.0版本疤祭,所以可以參考這篇文章進(jìn)行一些修改設(shè)置,然后運(yùn)行Appium啟動(dòng)連接饵婆,再運(yùn)行上面的demo勺馆,可以得到下面的輸出結(jié)果:

Testing started at 11:56 ...
E:\Python27\python.exe "E:\Program Files\JetBrains\PyCharm Community Edition 2019.1.3\helpers\pycharm\_jb_unittest_runner.py" --target unittestdemo.MyTestCase
Launching unittests with arguments python -m unittest unittestdemo.MyTestCase in F:\code\AutomatedTestingDemo


Ran 1 test in 16.699s

OK

Process finished with exit code 0
Appium常用的相關(guān)API的介紹
  • 控件定位

    方法 說(shuō)明 備注
    find_element_by_id 通過(guò)元素的id定位,返回含有該屬性的元素侨核,在UIAutomator viewer上即resource id 找不到元素時(shí)會(huì)拋出異常草穆,以下同理
    find_elements_by_id 通過(guò)元素的id定位,返回含有該屬性的所有元素 找不到元素時(shí)不會(huì)拋出異常,以下同理
    find_element_by_name 通過(guò)元素Name定位搓译,返回含有該屬性的元素悲柱,對(duì)于android,即text屬性
    find_elements_by_name 通過(guò)元素Name定位(元素的名稱屬性text)些己,含有該屬性的所有元素
    find_element_by_xpath 通過(guò)Xpath定位诗祸,返回含有該屬性的元素
    find_elements_by_xpath 通過(guò)Xpath定位,返回含有該屬性的所有元素
    find_element_by_class_name 通過(guò)元素class name屬性定位,返回包含該屬性的元素
    find_elements_by_class_name 通過(guò)元素class name屬性定位,返回包含該屬性的所有元素 該字段存在的意義主要是為了一些有殘障的人士準(zhǔn)備的轴总,方便他們使用程序
    find_element_by_accessibility_id 通過(guò)accessibility id定位直颅,在android app上相當(dāng)于content-description字段,而在ios app 上accessibility identifier字段 同上
    find_elements_by_accessibility_id 同上
    find_element_by_android_uiautomator 根據(jù)UIautomator定位元素 僅android
    find_elements_by_android_uiautomator 同上 僅android
    find_element_by_ios_uiautomation 在iOS中通過(guò)uiautomation找到一個(gè)元素 僅iOS
    find_elements_by_ios_uiautomation 同上 僅iOS
  • 動(dòng)作操作(手勢(shì)操作)

    方法 說(shuō)明 備注
    click 點(diǎn)擊 element.click()
    send_keys 在元素中模擬輸入 開(kāi)啟appium自帶的輸入法并配置了appium輸入法后怀樟,即unicodeKeyboard功偿、resetKeyboard,可以輸入中英文
    clear 清除輸入的內(nèi)容 element.clear()
    swipe(self, start_x, start_y, end_x, end_y, duration=None) 滑動(dòng),主要用于緩慢滑動(dòng)械荷,從(start_x, start_y)點(diǎn)滑動(dòng)到(end_x, end_y)點(diǎn)共耍,可以自定義duration【毫秒】滑動(dòng)時(shí)間 driver.swipe(100,100,100,400)
    flick(self, start_x, start_y, end_x, end_y) 快速滑動(dòng) 主要用于快速滑動(dòng),無(wú)duration,如View切換吨瞎,按妆远怠(start_x, start_y)點(diǎn)后快速滑動(dòng)至(end_x, end_y)點(diǎn)
    shake 搖一搖
    lock 鎖屏 iOS專有
    scroll(self, origin_el, destination_el) 滾動(dòng) 從元素origin_el滾動(dòng)至元素destination_el,只有iOS可以使用
    drag_and_drop(self, origin_el, destination_el) 拖放 將元素origin_el拖到目標(biāo)元素destination_el
    zoom(self, element=None, percent=200, steps=50) 在元素上執(zhí)行放大 driver.zoom(element)#默認(rèn)分成50步完成,放大量為200%
    pinch(self, element=None, percent=200, steps=50) 在元素上執(zhí)行縮小 driver.pinch (element)
    tap(self, positions, duration=None) 模擬手指點(diǎn)擊(最多五個(gè)手指)颤诀,可設(shè)置按住時(shí)間長(zhǎng)度(單位毫秒)字旭,positions參數(shù)為單位為元組的列表,如[(x1,y1),(x2,y2)] driver.tap([(300,500)],10)
    keyevent 發(fā)送按鍵碼(安卓?jī)H有) KEYCODE_HOME (按鍵Home) : 3 崖叫;KEYCODE_MENU (菜單鍵) : 82 遗淳;KEYCODE_BACK (返回鍵) : 4`
  • 獲取相關(guān)元素及設(shè)備相關(guān)信息

    方法 說(shuō)明 備注
    get_window_size 獲取當(dāng)前設(shè)備的寬、高 width=driver.get_window_size()['width']
    location 獲取元素的左上角坐標(biāo) x=element.location['x']
    size 獲取元素的寬心傀、高 width=element.size['width']
    current_activity 獲取設(shè)備當(dāng)前的activity driver.current_activity
    context 獲取當(dāng)前會(huì)話的當(dāng)前上下文 driver.context
    app_strings 對(duì)于Android屈暗,獲取app的strings.xml文件內(nèi)容 ios待試
  • 其他操作(系統(tǒng)操作如網(wǎng)絡(luò)等、截圖)

    方法 說(shuō)明 備注
    wait_activity(self, activity, timeout, interval=1) 等待指定activity的出現(xiàn)脂男,返回true or false 默認(rèn)是輪詢間隔是1s养叛,需要值得注意的是這里的參數(shù)是current_activity打印出來(lái)的值,即不包含包名
    quit 退出 退出腳本運(yùn)行宰翅,并關(guān)閉每個(gè)相關(guān)的窗口連接
    background_app 后臺(tái)運(yùn)行 把a(bǔ)pp放置于后臺(tái)運(yùn)行一铅,設(shè)置時(shí)間seconds,單位s堕油,相當(dāng)于一段時(shí)間后重啟app潘飘,而不是home將app放置后臺(tái)
    save_screenshot(self, filename) 截圖 filename參數(shù)為路徑,包含文件名稱
    is_app_installed 指定App是否安裝 參數(shù)為包名掉缺,已安裝返回True卜录,否則返回False
    remove_app 卸載指定app 參數(shù)為包名
    install_appt(self, filename) 安裝指定app filename參數(shù)為路徑,包含apk名稱
    launch_app 啟動(dòng)app 啟動(dòng)的app為desired_caps里設(shè)置的app
    close_app 關(guān)閉app 關(guān)閉的app為desired_caps里設(shè)置的app
    start_activity 啟動(dòng)指定activity 參數(shù)為packageName和activityName

Android Native APP自動(dòng)化(Python)

針對(duì)于Hybrid的App眶明,Appium是基于Selendroid框架實(shí)現(xiàn)艰毒,而Selendroid框架又是基于Instrumentation框架實(shí)現(xiàn)的。

可見(jiàn)搜囱,Appium本身是借助于其他框架控制APP丑瞧。

Selendroid的架構(gòu)
selendroid原理
定位頁(yè)面元素
  • 原生頁(yè)面元素:使用UIAutomator viewer定位

  • hybrid頁(yè)面原色: 使用Chrome瀏覽器的Inspector工具(打開(kāi)瀏覽器,按F12進(jìn)入開(kāi)發(fā)者模式蜀肘,先切換成手機(jī)顯示模式绊汹,然后在定位到元素后,在其對(duì)應(yīng)的代碼里右鍵-copy XPath扮宠,其他瀏覽器也可以)西乖。

copy_xpath

上下文

  • O:Operate 操作元素
  • V:Verify 驗(yàn)證結(jié)果
  • E:Exception 處理異常
基于Selendroid的自動(dòng)化腳本實(shí)現(xiàn)

在頁(yè)面里搜索一個(gè)關(guān)鍵詞,并驗(yàn)證和預(yù)期一致

  • Appium的配置、啟動(dòng)

    [圖片上傳失敗...(image-85a3f2-1586312847117)]

  • 腳本的初始化

    [圖片上傳失敗...(image-2236ef-1586312847117)]

  • 腳本的實(shí)現(xiàn) - S-LOVE原則

    import unittest
    import time
    from appium import webdriver
    
    
    class MyTestCase(unittest.TestCase):
    
        def setUp(self):
            # 定義初始化的屬性信息
            self.desired_caps = {}
            self.desired_caps['platformName'] = 'Android'
            self.desired_caps['platformVersion'] = '6.0'
            self.desired_caps['deviceName'] = '192.168.115.101:5555'
            self.desired_caps['appPackage'] = 'com.hyd.miniwebbrowser'
            self.desired_caps['appActivity'] = '.MainActivity'
            self.desired_caps["unicodeKeyboard"] = "True"
            self.desired_caps["resetKeyboard"] = "True"
            self.desired_caps["automationName"] = "Selendroid"
            self.driver = webdriver.Remote('http://localhost:4723/wd/hub', self.desired_caps)
    
        def testSearch(self):
            # Locate 定位輸入框
            input_url = self.driver.find_element_by_id("et_url")
            # Operate 操作
            input_url.send_keys("http://wap.sogou.com")
    
            btn_search = self.driver.find_element_by_id("btn_search")
            btn_search.click()
    
            time.sleep(5)
    
           # Switch 切換當(dāng)前的上下文
            print self.driver.contexts
            self.driver.switch_to.context('WEBVIEW_0')
            print self.driver.current_context
            time.sleep(5)
    
            # 定位web輸入框
            web_input = self.driver.find_element_by_xpath('//*[@id="keyword"]')
            web_input.click()
            web_input.send_keys("2020")
            web_search_button = self.driver.find_element_by_xpath('//*[@id="searchform"]/div/div/div[1]/div[2]/input')
            web_search_button.click()
            time.sleep(5)
    
            # 檢驗(yàn)查詢結(jié)果
            first_result = self.driver.find_element_by_xpath('//*[@id="sogou_vr_30010212_1"]/div/div[1]/a[1]')
            self.assertTrue("2020" in first_result.text)
    
        def tearDown(self):
            self.driver.quit()
    
    
    if __name__ == '__main__':
        unittest.main()
    
  • 腳本的運(yùn)行

    Testing started at 18:47 ...
    E:\Python27\python.exe "E:\Program Files\JetBrains\PyCharm Community Edition 2019.1.3\helpers\pycharm\_jb_unittest_runner.py" --target HybridScript.MyTestCase.testSearch
    Launching unittests with arguments python -m unittest HybridScript.MyTestCase.testSearch in F:\code\AutomatedTestingDemo\hybrid_app
    
    
    Ran 1 test in 39.463s
    
    OK
    
    Process finished with exit code 0
    [u'WEBVIEW_0', u'NATIVE_APP']
    WEBVIEW_0
    

結(jié)語(yǔ)

本文主要是我自己在學(xué)習(xí)用Python對(duì)Android APP進(jìn)行自動(dòng)化測(cè)試時(shí)踩過(guò)的一些坑和寫(xiě)的Demo获雕,離真正的自動(dòng)化測(cè)試還有一定的距離薄腻,所以大家可以多寫(xiě)寫(xiě)自動(dòng)化測(cè)試腳本,業(yè)精于勤届案!有不對(duì)的地方也請(qǐng)?jiān)谠u(píng)論里指出庵楷,謝謝!
文中代碼已上傳至GitHub楣颠,傳送門尽纽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市球碉,隨后出現(xiàn)的幾起案子蜓斧,更是在濱河造成了極大的恐慌仓蛆,老刑警劉巖睁冬,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異看疙,居然都是意外死亡豆拨,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門能庆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)施禾,“玉大人,你說(shuō)我怎么就攤上這事搁胆∶指悖” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵渠旁,是天一觀的道長(zhǎng)攀例。 經(jīng)常有香客問(wèn)我,道長(zhǎng)顾腊,這世上最難降的妖魔是什么粤铭? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮杂靶,結(jié)果婚禮上梆惯,老公的妹妹穿的比我還像新娘。我一直安慰自己吗垮,他們只是感情好垛吗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著烁登,像睡著了一般职烧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天蚀之,我揣著相機(jī)與錄音蝗敢,去河邊找鬼。 笑死足删,一個(gè)胖子當(dāng)著我的面吹牛寿谴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播失受,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼讶泰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了拂到?” 一聲冷哼從身側(cè)響起痪署,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎兄旬,沒(méi)想到半個(gè)月后狼犯,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡领铐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年悯森,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绪撵。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瓢姻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出音诈,到底是詐尸還是另有隱情幻碱,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布细溅,位于F島的核電站褥傍,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏谒兄。R本人自食惡果不足惜摔桦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望承疲。 院中可真熱鬧邻耕,春花似錦、人聲如沸燕鸽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)啊研。三九已至御滩,卻和暖如春鸥拧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背削解。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工富弦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人氛驮。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓腕柜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親矫废。 傳聞我的和親對(duì)象是個(gè)殘疾皇子盏缤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容