沙河口網(wǎng)站建設(shè)競(jìng)價(jià)排名什么意思
前言:
小目標(biāo)
關(guān)于UI自動(dòng)化的定義,我想要的是自動(dòng)地按照流程去點(diǎn)擊頁(yè)面、輸入數(shù)據(jù),不需要人去參與,節(jié)省人工時(shí)間。比如登錄,能夠自己去填寫(xiě)用戶名&密碼,然后點(diǎn)擊按鈕跳轉(zhuǎn)到下一個(gè)頁(yè)面等。在能夠保證業(yè)務(wù)的足夠穩(wěn)定性的條件下,UI自動(dòng)化測(cè)試能夠節(jié)省很多回歸功能的人力。這就是我的一個(gè)小目標(biāo)。
測(cè)試需要全面,需要對(duì)結(jié)果去做判斷。如果熟悉單元測(cè)試或接口自動(dòng)化的朋友,應(yīng)該知道這些其實(shí)就是功能覆蓋、用例設(shè)計(jì)、斷言……這些概念。于是小目標(biāo)就升級(jí)成了,一個(gè)可以重復(fù)執(zhí)行,多場(chǎng)景的,結(jié)果可預(yù)測(cè)的UI自動(dòng)化測(cè)試。
正文:
測(cè)試基礎(chǔ)
軟件測(cè)試是為了發(fā)現(xiàn)錯(cuò)誤而執(zhí)行程序的過(guò)程?;蛘哒f(shuō),是根據(jù)軟件開(kāi)發(fā)各階段的規(guī)格說(shuō)明和程序內(nèi)部結(jié)構(gòu)而精心設(shè)計(jì)的一批測(cè)試用例(即輸入數(shù)據(jù)及預(yù)期的輸出結(jié)果),并利用這些測(cè)試用例去運(yùn)行程序,以發(fā)現(xiàn)程序錯(cuò)誤的過(guò)程。
白盒測(cè)試(White Box Testing) 又稱結(jié)構(gòu)測(cè)試、邏輯驅(qū)動(dòng)測(cè)試,完全了解程序的結(jié)構(gòu)和處理過(guò)程,按照程序的內(nèi)部邏輯測(cè)試程序,檢驗(yàn)程序中的每條通路是否都能按預(yù)定要求準(zhǔn)確工作;對(duì)應(yīng)到實(shí)際工作中,代碼diff就是白盒測(cè)試。
黑盒測(cè)試(Black Box Testing) 又稱功能測(cè)試,在程序接口進(jìn)行的測(cè)試,已知產(chǎn)品的功能設(shè)計(jì)規(guī)格,可以進(jìn)行測(cè)試證明每個(gè)實(shí)現(xiàn)了的功能是否符合要求。對(duì)應(yīng)到工作中,Checklist&Case就是功能測(cè)試。UI自動(dòng)化測(cè)試,是將功能測(cè)試中大量的重復(fù)性操作(例如線上回歸)提取出來(lái),用腳本的形式驅(qū)動(dòng)設(shè)備進(jìn)行測(cè)試,有著可重復(fù)運(yùn)行,執(zhí)行效率高的特點(diǎn)。
測(cè)試用例
測(cè)試用例是為特定的目的而設(shè)計(jì)的一組測(cè)試輸入、 執(zhí)行條件和預(yù)期的結(jié)果。
1.測(cè)試用例需要能夠覆蓋被測(cè)試的功能。
2.測(cè)試的結(jié)果的正確性是可判定的,每一個(gè)測(cè)試用例都應(yīng)該有相應(yīng)的期望結(jié)果。
3.即對(duì)同樣的測(cè)試用例,系統(tǒng)的執(zhí)行結(jié)果應(yīng)當(dāng)是相同的。
如何覆蓋被測(cè)試功能,我們需要對(duì)輸入進(jìn)行分類劃分:等價(jià)類劃分方法,邊界值分析方法。
等價(jià)類劃分方法,將程序的輸入域劃分為若干個(gè)等價(jià)類(子集),然后從每一個(gè)子集中選取少數(shù)具有代表性的數(shù)據(jù)作為測(cè)試用例??梢杂行p少輸入類型。例如用戶名輸入,可以劃分為允許的字符類型:數(shù)字、字母,不允許的字符類型:特殊字符,漢字,空格等。
邊界值分析方法,邊界值分析法就是對(duì)輸入或輸出的邊界值進(jìn)行測(cè)試的一種黑盒測(cè)試方法。通常邊界值分析法是作為對(duì)等價(jià)類劃分法的補(bǔ)充,這種情況下,其測(cè)試用例來(lái)自等價(jià)類的邊界。例如用戶名長(zhǎng)度是4-10位,我們依據(jù)邊界值,就需要對(duì)3、4、10、11這四個(gè)邊界值分別做測(cè)試。
相對(duì)的,輸出類劃分后,對(duì)每一種輸入都有唯一對(duì)應(yīng)的輸出,這個(gè)輸出和功能無(wú)關(guān),不管是正常流還是異常流,都需給出唯一結(jié)果。我們稱之為斷言,斷言一般分為這這幾類:等于、不等于、包括、不包括 或復(fù)雜的組合邏輯。
UI自動(dòng)化測(cè)試用例
UI自動(dòng)化在用例設(shè)計(jì)上也需滿足上述性質(zhì),此外在輸入中需要過(guò)程中需要定義UI的操作,同時(shí)在結(jié)果的判定上,會(huì)依賴UI元素的展示和頁(yè)面的狀態(tài)。比如某種異常狀態(tài)下會(huì)彈窗提示,我們則需要去獲取這個(gè)彈窗,然后對(duì)彈窗上UI元素進(jìn)行比對(duì)和判斷,而無(wú)法去做返回碼的比較判斷。關(guān)于頁(yè)面狀態(tài)的斷言,相對(duì)于直接數(shù)據(jù)的比較判斷不夠直接、難度較大,當(dāng)前還有很多難點(diǎn)。
2.UIAutomation
iOS4時(shí)代,Apple發(fā)布了一個(gè)名為UIAutomation的測(cè)試框架,它可以用來(lái)在真實(shí)設(shè)備和iPhone模擬器上執(zhí)行自動(dòng)化測(cè)試。UIAutomation的功能測(cè)試代碼是用Javascript編寫(xiě)的。UIAutomation和Accessibility有著直接的關(guān)系,你將用到通過(guò)標(biāo)簽和值的訪問(wèn)性來(lái)獲得UI元素,同時(shí)完成相應(yīng)的交互操作。
UIAutomation的js測(cè)試腳本,需要在Instrument的Automation控件上測(cè)試。但是在Xcode8.0之后,Instrument已經(jīng)不再有這個(gè)模塊了。而Apple也不再對(duì)它維護(hù)了,推廣使用UITest來(lái)替代它。
Accessibility
UIAutomation的實(shí)現(xiàn)原理依賴于UI控件的Accessibility,這項(xiàng)技術(shù)是為了輔助身體不便的人士使用 app。VoiceOver 是 Apple 的屏幕閱讀技術(shù),UI Accessibility 的基本原則就是對(duì)屏幕上的 UI 元素進(jìn)行分類和標(biāo)記,兩者配合,通過(guò)閱讀或者聆聽(tīng)這些元素,用戶就可以在不接觸屏幕的情況下通過(guò)聲音來(lái)使用 app。
如果一個(gè)控件的Accessibility是可以被訪問(wèn)的,你就可以設(shè)置和讀取它的值,作相關(guān)的操作,而當(dāng)一個(gè)控件的Accessibility不可見(jiàn)時(shí),你就沒(méi)有辦法通過(guò)automation訪問(wèn)它。每一個(gè)可以被訪問(wèn)(Accessibility enable)的UIKit控件都可以用一個(gè)Javascript對(duì)象來(lái)描述,它就是一個(gè)UIAElement。UIAElement有幾個(gè)屬性:name, value, elements, parent。UIKit層次樹(shù)結(jié)構(gòu),可以直接映射到UIAElement的層次樹(shù)。有了基本屬性和層次樹(shù)結(jié)構(gòu),我們就可以方便的使用JS對(duì)App中的空間進(jìn)行操作了。
看這個(gè)簡(jiǎn)單的小栗子,操作流程:找到tabbar->找到名稱是“First”的button點(diǎn)擊->給第一個(gè)textField設(shè)值->點(diǎn)擊鍵盤(pán)的return->取id是“RecipeName”的staticTexts(label)的值->斷言該label內(nèi)容和之前輸入內(nèi)容的相等。
可以看出尋找控件的兩種方式:依據(jù)控件Accessibility identitifer查找;依據(jù)控件在數(shù)組的下標(biāo)查找。前者需要你去設(shè)置,增加開(kāi)發(fā)時(shí)成本。后者的變化性高,UI層級(jí)改變導(dǎo)致你的用例改變。
?
test("Test 1", function(target, app) {target.logDevice();var window = app.mainWindow();app.logElementTree();//-- select the elementsUIALogger.logMessage( "Select the first tab" );var tabBar = app.tabBar();var selectedTabName = tabBar.selectedButton().name();if (selectedTabName != "First") {tabBar.buttons()["First"].tap();}//-- tap on the text fielsUIALogger.logMessage( "Tap on the text field now" );var recipeName = "Unusually Long Name for a Recipe";window.textFields()[0].setValue(recipeName);target.delay( 2 );//-- tap on the text fielsUIALogger.logMessage( "Dismiss the keyboard" );app.logElementTree();app.keyboard().buttons()["return"].tap();var textValue = window.staticTexts()["RecipeName"].value();assertEquals(recipeName, textValue);
});
3.UITest
UITest是Apple隨著Xcode 7和iOS 9新的UI自動(dòng)化測(cè)試框架。較之前不同的是,在UITest框架下,我們可以使用自己熟悉的Objc和Swift語(yǔ)言來(lái)編寫(xiě)自動(dòng)化測(cè)試的腳本。除此之外,UITest最大的亮點(diǎn)是支持屏幕錄制——通過(guò)對(duì)App的操作自動(dòng)生成相應(yīng)的測(cè)試腳本代碼。這意味著非專業(yè)人士,也可以很方便地參與到自動(dòng)化測(cè)試?yán)飦?lái)。
原理和UIAutomation一樣,UITest也依賴控件的Accessibility屬性,UITest為所有UIKit控件提供了一個(gè)XCUI開(kāi)頭的代理類。比如UIApplication,對(duì)應(yīng)的是XCUIApplication,在 UI Testing 中代表整個(gè) app 的對(duì)象。
對(duì)于一般的UIKit對(duì)象,Apple提供XCUIElement對(duì)象作為映射。我們不能直接通過(guò)得到的 XCUIElement 來(lái)直接訪問(wèn)被測(cè) app 中的元素,而只能通過(guò) Accessibility 中的像是 identifier 或者 frame 這樣的屬性來(lái)獲取 UI 的信息。關(guān)于具體的可用屬性,可以參看 XCUIElementAttributes 的文檔。雖然不能直接通過(guò)Element得到屬性,但是可以通過(guò)- descendantsMatchingType:,訪問(wèn)子節(jié)點(diǎn),從而得到層級(jí)結(jié)構(gòu)。
hello world和屏幕錄制操作,可以參考喵大的筆記,附有demo哦。
4.Appium
UITest支持iOS開(kāi)發(fā)熟悉的編程語(yǔ)言、屏幕錄制等多項(xiàng)強(qiáng)大功能,但這些都是和Xcode這個(gè)IDE綁定的。當(dāng)我們?cè)赬code里寫(xiě)完代碼,本地運(yùn)行,這種種更像是單元測(cè)試,而沒(méi)有太多自動(dòng)化的味道了。一段真正的自動(dòng)化測(cè)試腳本,應(yīng)該和被測(cè)代碼分開(kāi),能夠部署到一臺(tái)服務(wù)器上自動(dòng)運(yùn)行,讓一項(xiàng)自動(dòng)化測(cè)試真正自動(dòng)化起來(lái),成為了我的小目標(biāo)3.0版本。在這里,Appium這個(gè)強(qiáng)大的自動(dòng)化測(cè)試工具登場(chǎng)了,看看他的自我介紹。
跨平臺(tái)、開(kāi)源、多設(shè)備多系統(tǒng)的支持,而且文檔詳細(xì),還有中文版本,實(shí)在是業(yè)界良心。
背景
關(guān)于Appium的介紹,官方的文檔已經(jīng)說(shuō)得很清楚了,我這兒大致提煉一下幾個(gè)重要的點(diǎn)。
1.無(wú)需為了自動(dòng)化,而重新編譯或者修改你的應(yīng)用
在iOS上,這個(gè)特性是顯然的。前面也說(shuō)道了,因?yàn)锳pple提供了Accessibility特性,讓你可以得到控件響應(yīng)的id,frame等。還可以通過(guò)代理,從而得到樹(shù)形層級(jí)結(jié)構(gòu)。
2.跨平臺(tái)
這主要?dú)w功于Appium的自動(dòng)化統(tǒng)一接口WebDriver API.WebDriver(也就是 “Selenium WebDriver”)。我們使用這套統(tǒng)一的接口,在各自平臺(tái)上去解釋,得到不同的底層實(shí)現(xiàn)。比如iOS這邊是UIAutomation和UITest,Android則是UiAutomator和Instrumentation。
3.多種語(yǔ)言編寫(xiě)&執(zhí)行測(cè)試腳本
這得益于Appium的C/S架構(gòu),我們將編寫(xiě)執(zhí)行腳本的部分稱為客戶端(Clinet),腳本內(nèi)容遵循統(tǒng)一接口。每一行,其實(shí)就是Client向服務(wù)器去發(fā)送一條Http消息,然后Server解析并翻譯成對(duì)應(yīng)平臺(tái)(iOS/Adr)的實(shí)際測(cè)試命令,再發(fā)送給Device,再執(zhí)行。可以通過(guò)下面的示意圖簡(jiǎn)單了解。
因?yàn)镾erver層的存在,和統(tǒng)一接口的隔離,實(shí)現(xiàn)了腳本實(shí)現(xiàn)和執(zhí)行條件的多樣性?,F(xiàn)已知的就支持Java、Python、js、Ruby等方式的Client API。
安裝指南
同樣,官方文檔的快速開(kāi)始也給出了詳盡的步驟。但是實(shí)際上我在MAC上安裝Appium的時(shí)候,還是遇到了各種各樣的坑。這個(gè)指南部分,希望能幫助大家趟過(guò)這些坑。
0.下載圖形化桌面應(yīng)用 Appium App
目前更新到1.5,不支持Xcode8 和UITest。如果還在使用Xcode 7系列的版本可以直接下載使用。
1.安裝 homebrew & node 如果接觸過(guò)web前端的同學(xué)應(yīng)該不會(huì)陌生。
2.node安裝appium
?
npm install -g appium
?
到這里需要掛代理翻墻。如果沒(méi)有條件的話,可以使用淘寶的NPM 鏡像。
安裝到一半,應(yīng)該會(huì)遇到/usr/local目錄權(quán)限問(wèn)題。這里給個(gè)小提示,建議給/usr/local/lib/node_modules/appium開(kāi)全權(quán)限sudo chmod -R 777 ./ ,不建議使用sudo,據(jù)說(shuō)會(huì)遇到別的問(wèn)題。如果中途遇到錯(cuò)誤,使用
npm uninstall -g appium
?
命令卸載,然后重裝。如果卸載不了,就直接去Finder/usr/local/lib/node_modules/appium目錄刪除就好了。
安裝好之后,運(yùn)行
$ appium &
命令就可以啟動(dòng)Appium的server了。
Hello World!
安裝好了Appium server之后,可以開(kāi)始運(yùn)行第一個(gè)程序了。去官網(wǎng)下載示例代碼。下載之后你能看到有一個(gè)apps的文件夾和examples文件夾,前者放的是示例程序,后面是不同語(yǔ)言客戶端的測(cè)試腳本。打開(kāi) apps/TestApp,運(yùn)行能看到這是一個(gè)單頁(yè)面的程序,最上方有兩個(gè)輸入框,輸入數(shù)字,點(diǎn)擊Compute Sum按鈕,就能得出兩者相加的和。
下面我們就來(lái)做這個(gè)部分的UI自動(dòng)化測(cè)試。找一個(gè)自己熟悉的Client語(yǔ)言去執(zhí)行自動(dòng)化腳本,比如Java。打開(kāi),是一個(gè)Maven工程,下載了相應(yīng)依賴庫(kù)。之后打開(kāi)SimpleTest文件,因?yàn)閄code 8不支持UIAutomation框架,所以需要在setup中指定capability方式為XCUItest。
?
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "XCUITest");
capabilities.setCapability("platformVersion", "10.0");
capabilities.setCapability("deviceName", "iPhone 6");
運(yùn)行testUIComputation方法??梢钥吹侥M器啟動(dòng)了,但是之后會(huì)遇到Carthage找不到的問(wèn)題
裝上之后
官方Issues中找到了答案,WebDriverAgent缺少webpack。使用npm i -g webpack安裝就好。PS:和之前一樣使用淘寶源或者掛一個(gè)代理。
完成了以上步驟之后,你就能看到你的Test在模擬器中自動(dòng)運(yùn)行,隨著Terminal大量的log輸出,測(cè)試結(jié)果也成功返回到Java的Client,在IDEA中看到執(zhí)行結(jié)果,PASS!到此為止,第一個(gè)自動(dòng)化測(cè)試被執(zhí)行成功了~
Client - Server - Device交互
driver.findElements
我們以java代碼driver.findElements(By.className(“UIATextField”))找到textField數(shù)組的過(guò)程為例子,去分析一下log,看看一次交互式怎么進(jìn)行的。?
?
// client ----http----> server
[HTTP] --> POST /wd/hub/session/94f7526c-94ba-4ece-8740-d94bd3d4f50f/elements {"using":"class name","value":"UIATextField"}[MJSONWP] Calling AppiumDriver.findElements() with args: ["class name","UIATextField","94f7526c-94ba-4ece-8740-d94bd3d4f50f"]
[debug] [XCUITest] Executing command 'findElements'
[debug] [BaseDriver] Valid locator strategies for this request: xpath, id, name, class name, -ios predicate string, accessibility id
[XCUITest] Rewrote incoming selector from 'UIATextField' to 'XCUIElementTypeTextField' to match XCUI type. You should consider updating your tests to use the new selectors directly
[debug] [BaseDriver] Waiting up to 0 ms for condition// server ----http----> device
[JSONWP Proxy] Proxying [POST /elements] to [POST http://localhost:8100/session/79CBBB84-DB6E-48BA-B79F-91539E1E4708/elements] with body: {"using":"class name","value":"XCUIElementTypeTextField"}// device ----http----> server
[JSONWP Proxy] Got response with status 200: {"value":[{"ELEMENT":"1A29AE60-5433-4B52-83F8-B4E2C794972E","type":"XCUIElementTypeTextField","label":"TextField1"},{"ELEMENT":"575EE2C2-4AFF-4320-B4D0-C30F59410DA9","type":"XCUIElementTypeTextField","label":"TextField2"}],"sessionId":"79CBBB84-DB6E-48BA-B79F-91539E1E4708","status":0}[MJSONWP] Responding to client with driver.findElements() result: [{"ELEMENT":"1A29AE60-5433-4B52-83F8-B4E2C794972E","type":"XCUIElementTypeTextField","label":"TextField1"},{"ELEMENT":"575EE2C2-4AFF-4320-B4D0-C30F59410DA9","type":"XCUIElementTypeTextField","label":"TextField2"}]
// server ----http----> client
[HTTP] <-- POST /wd/hub/session/94f7526c-94ba-4ece-8740-d94bd3d4f50f/elements 200 225 ms - 285
其中
[MJSONWP] 打印的是S內(nèi)部的處理日志。
[JSONWP Proxy] 打印的是S/D之間的通信日志。
可以看到,Client、Server、Device是通過(guò)Http協(xié)議通信的,大致流程為:
Client通過(guò)http協(xié)議,將指定格式的命令發(fā)送給server。server調(diào)用中間層AppiumDriver解析命令,發(fā)送給實(shí)際的處理者。實(shí)際處理者依據(jù)平臺(tái)、版本不同而不一樣,這里是XCUITest(iOS)。而Device(iphone、模擬器)和Server的通訊也是通過(guò)http協(xié)議。
到這里,大家會(huì)有疑問(wèn)了,Server怎么找到對(duì)應(yīng)的Device,他們之間如何通過(guò)Http通訊的?這里就要引出WebDriverAgent。它的作用:
WDA的inspector演示:直接在瀏覽器端打開(kāi) http://192.168.0.105:8100/inspector
TextField賦值
再看TextField賦值java代碼elem.sendKeys(String.valueOf(rndNum));的執(zhí)行步驟
[HTTP] --> POST /wd/hub/session/94f7526c-94ba-4ece-8740-d94bd3d4f50f/element/1A29AE60-5433-4B52-83F8-B4E2C794972E/value {"id":"1A29AE60-5433-4B52-83F8-B4E2C794972E","value":["1"]}[MJSONWP] Calling AppiumDriver.setValue() with args: [["1"],"1A29AE60-5433-4B52-83F8-B4E2C794972E","94f7526c-94ba-4ece-8740-d94bd3d4f50f"]
[debug] [XCUITest] Executing command 'setValue'[JSONWP Proxy] Proxying [GET /element/1A29AE60-5433-4B52-83F8-B4E2C794972E/attribute/type] to [GET http://localhost:8100/session/79CBBB84-DB6E-48BA-B79F-91539E1E4708/element/1A29AE60-5433-4B52-83F8-B4E2C794972E/attribute/type] with no body
[JSONWP Proxy] Got response with status 200: "{\n \"value\" : \"XCUIElementTypeTextField\",\n \"sessionId\" : \"79CBBB84-DB6E-48BA-B79F-91539E1E4708\",\n \"status\" : 0\n}"
[debug] [BaseDriver] Set implicit wait to 0ms
[debug] [BaseDriver] Waiting up to 0 ms for condition
[JSONWP Proxy] Proxying [POST /element] to [POST http://localhost:8100/session/79CBBB84-DB6E-48BA-B79F-91539E1E4708/element] with body: {"using":"class name","value":"XCUIElementTypeKeyboard"}
[JSONWP Proxy] Got response with status 200: {"value":{"using":"class name","value":"XCUIElementTypeKeyboard","description":"unable to find an element"},"sessionId":"79CBBB84-DB6E-48BA-B79F-91539E1E4708","status":7}
[debug] [XCUITest] No keyboard found. Clicking element to open it.
[JSONWP Proxy] Proxying [POST /element/1A29AE60-5433-4B52-83F8-B4E2C794972E/click] to [POST http://localhost:8100/session/79CBBB84-DB6E-48BA-B79F-91539E1E4708/element/1A29AE60-5433-4B52-83F8-B4E2C794972E/click] with body: {}
[JSONWP Proxy] Got response with status 200: {"status":0,"id":"1A29AE60-5433-4B52-83F8-B4E2C794972E","value":"","sessionId":"79CBBB84-DB6E-48BA-B79F-91539E1E4708"}
[debug] [BaseDriver] Waiting up to 0 ms for condition
[JSONWP Proxy] Proxying [POST /element] to [POST http://localhost:8100/session/79CBBB84-DB6E-48BA-B79F-91539E1E4708/element] with body: {"using":"class name","value":"XCUIElementTypeKeyboard"}
[JSONWP Proxy] Got response with status 200: {"value":{"ELEMENT":"FB515A63-3249-419E-8106-2681A1FEBA24","type":"XCUIElementTypeKeyboard","label":null},"sessionId":"79CBBB84-DB6E-48BA-B79F-91539E1E4708","status":0}
[debug] [BaseDriver] Set implicit wait to 0ms
[JSONWP Proxy] Proxying [POST /element/1A29AE60-5433-4B52-83F8-B4E2C794972E/value] to [POST http://localhost:8100/session/79CBBB84-DB6E-48BA-B79F-91539E1E4708/element/1A29AE60-5433-4B52-83F8-B4E2C794972E/value] with body: {"value":["1"]}
[JSONWP Proxy] Got response with status 200: {"status":0,"id":"1A29AE60-5433-4B52-83F8-B4E2C794972E","value":"","sessionId":"79CBBB84-DB6E-48BA-B79F-91539E1E4708"}[MJSONWP] Responding to client with driver.setValue() result: null
[HTTP] <-- POST /wd/hub/session/94f7526c-94ba-4ece-8740-d94bd3d4f50f/element/1A29AE60-5433-4B52-83F8-B4E2C794972E/value 200 2247 ms - 76
?
這看出setValue命令,包含幾個(gè)步驟:檢查是否打開(kāi)鍵盤(pán)、獲取輸入框、彈出鍵盤(pán)、輸入框賦值,每一個(gè)步驟都會(huì)和Device通訊。
發(fā)送數(shù)據(jù)
session/94f7526c-94ba-4ece-8740-d94bd3d4f50f 這個(gè)指定了當(dāng)前這個(gè)case的唯一id,在第一次通信時(shí)確立。由于第一次通信比較復(fù)雜,在最后會(huì)講到。之后是id為1A29AE60-5433-4B52-83F8-B4E2C794972E 的Element,剛好是上一次請(qǐng)求列表的第一個(gè)元素,表明這次是對(duì)這個(gè)元素做操作。再看value,是一個(gè)json,定義的剛好是這個(gè)Eelemet和它的值,這些就是自動(dòng)化統(tǒng)一接口的格式,一個(gè)簡(jiǎn)單命令的定義。
建立Session
?
[Appium] Appium REST http interface listener started on 0.0.0.0:4723
[HTTP] --> POST /wd/hub/session {"desiredCapabilities":{"app":"/Users/zhiyu.zhao/Desktop/appiumTest/sample-code/sample-code/examples/java/junit/../../../apps/TestApp/build/release-iphonesimulator/TestApp.app","automationName":"XCUITest","platformName":"iOS","deviceName":"iPhone 6","platformVersion":"10.0"}}
[MJSONWP] Calling AppiumDriver.createSession() with args: [{"app":"/Users/zhiyu.zhao/Desktop/appiumTest/sample-code/sample-code/examples/java/junit/../../../apps/TestApp/build/release-iphonesimulator/TestApp.app","automationName":"XCUITest","platformName":"iOS","deviceName":"iPhone 6","platformVersion":"...[Appium] Creating new XCUITestDriver session
[Appium] Capabilities:
[Appium] app: '/Users/zhiyu.zhao/Desktop/appiumTest/sample-code/sample-code/examples/java/junit/../../../apps/TestApp/build/release-iphonesimulator/TestApp.app'
[Appium] automationName: 'XCUITest'
[Appium] platformName: 'iOS'
[Appium] deviceName: 'iPhone 6'
[Appium] platformVersion: '10.0'[debug] [XCUITest] XCUITestDriver version: 2.0.33
[BaseDriver] Session created with session id: 94f7526c-94ba-4ece-8740-d94bd3d4f50f
[debug] [XCUITest] Xcode version set to '8.0'
[debug] [XCUITest] iOS SDK Version set to '10.0'
[iOSSim] Constructing iOS simulator for Xcode version 8.0 with udid 'B9747B0B-C664-4C44-A651-9C3D8F7A980A'// 開(kāi)啟模擬器
[XCUITest] Determining device to run tests on: udid: 'B9747B0B-C664-4C44-A651-9C3D8F7A980A', real device: false
[BaseDriver] Using local app '/Users/zhiyu.zhao/Desktop/appiumTest/sample-code/sample-code/examples/java/junit/../../../apps/TestApp/build/release-iphonesimulator/TestApp.app'
[debug] [XCUITest] Checking whether app '/Users/zhiyu.zhao/Desktop/appiumTest/sample-code/sample-code/examples/java/junit/../../../apps/TestApp/build/release-iphonesimulator/TestApp.app' is actually present
[debug] [XCUITest] App is present
[debug] [ios-app-utils] Getting bundle ID from app '/Users/zhiyu.zhao/Desktop/appiumTest/sample-code/sample-code/examples/java/junit/../../../apps/TestApp/build/release-iphonesimulator/TestApp.app': 'io.appium.TestApp'
[debug] [iOSLog] Starting iOS 10.0 simulator log capture
[debug] [iOSLog] System log path: /Users/zhiyu.zhao/Library/Logs/CoreSimulator/B9747B0B-C664-4C44-A651-9C3D8F7A980A/system.log
[XCUITest] Setting up simulator
[debug] [iOS] No reason to set locale
[debug] [iOS] No iOS / app preferences to set
[XCUITest] Simulator with udid 'B9747B0B-C664-4C44-A651-9C3D8F7A980A' not booted. Booting up now
[debug] [iOSSim] Killing all iOS Simulators
zhiyu.zhao@999999999:~|? [iOSSim] Starting simulator with command: open /Applications/Xcode.app/Contents/Developer/Applications/Simulator.app --args -CurrentDeviceUDID B9747B0B-C664-4C44-A651-9C3D8F7A980A
[iOSSim] Tailing simulator logs until we encounter the string "SMS Plugin initialized"
[iOSSim] We will time out after 60000ms
[debug] [iOSSim] Waiting an extra 10000ms for the simulator to really finish booting
[debug] [iOSSim] Done waiting extra time for simulator
[iOSSim] Simulator booted in 26076ms// 安裝TestApp、開(kāi)啟WebDriverAgent
[debug] [XCUITest] Installing app '/Users/zhiyu.zhao/Desktop/appiumTest/sample-code/sample-code/examples/java/junit/../../../apps/TestApp/build/release-iphonesimulator/TestApp.app' on device
[XCUITest] Using default agent: /usr/local/lib/node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent/WebDriverAgent.xcodeproj
[XCUITest] Using default bootstrap: /usr/local/lib/node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent
[XCUITest] Launching WebDriverAgent on the device
[debug] [XCUITest] Carthage found: /usr/local/bin/carthage
[debug] [XCUITest] Killing hanging processes
[debug] [XCUITest] Beginning test with command 'xcodebuild build test -project /usr/local/lib/node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent/WebDriverAgent.xcodeproj -scheme WebDriverAgentRunner -destination id=B9747B0B-C664-4C44-A651-9C3D8F7A980A -configuration Debug' in directory '/usr/local/lib/node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent'
[XCUITest] Waiting for WebDriverAgent to start on device[debug] [WebDriverAgent] Sim: Nov 2 16:50:33 999999999 CoreSimulatorBridge[56212]: Pasteboard change listener callback port <NSMachPort: 0x7ff8707030a0> registered[Xcode] === BUILD TARGET WebDriverAgentLib OF PROJECT WebDriverAgent WITH CONFIGURATION Debug ===[Xcode] === BUILD TARGET WebDriverAgentRunner OF PROJECT WebDriverAgent WITH CONFIGURATION Debug ===// WebDriverAgentRunner-Runner.app
[debug] [WebDriverAgent] Sim: Nov 2 16:50:42 999999999 CoreSimulatorBridge[56212]: Requesting installation of file:///Users/zhiyu.zhao/Library/Developer/Xcode/DerivedData/WebDriverAgent-brdadhpuduowllgivnnvuygpwhzy/Build/Products/Debug-iphonesimulator/WebDriverAgentRunner-Runner.app/ with options: {[debug] [WebDriverAgent] Sim: Nov 2 16:50:46 999999999 CoreSimulatorBridge[56212]: [Common] [FBSSystemService][0xc2a4] Sending request to open "com.apple.test.WebDriverAgentRunner-Runner"
[debug] [WebDriverAgent] Sim: Nov 2 16:50:46 999999999 CoreSimulatorBridge[56212]: [Common] [FBSSystemService][0xc2a4] Request successful: <FBSProcessHandle: 0x7ff870505830; XCTRunner:56563; valid: YES>
[debug] [WebDriverAgent] Sim: Nov 2 16:50:47 999999999 XCTRunner[56563]: assertion failed: 15G31 14A345: libxpc.dylib + 62597 [37A9DF49-35C1-3D93-B854-B35CACF0100F]: 0x7d
[debug] [WebDriverAgent] Sim: Nov 2 16:50:47 999999999 XCTRunner[56563]: Running tests...
[debug] [WebDriverAgent] Sim: Nov 2 16:50:48 --- last message repeated 4 times ---
[debug] [WebDriverAgent] Sim: Nov 2 16:50:48 999999999 XCTRunner[56563]: Continuing to run tests in the background with task ID 1
[debug] [WebDriverAgent] Sim: Nov 2 16:50:48 --- last message repeated 13 times ---
[debug] [WebDriverAgent] Sim: Nov 2 16:50:48 999999999 XCTRunner[56563]: Built at Nov 2 2016 16:50:41[XCUITest] Detected that WebDriverAgent is running at url 'http://10.86.132.138:8100'
[debug] [WebDriverAgent] Sim: Nov 2 16:50:48 999999999 XCTRunner[56563]: ServerURLHere->http://10.86.132.138:8100<-ServerURLHere
[XCUITest] WebDriverAgent started at url 'http://10.86.132.138:8100'[JSONWP Proxy] Proxying [POST /session] to [POST http://localhost:8100/session] with body: {"desiredCapabilities":{"bundleId":"io.appium.TestApp","arguments":[],"environment":{},"shouldWaitForQuiescence":true}}
[JSONWP Proxy] Got response with status 200: {"value":{"sessionId":"79CBBB84-DB6E-48BA-B79F-91539E1E4708","capabilities":{"device":"iphone","browserName":"TestApp","sdkVersion":"10.0","CFBundleIdentifier":"io.appium.TestApp"}},"sessionId":"79CBBB84-DB6E-48BA-B79F-91539E1E4708","status":0}[Appium] New XCUITestDriver session created successfully, session 94f7526c-94ba-4ece-8740-d94bd3d4f50f added to master session list
[MJSONWP] Responding to client with driver.createSession() result: {"webStorageEnabled":false,"locationContextEnabled":false,"browserName":"","platform":"MAC","javascriptEnabled":true,"databaseEnabled":false,"takesScreenshot":true,"networkConnectionEnabled":false,"app":"/Users/zhiyu.zhao/Desktop/appiumTest/sample...
[HTTP] <-- POST /wd/hub/session 200 59127 ms - 520
?Client發(fā)送建立Session請(qǐng)求->Server接受,打開(kāi)模擬器->安裝被測(cè)試APP->啟動(dòng)WDARunner->完成后Device返給Server Device Session id->Server返給Client 設(shè)備信息和本次Session id
5.ATX:AutomatorX
項(xiàng)目GITHUB?
特點(diǎn)
完全的黑盒測(cè)試框架,無(wú)需知道項(xiàng)目代碼,非侵入式
支持iOS, Android的自動(dòng)化測(cè)試,兩個(gè)平臺(tái)都支持測(cè)試第三方應(yīng)用
對(duì)于iOS的真機(jī),安卓模擬器都能很好的支持
可以用來(lái)測(cè)試Windows應(yīng)用
對(duì)于游戲的測(cè)試使用了圖像識(shí)別
同一個(gè)測(cè)試腳本可以通過(guò)圖像的縮放算法,適配到其他分辨率的手機(jī)上
主要特點(diǎn)集中在圖像識(shí)別上,通過(guò)圖像識(shí)別來(lái)尋找某控件和頁(yè)面狀態(tài)判斷的斷言。
6.最終目標(biāo)
小目標(biāo)3.0讓自動(dòng)化自動(dòng)起來(lái),也就是搭建云測(cè)試平臺(tái),實(shí)現(xiàn)設(shè)備和測(cè)試腳本分離、透明化。同一App的測(cè)試腳本可以由多個(gè)Client來(lái)編寫(xiě),然后由平臺(tái)合理分配設(shè)備資源來(lái)運(yùn)行這些測(cè)試腳本。而由于UI界面本身多變的特性,腳本的維護(hù)會(huì)比接口的自動(dòng)化測(cè)試成本高很多,所以最終目標(biāo)是在3.0的基礎(chǔ)上,在Client端加上屏幕錄制技術(shù),類似于Xcode的錄制操作生成代碼的功能。這樣就能夠建立起一整套維護(hù)成本低,自動(dòng)化程度高,拓展性好的自動(dòng)化測(cè)試平臺(tái)。
?
?