在软件工程中,非功能性需求(nonfunctional requirements,简称NFRs)与软件架构(software architectures,简称SAs)之间存在着紧密联系。早在1994年,Rick Kazman和Len Bass就肯定地说过,软件架构与实现非功能性需求之间存在密切联系。这一想法在
软件开发领域已经流行很多年,它也解释了为什么开发项目要在实现非功能性需求方面做大量投入。
当我们认识到软件架构的概念如何从简单的结构性表示演变为决策视角时,这个笼统的观点就显得更加具体了。 从决策角度来看,非功能性需求是对各种设计方案进行选择的标准。4 例如,从可维护性或可移植性方面考量,需要一种层次性架构风格;从效率方面考量,需要一种专门的
数据库技术。
软件架构师在执行软件架构设计任务时,必须连续不断地应对非功能性需求。他们必须了解系统有哪些非功能性需求,以及架构决策对实现这些非功能性需求的影响。 在本文中,我们将介绍一项实证研究,它揭示了软件架构师们在决策过程中应对非功能性需求的有关实践。这项研究以一个调研活动为基础,该调研活动由两部分组 成。首先,我们从工程角度对非功能性需求加以分析,尤其是与三类需求工程活动(获取、文档化和验证)的关系。然后,我们深入研究了非功能性需求是如何影响 架构决策的。
调研
我们针对同一个软件项目,多次组织了半结构化访谈(semi-structured interviews),访谈的对象都是参与过该项目的软件架构师。相对其他定性研究策略(如结构化问卷调查)而言,半结构化访谈更具灵活性,它使我们可 以更好地研究对话中出现的相关问题。另外,我们把讨论范围限定在单个软件项目以内,而不是考虑一般性的架构原则,这有助于我们更好地理解与评估背景信息。
访谈对象及所在机构
本调研涉及13位访谈对象,他们来自12家跨越不同业务与应用领域的软件密集型机构(见表1)。根据业务种类不同,这些机构可分为三类:
软件咨询公司,主要是为客户从事软件开发任务。
IT部门,为满足机构内部需求而从事或外包软件开发任务。
软件供应商,开发特定私有方案,并将其商品化。
本调研涉及的软件项目,其功能与大小也有差别。
尽管所有访谈对象都在各自项目中履行架构师职责,但他们的所在机构并没有专门设置软件架构师职位。相反,机构是根据技术知识或经验来为各个项目选择架构师的。除去一个例外,其他所有访谈对象都同时还兼任其他角色(如项目经理、顾问或开发者)。
访谈实施
我 们为访谈制作了一个访谈指南,并通过两位研究者和两位软件架构师对它进行了
测试,以确保有效。然后,我们把访谈指南预先发送给所有访谈对象,让他们有机会 熟悉访谈话题,并挑选一个用于访谈的项目。访谈是面对面进行的,每次访谈大约一小时。我们对访谈进行了录音,然后将它们转录为文本,以便进行分析。而后, 我们请访谈对象来验证转录内容。有时,我们会明确请求访谈对象澄清某些方面。我们使用了NVivo软件来评估收集到的数据。我们对所有语句和词语进行了归类,把描述相同想法、动作或属性的语句和词语归为一组。最后,我们根据机构和项目的特征来分析了数据。
局限性
我们了解我们的样本不是随机的,因此未必能够代表更广泛的软件开发全体。所以,为了试图缓解可能存在的偏差,我们让机构自己挑选访谈对象,并允许访谈对象自 己挑选项目。我们承认,访谈对象可能会倾向于选择较为成功的项目。为了缓和这一问题,我们向访谈对象说明,该项研究不用于分析最佳实践,只是想了解做事方 式。我们承诺为反馈内容保密。大部分机构是中小型机构,而且都来自西班牙。当然,调研结果可能受到上述因素的影响。此外,大部分都不是紧要领域的项目。不 过,由于我们试图通过这些项目来揭示工业界实践,而不是提出一般性理论,所以这不算重大弱点。
架构师如何应对非功能性需求
我们向软件架构师们提出了好几个具体的问题,关于他们如何获取并文档化非功能性需求,以及之后如何在系统中进行验证。我们认为,这对理解架构师在项目中进行决策制定的背景十分重要。关于这部分的详情,请参见我们的另一篇文章6。问题列表见下。由于我们实施的是半结构化访谈,因此这些问题只是作为指导,访谈是依据对话情况来推动的。关于需求获取、文档化和验证方面的话题自然而然地在对话中出现。
获取非功能性需求,由谁负责?
需求获取的目的是从涉众等处得到系统需求,并细化之。研究者和实践者都认同需求获取是需求工程中最具挑战的部分。致力于精确无歧义表达需求的技术有很多,如调研、创意研讨会等。
这些技术假定来自客户方面的涉众(最终用户、经理等)在需求获取方面将贡献很多。就功能性需求而言,一些访谈对象认同该假定。例如,访谈对象A说:“[业务分析师]编写一个详细的文档来反映所有[功能性]需求”。?
但是,该假定对非功能性需求来说并不成立。在我们的调研中,有10个项目,软件架构师是非功能性需求的主要来源。有些客户从未提到非功能性需求。访谈对象E 说:“[客户]从没提到过网页加载时间不能超过2秒这样的需求,但他后来却对此颇有抱怨。”访谈对象L2说:“客户提到一个基本的[非功能性需求],然后 我们根据自己的经验作了补充”。”
这一数值已经超过了Uwe van Heesch和Paris Avgeriou提到的架构师显著涉及需求获取的比例(60%)。7
只有访谈对象D、H、I的所在机构是由客户来领导非功能性需求获取的。有趣的是,也只有这几个机构的项目是外包的(管理方分别是一家航空工业公司、一家软件 公司和一家银行)。这一情况是由机构之间的从属关系造成的。然而,即便在这些案例中,架构师仍然在定义非功能性需求方面发挥着积极作用。访谈对象D说: “我们的客户是一个航空系统部门,所以所有非功能性需求都是良好定义的。另外,我们需要基于我们的经验再补充一些非功能性需求。?”
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
如何获取非功能性需求?
非功能性需求难以捉摸的特性,决定了不容易事先获取。根据这条一般性的看法,所有访谈对象都认同非功能性需求的获取是一个迭代的过程,需要跨越整个系统生命 周期。因为在达到一定重要阶段(通常是原型)之前,可能不太容易对系统的部分行为提出期望。访谈对象J称:“我们首先确定一些相关的非功能性需求,比如与 其他系统的兼容性等,然后开发一个原型,并分析其他候选方案。”?
此外,我们无法在第一次开发之前把非功能性需求考虑完全。他们需要纠正性维护, 以纠正未符合预期的不正确行为。访谈对象K说,“在效率方面,我们必须作出改变,因为在项目开始之时并没有就服务水平提出要求。”?这样是合理的。有些非 功能性需求(例如安全性方面)只有在目标环境中部署系统或意外发生时,才能进行全面检查。
如何档案化非功能性需求?
为了让档案化更加有效,学术界与标准化组织已经提出了许多用于编写系统需求规格说明书的表示法和模版。然而,13位访谈对象中有9位承认他们不对非功能性需 求进行档案化。访谈对象H说:“[功能性需求]是用UML、概念模型、用例来表示的,但没听说过非功能性需求。”一些访谈对象说,只有当客户需要,或者项 目属于紧要领域时,才有必要档案化。有四位访谈对象表示他们明确记录非功能性需求。访谈对象D的所在机构采用一种领域特定语言(domain- specific language)。“因为我们为航空领域工作,我们必须以可验证的方式来明确表达非功能性需求。我们有专门的模版,我们采用来自其他工程领域的不同技术 (如风险模型、故障树等)。”两位访谈对象表示,他们采用具有一定结构的自然语言来记录非功能性需求。访谈对象B采用Volere需求模版(它提供了一个 高度结构化的需求模版);访谈对象K采用符合ISO/IEC 9126质量模型的纯文本。
访谈对象J只采用纯文本文档。只有访谈对象B和 D是不断维护需求文档的;J和K只记录最初的非功能性需求。访谈对象K说:“起初,我们用自然语言记下一些关于非功能性需求的想法,... 不过之后,我们并没有跟踪它们,在设计过程中也没有出现新的非功能性需求。”人们似乎很自然地认为,可度量性与连续(或至少规律的)记录更新之间存在一定 关系。但要确认这种关系是否存在,需要做进一步研究。
所以我们可以看到,非功能性需求很多是不言而喻的,甚至是隐含的。把它们档案化,准 确性和及时性会受到严重损害。这种情况可以用成本和收益来解释。访谈对象C直率地说:“我几乎不对项目进行适当的档案化,主要是它耗费太多钱。”如果实践 者们无法从中感到益处,那么非功能性需求将继续保持难以捉摸的状态。
如何在系统中验证非功能性需求?
验证系统的行为 是否满足非功能性需求是有难度的。不同非功能性需求之间存在差异,因此相应的验证方法也有所不同。不过,有11位访谈对象说,所有非功能性需求都在项目中 得到了满足,尽管总有改进余地。然而,当我们问道如何针对非功能性需求进行验证时,他们的回答显得含糊。访谈对象D是这么说的:“对于一些[不是全部]非功能性需求,由于不容易测试,我们只是非正式地跟客户进行了讨论。“因此,我们有必要把自以为满足非功能性需求(正如访谈对象中的那11位(85%)所做 的)和真正的验证区分开来(访谈对象中有8位(61%)对某些类型的非功能性需求进行了验证)。(这与过去研究得出的60%是相称的。8)
八位访谈对象执行了一些非功能性需求的验证,不过仅限于一到三种。他们只考虑以下类型的非功能性需求。
性能效率。访谈对象H说:“我们通过负载和压力测试来进行性能评估。”?
正确性。访谈对象A说:“我们每编码一小时,就投入一小时来测试。”?
易用性。访谈对象K说:“我们制作了一个原型,确保客户对用户界面满意。”?
可靠性。访谈对象J说:“我们强行引入一些错误,看看系统会发生什么,会不会丢失数据等。”?
安全性,作为十分重要的一类非功能性需求,所有访谈对象都没有提到。访谈对象F描述了一个极端的不作验证的例子:“我们等客户来抱怨,他们会发现问题的。” 尽管这是个不令人满意的回复,但它再次反映了这点(和前面提到的档案化一样):出于预算和时间上考虑,工程实践可能没法按照理想的方式进行。
与之形成鲜明对比的是,访谈对象D采用基于统计分析和模拟的形式化方法来检查系统的可靠性。当然,这是预料之中的,因为他们的项目涉及到航天工业中的信息系统,属于紧要领域。过去有研究发现,评估方法与评估目标有关。9 我们的发现与之不谋而合。
我们有一个可能与前人研究结果一致的发现,即档案化与验证之间的联系。如Andreas Borg及其同事所说的那样,“如果用不可度量的词语来表达需求,那么测试会很消耗时间,甚至根本无法测试。”10仅有两位访谈对象采用了可度量的方式来表达非功能性需求,这可能是验证水平整体较低的原因之一。
非功能性需求如何影响架构决策
毫无意外,所有访谈对象都认同:非功能性需求会影响他们的决策。但是他们的具体回答反映出了一些细微差别。
决策类型
非功能性需求影响着四类决策。
架构模式
对于给定类型的项目,大部分访谈对象会很自然地选择层次架构,尽管他们中有些人明确给出了决策理由。访谈对象J说:“我们采用层次架构,因为它允许以后变化。”?
实现策略
有些类型的需求可能需要具体的架构级策略。它可以是一般性的设计决策(比如访谈对象L1说“我们采用单点登录,以增强子系统的集成性”),也可以是有关个别组件的具体决策(比如访谈对象A说“我们为数据库表建立副本,因为访问时间过长”)。?
横向决策
有 些非功能性需求会影响到整体架构。访谈对象L1说,“我们更倾向于采用我们已经掌握的技术。”一个反复出现的问题是,第三方组件尤其是开源软件(open source software,OSS)的使用。访谈对象D说,“出于可维护性考虑,我们希望能够获得源代码,所以我们选择了开源软件方案。”?
技术平台
非功能性需求也许可以通过选择正确的数据库或中间件等来满足。在这种情况下,它们可能是影响整个系统的。访谈对象K说:“我们需要高可用性 (availability),而只有Oracle能够保证这一需求。”非功能性需求也可能是局部的。访谈对象H说:“有一个查询是直接通过 JDBC(Joint Database Connectivity)实现的,由于效率原因,所以没有采用Hibernate。”?
不同的决策制定过程
我 们在本次调研中发现了一个关于决策制定的特别方面,即技术决策与其他决策的交织。我们听到三种不同的反馈。有四位访谈对象表示,非技术性决策优先。访谈对 象C说:“架构师应该在之前设计好的逻辑结构上,选用合适的技术。”另外四位访谈对象说,重大技术决策优先,之后的决策应该与之配合。访谈对象H说:“客 户给我们设了一些限制,比如,架构必须基于开源软件(OSS)和Java。”而其他五位访谈对象认为,技术决策和其他决策是交叉并彼此影响的,可以看成是 一种架构设计层面上的局部双峰模型。11
影响程度
我们询问访谈对象在进行架构决策时会考虑哪些非功能性需求。我们以ISO/IEC 25000质量标准为统一框架,将他们的回答汇总如下。
明确性(Explicitness)
很明显,架构师们期望一定的非功能性需求,即便还没有将它们作为需求明确列出。访谈对象I说:“我不会考虑一个不安全的系统。”由于所采用技术与平台的当前 特性,这些不言而喻的非功能性需求经常浮现在架构师的脑海里。访谈对象E说:“我们不会去考虑文档的安全性,因为它是由SharePoint管理系统负责 的。”?
来源(Source)
有些需求直接来自开发团队或架构师。访谈对象B说:“未来要维护这个系统的人是我们, 所以,确保它的可维护性对我们来说是很重要的。”相对于来自客户的非功能性需求,这些来自开发团队的非功能性需求与架构决策过程更加接近,因为技术人员从 解决方案的角度去思考,而客户的思考角度是面向问题的。
非技术性(Nontechnicality)
非技术性的非功 能性需求(NFRs)指那些不与软件内在质量直接相关、而是与系统环境有关的的需求,比如许可证或成本等。12架构师要考虑这些基本因素;访谈对象们表 示,所有非功能性需求中有大约40%属于非技术性的。有时,他们会以最高优先级来考虑这些需求。访谈对象J称:“成本是第一位的,所有别的都得服从 它。”?
重要性(Importance)
我们询问访谈对象哪种类型的非功能性需求是最为重要的。许可证问题、易用 性、可靠性、性能效率,以及可维护性是被提到最多的。而只有两位访谈对象提到了可移植性。我们将该信息与访谈对象在面谈中提到的决策案例进行了交叉检查; 我们发现,性能效率和可维护性对决策的影响最大。
术语问题(Terminology issues)
在与访谈对象讨 论非功能性需求时,我们碰到一些术语上的问题。有些访谈对象请求对术语进行补充解释,比如“可用性(availability)”和“准确性 (accuracy)”。其他的访谈对象会在给定上下文中错误地使用术语,比如用“人体工学”来表达“易用性”。有些访谈对象甚至采用错误的定义,比如 “可维护性(maintainability)是十分重要的,因为我们不能对运转中的系统进行修改。”另一个常见的问题是混淆使用“性能 (performance)”与“效率(efficiency)”。ISO/IEC 25000将性能效率定义为“一定条件下相对于所用资源数量的性能”。?”13 该定义有助于我们解除混淆。
为了检查研究中的观察结果是否有效,我们与一些大型IT企业展开了一项新的研究。我们期望在文档化和验证上看到改善,并且有可能的话,在各种非功能性需求的重 视程度上有所变化。我们还想研究,如果把非功能性需求与架构决策之间的关系明确表达出来(比如,考虑了哪些权衡,放弃了哪些选择等等)的话,将对最终的系 统架构决策有何影响。关于本课题的相关研究,请见下方。
致谢
我们非常感谢参加本课题的参与者,感谢他们的时间和贡献。本课题获得西班牙项目TIN2010-19130-C02-01的资助。
本文由《IEEE Software》杂志首发,现在由InfoQ和IEEE Computer Society联合向您呈现。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
Selenium2library在我们实际测试
web页面的时候基本上已经够用了,不过还是会有部分情况下会脱离Selenium2library的控制,无法进行操作。比如说下载文件的时候,要选择保存文件在什么地方,比如说上传文件的时候,要选择上传哪个文件,这些在Selenium2library下都没有很好的处理办法。但是结合上AutoItLibrary,就可以很好的来进行处理了。结合AutoItLibrary的内容分2篇,本篇介绍AutoItLibrary安装使用和对话框处理,下篇介绍上传下载。
下载解压缩后直接用ride打开里面的tests看代码或者运行案例即可。
1、AutoItLibrary安装
简单说下安装,把下面2个下载了,先安装pywin32,然后再安装AutoItLibrary,解压缩进入相应目录执行
python setup.py install
pywin32-217.win32-py2.7.exe(我之前下载的217,最新的好像是218,版本较多,请注意py版本)
AutoItLibrary-1.1.tar.gz(必须先安装上面的pywin32,并且Python的安装目录不能有空格,如果有空格会导致注册autoit的dll时出错。版本一直是1.1)
64位的机器:除了安装上面2个之外,还不得不再安装一个AutoItV3。一般情况下装完这个就能用了。
2、AutoItLibrary对象识别
当成功安装AutoItLibrary之后,在你的硬盘某个盘根目录会多一个Robotframework的目录,具体哪个盘取决于你的User目录在哪个盘,例如我的是在D盘,因此多出来的这个目录就在如下路径:
D:\RobotFramework\Extensions\AutoItLibrary
这里是一些辅助工具,比如AutoItX.chm是帮助文档,AutoItLibrary.html是
测试库的关键字文档说明,Au3Info.exe是最重要的识别对象的工具了。
在Finder Tool的位置有个十字星,可以用鼠标拖动他到你需要识别的对象上,就像下图这样:
AutoItLibrary的对象操作大体上有几大主要部分,Window操作、Control操作、Mouse操作、Process操作、Run操作、Reg操作还有一些其他的操作。
其中前三个操作我比较常用,Window和Control应该比较好理解吧,你看到的窗口就是Window,窗口上的按钮、文本框等就是Control。所以在通常要去操作Control时,一般需要先激活窗口,再操作控件。
AutoItLibrary的鼠标操作要用到真实坐标,这和Selenium2Library里的坐标略有差异,下篇会有例子。
回到上图,可以看到最重要识别出来的属性,分两块,在左侧上半部分,Basic Window Info和Basic Control Info。
经过我多次的使用,Window方面识别用Title比较多,Control主要用controlID,controlID就是在Basic Control Info里的Class+Instance,比如说图中这个对象,他的controlID就是Edit1,关键字里的strControl就是controlID(chm里都是写的controlID)。
AutoItLibrary的关键字我就不一一介绍了,大家可以看Chm帮助或者html的关键字文档,不过chm是原生AutoIt的文档,对于理解关键字的作用比较有帮助。关键字文档只是列出来所有的关键字和参数,基本很少有说明。
3、web对话框
a、你肯定见过这种对话框,前一个是只有确定的,还有确定取消2个按钮的。
b、你应该也见过这种对话框
c、还有那种在网页上弹出的要输入用户密码的登录框,我这里没有找到例子,也木有截图。(找到截图,见最底下)
以上这些都可以用AutoItLibrary来处理。
对于a来说,Selenium2Library中的confirm action就可以处理了。
对于b、c来说,都要用AutoItLibrary处理更好一些,因为那些文本框的输入已经脱离了Selenium2Library的控制了。
先来看a这种对话框在Selenium2Library的处理,脚本如下:
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
1、真机调试打开USB调试模式
2、启动脚本提示apk包Could not make a string,是释放string.json出错,由于apk损坏导致,验证是安装到真机上开启APP
3、Activity要写对,否则提示不存在Activity,建议写完整名称,完整包名类似com.xxx.xxx.Activity;启动Activity要写对,否则提示XXX never XXX。包名参数与Activity参数可以在AndroidManifest.xml(获取方法http://code.google.com/p/android-apktool/)中查看,包名:<manifest
android:versionCode="12" android:versionName="2.6.0.0.0" package="com.xxx.xxx",一般位于XML定义的下一行,启动Activity在这里看,带有LAUNCHER关键字<activity android:theme="@*android:style/Theme.NoTitleBar" android:label="@string/app_name"
android:name="com.xxx.xxx.SplashActivity" android:launchMode="singleTop" android:screenOrientation="portrait" ,本例中是com.xxx.xxx.SplashActivity
4、
Appium支持一个Webdriver元素定位方法的子集
find by "tag name" (i.e., 通过UI的控件类型)
find by "name" (i.e., 通过元素的文本, 标签, 或者开发同学添加的id标示, 比如accessibilityIdentifier)
find by "xpath" (i.e., 具有一定约束的路径抽象标示, 基于XPath方式)
5、Appium 在 Mac OS X 上安装使用文档,参考:http://testerhome.com/topics/166,
Windows平台,参考:http://testerhome.com/topics/155,
Linux平台,参考:http://testerhome.com/topics/160,Android平台,参考:http://testerhome.com/topics/153
6、iOS模拟器—>硬件—>设备—>iPhone
7、【坑】Appium在MacOS10.9以及iOS7上面的问题:启动appium脚本没有问题。安装好应用之后log中会报出500,同时instruments会显示simulator session timeout。
8、生成build/Test.appa的方法,进入到目录下面编译
xcodebuild -sdk iphonesimulator6.0
9、安装路径问题
全局路径,也就是带上参数 -g 的安装模式。这个命令会把模块安装在 $PREFIX/lib/node_modules 下,可通过命令 npm root -g 查看全局模块的安装目录。 package.json 里定义的bin会安装到 $PREFIX/bin 目录下,如果模块带有 man page 会安装到 $PREFIX/share/man 目录下。
本地路径,不带 -g 参数的。从当前目录一直查找到根目录/下有没有 node_modules 目录,有模块安装到这个目录下的 node_modules 目录里,如果没有找到则把模块安装到当前目录 node_modules 目录下。package.josn 定义的 bin 会安装到 node_modules/.bin 目录下,man page 则不会安装。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
1、如果需要加入一个一个的类
public static void main(String args[]){ tng.SetTestClasses(new Class[]{MyTest.class}) //这里可以加多个类。 tng.run(); } |
public static void main(String args[]){ TestNG tng = new TestNG(); RetryTestListener rtl = new RetryTestListener(); XmlSuite xs = new XmlSuite(); Parser parser = new Parser("./testxml/temp.xml"); List<XmlSuite> suites = new ArrayList<XmlSuite>(); try { suites = parser.parseToList(); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }; tng.setXmlSuites(suites); tng.addListener(rtl); tng.run(); } |
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
一、什么是同步点
同步点是指在一个
测试过程中,指示QuickTest等待应用程序中某个特定过程运行完成以后再运行下一步操作。
Waits until the specified object property achieves the specified value or exceeds the specified timeout before continuing to the next step.
测试过程中,如果需要指定QuickTest暂停运行一个测试或组件,直到特定的对象属性存在后才开始运行下一步,那么可以插入同步点来实现。例如以下几种情况:
判断进度条是否已经100%完成。
判断某一状态消息的出现。
等待某按钮状态变为可用。
一个操作后,弹出一个消息对话框。
等待窗口打开并提交数据。
二、同步点方法
默认等待时间
Sync方法;
Wait方法;
WaitProperty方法;
Exist方法;
2.1 默认等待时间
1)File>>>Settings>>>Run>>>Object synchronization timeout:QTP默认对象识别同步时间为20S,可以手工更改。
2)File>>>Settings>>>Web>>>Browser navigation timeout:Web插件对于Web浏览器对象的默认同步时间为60s,可以手工更改。
2.2 Sync
Syntax
object.Sync
Example
Browser("Mercury Tours").Sync '等待IE加载完成
Browser("Mercury Tours").Page("Mercury Tours").Sync '等待页面加载完成
Description
Sync方法等待浏览器或页面加载完成后才进行下一步操作,Sync方法只能在WEB中使用,操作对象只有Browser(浏览器对象)和Page(页面对象)。
注意:虽然Sync方法会使
QTP等待到页面加载完成后,但无法判断页面是否加载成功,如果需要判断页面加载是否成功,可以通过判断页面中对象visible的属性值。
Browser("
Google").Page("Google").WebEdit("q").GetROProperty("visible")=true
2.3 Wait方法
Syntax
object.WaitProperty (PropertyName, PropertyValue, [TimeOut])
Example
Wait 10 或Wait(10)
Description
wait方法可设定指定的等待时间,时间单位为秒,但这个时间只能是固定的,即必须等到这个时间才能继续执行。
注意:死等待有时候会浪费时间,有时候会因设定时间过短导致找不到对象。
2.4 WaitProperty
Syntax
object.WaitProperty (PropertyName, PropertyValue, [TimeOut])
Example
windows("XXX").dialog("XXXXXXXX").waitProperty "visible",true,50000
Description
WaitProperty方法是指当指定的属性出现后或是指定时间后指定的属性还未出现,再进行下一步操作。
方法中的visible是属性,true是属性的值,50000为最长等待时间,单位为毫秒。即在最长等待时间内任意时刻visible的值为true了,脚本继续向下执行,否则直到等到最大等待时间,然后给出waring。
注意:
1)如果超出最大等待时间,QTP报告中的结果是warning,而不是fail。
2)该方法适用于除WinMenu对象(菜单对象)以外的所有标准Windows对象
2.5 Exist
Syntax
object.Exist([TimeOut])
Example
windows("XXX").dialog("XXXXXXXX").Exist(10)
Description
方法中的10的时间单位为秒。该方法与waitproperty方法类似,当程序执行到该语句时会去检查对象是否存在,若存在返回true,进入下一步;若10s内检查对象一直不存在返回flase,一般用于if语言中比较多。
如果设置超时时间为0,如object.Exist 0,那么QTP不会等待,而是直接返回查找的结果(True或False)。
如果未设置超时时间,如object.Exist,那么超时时间为QTP默认的同步时间
学习心得:学习中遇到问题,不要急着四处询问,尝试使用自带的操作手册,往往有意外的收获,看看下面
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
1. 在app/etc/local.xml 中,添加新的
数据库选项
<?xml version="1.0"?> <config> <global> <install> <date><![CDATA[Tue, 05 Jul 2011 03:23:52 +0000]]></date> </install> <crypt> <key><![CDATA[80eb4be66ce28df745f27c75f2604d33]]></key> </crypt> <disable_local_modules>false</disable_local_modules> <resources> <db> <table_prefix><![CDATA[]]></table_prefix> </db> <default_setup> <connection> <host><![CDATA[localhost]]></host> <username><![CDATA[root]]></username> <password><![CDATA[]]></password> <dbname><![CDATA[hello]]></dbname> <active>1</active> </connection> </default_setup> <vip_space_read> <connection> <host><![CDATA[localhost]]></host> <username><![CDATA[root]]></username> <password><![CDATA[]]></password> <dbname><![CDATA[hello_dev_test]]></dbname> <model>mysql4</model> <initStatements>SET NAMES utf8</initStatements> <type>pdo_mysql</type> <active>1</active> </connection> </vip_space_read> </resources> <session_save><![CDATA[files]]></session_save> </global> <admin> <routers> <adminhtml> <args> <frontName><![CDATA[hello_admin]]></frontName> </args> </adminhtml> </routers> </admin> </config> |
2. 在需要使用的不同数据库的model resource中,重写 _setResource 方法,例如
class Hello_Vip_Model_Entity_Vip_Adapter extends Mage_Core_Model_Mysql4_Abstract { protected $_logFile = 'vip.adapter.log'; protected function _construct() { $this->_setResource(array('read' =>'vip_space_read', 'write' =>'vip_space_read')); } |
经过以上两步,就能在某个model中使用不同的数据库
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
我把之前的一些学习经验和方法跟大家分享下,希望对大家有所帮助: 一、玩好
Linux一定要经常折腾,说白了,就是动手能力一定要强。我初学Linux那块,家里3台电脑,我在上面经常反反复复的做kickstart、网络ghost、双系统安装的实验。有很长一段时间,我还在其中的一台老式笔记本上安装了Ubuntu系统,通过它来游览网页和看视频,解决各种驱动问题,通过这些折腾,对Linux也是越来越有兴趣,学习的劲头也越来越足了。
二、床边经常放几本书,临睡觉前或无聊时经常翻一翻,我个人的感觉是夜深人静的时候印象非常深刻,很多知识点很容易就记住了。
三、我习惯手边放一个小本,初学的一些Linux操作单词我会写在上面,详细用法也会记载,等人或吃饭的时候我会拿来翻一翻,这样感觉掌握得特别快。对英文头疼的同学建议坚持看中英文字幕的美剧,比如现在流行的《
生活大爆炸》、《傲骨贤妻》、《权力的游戏》等等,相信英文不会成为学习的阻碍了。
四、实验过程中的排障一定要注意出错的原因,比如我近期发现自己PXE安装的实验机器,老是带了一个ifcfg_eth0.bak文件,后来经过仔细分析,发现是由于我的机器是Kickstart安装,分配的MAC跟原来机器不一致,机器重启service服务以后就自动的添加了一个ifcfg_eth0.bak文件,知道故障的原因以后就好办了。
工作中遇到的问题,也应该反反复复排查,千万不要在没搞清出错原因的前提下胡乱猜测,这样的效果是非常糟糕的。大家可以看下有问题的网卡文件,下面分配的MAC地址实际跟系统网卡自身的MAC地址并不是相匹配的,如下所示:
[root@localhost network-scripts]# cat ifcfg-eth0.bak # Realtek Semiconductor Co., Ltd. RTL8111/8168B PCI Express Gigabit Ethernet controller DEVICE=eth0 BOOTPROTO=none HWADDR=fe:ff:ff:ff:ff:ff ONBOOT=yes NETMASK=255.255.255.0 IPADDR=192.168.1.120 GATEWAY=192.168.1.1 TYPE=Ethernet |
而实际的网卡MAC地址我们用ifconfig eth0可以查看得到,这个跟上面所列的网卡MAC确实是不一样的,如下所示:
[root@localhost ~]# ifconfig eth0
eth0 Link encap:Ethernet HWaddr 90:2B:34:87:F3:CD
五、如果遇到复杂的问题或是自己想了很久也没有答案的知识点,建议可以去看一下别人的博客,学习别人的实验和心得体会,再融会贯通,吸收了就成了自己的。现在技术论坛的活跃度不高,但很人个人技术含金量还是很高的。这里建议大家一定要做好相关的知识难点的笔记,好记性不如烂笔头,一个一个小知识,长期坚持下去就是一个很可观的数值了。
六、实践出真知,在阅读别人的技术
文章或著作时,我也发现了不少错误之处,这时候千万不要相信所谓的权威(笔者手上正在阅读的一本国外专家著作中就存在着不少问题),相信自己的实验结果,一切以其为判断依据。
七、遇到新技术或疑难问题,先实验,再原理,不明白这点的同学先按照我的这种方法试一试,慢慢就明白了。
这些方法贵在坚持,持之以恒的话,肯定是有收获的。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
Android SDK 1.5已经将
JUnit包含进来了,重新用的时候还出了一点问题,还是决定写一篇比较详细的
文章,供大家和自己以后使用,写起来也挺方便的,Android下的Junit是对
java下的junit的扩展,殊途同归,基本类似~
Junit简介
JUnit是 一个开源的java单元
测试框架。在1997年,由 Erich Gamma 和 Kent Beck 开发完成。这两个牛人中 Erich Gamma 是 GOF 四人帮之一;Kent Beck 是 XP (Extreme Programming)极限编程创始人(不是Window XP)。俗话说“麻雀虽小,五脏俱全。” JUnit设计的非常小巧,但是功能却非常强大。Junit在TDD(
Test Driven Development)测试驱动开发中非常常 用,junit是设计比较好的测试框架,Android对junit进行了扩展,使其使用起来更方便省心
JUnit的一些特性:
1) 提供的API可以让你写出测试结果明确的可重用
单元测试用例
2) 提供了三种方式来显示你的测试结果,而且还可以扩展
3) 提供了单元测试用例成批运行的功能
4) 超轻量级而且使用简单,没有商业性的欺骗和无用的向导
5) 整个框架设计良好,易扩展
Android Junit Demo
首先GoogleJunit项目,然后新建一个Test Case:
publicclassBookCaseextendsAndroidTestCase {
publicvoid test(){
Log.i("BookCase","测试");
}
}
AndroidTestCase其实本身就是继承自TestCase,如果这样运行是没法运行的,需要到AndroidManifest.xml配置一下:
配置完这个之后还需要application配置一下uses-library:
最后一步就是测试了,右键方法Run AS=>Android Junit Test,结果如下:
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
说明:由于条件有限,我这里使用的是同一台centos的,但教程内容基本上通用。
1.编译安装git git安装教程
2.安装gitosis
$ yum install python python-setuptools
$ git clone git://github.com/res0nat0r/gitosis.git
$ cd gitosis
$ python setup.py install
2.在开发机器上生成公共密钥(用来初始化gitosis)
$ ssh-keygen -t rsa #不需要密码,一路回车就行(在本地操作)
$ scp ~/.ssh/id_rsa.pub root@xxx:/tmp/ # 上传你的ssh public key到服务器
3.初始化gitosis[服务器端]
$ adduser git # 新增一个git用户(先添加用户组 groupadd git)
$ su git # 切换倒git用户下
$ gitosis-init < /tmp/id_rsa.pub # id_rsa.pub是刚刚传过来的,注意放在/tmp目录主要是因为此目录权限所有人都有定权限的
$ rm /tmp/id_rsa.pub # id_rsa.pub已经无用,可删除.
4.获取并配置gitosis-admin [客户端]
$ git clone git@xxx:gitosis-admin.git # 切换到root用户并在本地执行,获取gitosis管理项目,将会产生一个gitosis-admin的目录,里面有配置文件gitosis.conf和一个 keydir 的目录,keydir目录主要存放git用户名
$ vi gitosis-admin/gitosis.conf # 编辑gitosis-admin配置文件
如果无法git clone的话,可以使用git clone git@xxx:/home/git/repositories/gitosis-admin.git
# 在gitosis.conf底部增加
[group 组名]
writable = 项目名
members = 用户 # 这里的用户名字 要和 keydir下的文件名字相一致
# VI下按ZZ(大写)两次会执行自动保存并退出,完成后执行
$ cd gitosis-admin
$ git add .
$ git commit -a -m “xxx xx” # 要记住的是,如果每次添加新文件必须执行git add .,或者git add filename,如果没有新加文件,只是进行修改的话就可以执行此句。
# 修改了文件以后一定要PUSH到服务器,否则不会生效。
$ git push
如果在git push的时候,遇到错误“ddress 192.168.0.77 maps to bogon, but this does not map back to the address - POSSIBLE BREAK-IN ATTEMPT!”,解决为修改/etc/hosts文件,将ip地址与主机名对应关系写进去就可以了。
注意:这里我们并没有进行任何的修改的,现在只有一个管理git的项目。下面的为新添加项目的配置,大家经常用到的也就是下面的操作的。
新建项目
到此步就算完成gitosis的初始化了。接下来的是新建一个新项目到服务器的操作,如第5步中配置gitosis.conf文件添加的是
[group project1] # 组名称
writable = project1 # 项目名称
members = xxx # 用户名xxx一定要与客户端使用的用户名完全一样,否则无权限操作
$ git commit -a -m “添加新项目project1,新项目的目录是project1,该项目的成员是xxx“ # “”里的内容自定
$ git push
将新创建的项目提交到git server 上进行登记。以便客户可以操作新项目.
# 在客户端创建项目目录(客户端,当前用户为 XXX )
现在回到开发者客户端,上面创建了一个新项目project1并提交到了git server 。我们这里就创建此项目的信息.注意 项目名称 project1要与gitosis.conf文件配置一致,
$ mkdir /home/用户/project1
$ cd /home/用户/project1
$ git init
$ git add . # 新增文件 留意后面有一个点
$ git commit -a -m “初始化项目project1″
# 然后就到把这个项目放到git server服务器上去.
$ git remote add origin git@xxx:project1.git # xxx为服务器地址
$ git push origin master
# 也可以把上面的两步合成一步
$ git push git@xxx:project1.git master
说明:如果在执行 git push origin master 的时候,提示以下错误: error: src refspec master does not match any. error: failed to push some refs to 'git@192.168.0.77:pro2.git' 这是由于项目为空的原因,我们在项目目录里新创建一个文件。经过->add -> commit -> push 就可以解决了
$ touch a.txt
$ git add a.txt
$ git commit -a -m 'add a.txt'
$ git push
------------------------------------------------------------------------------------------------ 如果在git clone的时候遇到“
error: cannot run ssh: No such file or directory - cygwin git
”错误,则表示本机没有安装ssh命令。安装方法请参考:http://blog.haohtml.com/archives/13313 有时候我们要更换电脑来重新开发项目。这个时候,只需要将id_rsa私钥放在home目录里的.ssh目录里就可以了。(有时候一个人开发多个项目,这时候可能会提示id_rsa文件已经存在。不太清楚这里如何解决???) 续篇:git下添加新项目及用户
====================================================
三、常见问题
首先确定 /home/git/repositories/gitosis-admin.git/hooks/post-update 为可执行即属性为 0755
1. git操作需要输入密码
原因
公密未找到
解决
上传id_rsa.pub到keydir并改为'gitosis帐号.pub'形式,如miao.pub。扩展名.pub不可省略
2. ERROR:gitosis.serve.main:Repository read access denied
原因
gitosis.conf中的members与keydir中的用户名不一致,如gitosis中的members = foo@bar,但keydir中的公密名却叫foo.pub
解决
使keydir的名称与gitosis中members所指的名称一致。 改为members = foo 或 公密名称改为foo@bar.pub
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters