发布新日志

  • 软件错误跟踪处理流程(转)

    2010-03-01 15:24:22

    看到一篇软件错误跟踪处理流程,虽然关于错误跟踪处理的文章很多,而且本人也做了一段项目群的问题管理工作,感触还是很多,尤其是在流程复杂性方面的体会颇多,有时间的话也考虑把自己的感受记录下来。相比自己参与的问题管理,这篇的流程处理还不是很复杂,毕竟项目和项目群还是有一定的区别。这里仍将该文记录下来,吸取其精华,盼能进步。
     
    软件错误跟踪处理流程
    文章出处:本地化世界网 作者:崔启亮 发布时间:2006-01-16

        大型本地化软件测试需要进行充分的测试准备,需要科学的测试流程管理。为了跟踪和控制测试质量,便于管理测试发现的Bug,需要为每一个测试项目配置一个专用缺陷跟踪数据库,以便报告、查询、分类、跟踪、处理和验证错误。

      为了保证发现和报告的错误质量,需要首先由经验丰富的测试人员,在缺陷跟踪数据库中对新发现的错误进行确认,如果确实属于错误,再由错误修复工程师进行修复处理。

      1、软件错误的状态

    • 新错误(New):测试中新报告的软件缺陷。
    • 更多新信息(New More Info):错误修复工程师认为报告的错误信息不完整,要求错误报告者添加更准确的错误信息。
    • 打开 (Open):错误被确认并分配给相关错误修复工程师处理。
    • 拒绝(Declined):拒绝修改缺陷。包括两种情况:
      • 拒绝-不是错误(Declined-Not Bug):报告的错误不术语错误。
      • 拒绝-重复(Declined-Duplicated):以前已经报告过这个错误,需要指出已经报告过的错误标识编号。
    • 修正(Fixed):错误修复工程师已完成修正,等待测试人员验证。
    • 重新打开(Reopen):没有正确修复的错误,需要进一步修复。
    • 延期(Deferred):不在当前版本修复的错误,以后的版本修复。包括两种情况:
      • 延期-下个版本(Deferred –Next Build):本项目的下一个新版本修复。
      • 延期-下个主要版本(Deferred –Next Main Release):本项目不修复,本软件下一个项目的版本修复。
    • 关闭(Closed):错误已被修复。

      2、Bug管理的一般流程

      测试人员提交新的错误入库,错误状态为New。

      高级测试人员验证错误,如果是重复报告的错误,则设置为Declined-Duplicated状态,并指出与哪个已经报个错误重复(注明标识编号ID#)。否则,如果确认是错误,分配给相应的修复工程师,设置状态为Open。如果不是错误,则拒绝,设置为Declined-Not Bug状态。

      错误修复工程师查询状态为Open的错误,如果因为错误的信息不完全,没法重现错误,则设置状态为New More Info;如果不是错误,则设置状态为Declined-Not Bug;如果是错误则修复,设置状态为Fixed。对于当前版本不能解决,准备本项目的下一个新版本处理的错误,要留下处理注释,设置错误为Deferred –Next Build状态。如果只能在软件的下个新项目才能解决,要留下处理注释,设置错误为Deferred –Next Main Release状态。

      对于不能解决和延期解决的错误,不能由软件修复工程师自己决定,一般要通过某种会议(评审会)通过才能认可。

      测试人员查询状态为Fixed的错误,然后验证错误是否已修复,如果已经修复,设置错误的状态为Closed,如没有解决置状态为Reopen。

      下面以一个错误的处理过程为例,给出一般的处理流程图。

      3、软件错误流程管理要点

    • 为了保证错误的正确性,需要有丰富测试经验的测试人员验证和确认发现的错误是否是真正的错误,测试步骤是否准确、简洁、可以重复。
    • 软件错误的确认并不总是轻而易举的事情。由于对软件设计具体要求的不了解,对测试报告的个别软件错误,可能无法确认是否属于真正的软件错误,本地化服务商需要与软件供应商交流并确认。
    • 每次对错误的处理都要保留处理信息,包括处理者姓名,时间,处理方法,处理步骤,错误状态,处理注释等。
    • 对错误的拒绝不能由程序员单方面决定,应该由项目经理,测试经理和设计经理共同决定。
    • 对错误延期处理不能由本地户服务商决定,应该由软件供应商决定。
    • 错误修复后必须由报告错误的测试人员验证后,确认已经修复,才能关闭错误。
  • 在QTP中使用描述性编程(实例)

    2008-03-20 14:51:57

     
     
    在QTP中使用描述性编程是一个提高QTP脚本利用率的很好的方式。
    通常QTP是通过对象库来识别不同的对象,而描述性编程是QTP另外一种能够识别对象的途径,它不依赖于对象库,通过增加一些对象的描述来识别对象的。
     
    说明:本例子是以Flight飞机订票系统的登陆界面为测试页面进行描述的。
     
    步骤一:录制脚本
    Dialog("Login").WinEdit("Agent Name:").Set "Holly"
    Dialog("Login").WinEdit("Password:").SetSecure "46ef0dc7efe5834c73673898279af1204fea51a7"
    Dialog("Login").WinButton("Cancel").Click
    共录制3步操作,输入Agent Name, Password, 点击Cancel按钮
     
    步骤二:初级描述性编程
    Dialog("Regexpwndtitle:=Login").WinEdit("Attached text:=Agent Name:").Set "Holly"
    Dialog("Regexpwndtitle:=Login").WinEdit("Attached text:=Password:").Set “Mercury”
    Dialog("Regexpwndtitle:=Login").WinButton("Class Name:=WinButton", "text:=Cancel").Click
    在这里要注意有三点:
    1)如果需要两个以上特性来描述一个对象,需要使用逗号(,)对描述性语言进行分割
    2)使用:=来连接属性和属性值,并且:=两边不能有空格
    3)使用SPY查看对象的属性名和属性值(Tools -> Object Spy)
     
    步骤三:描述性编程提高
    Dim descEditLogin
    Set descEditLogin = Descrīption.Create()
    descEditLogin("Class Name").Value = "Dialog"
    descEditLogin("Regexpwndtitle").Value = "Login"
     
    Dialog(descEditLogin).WinEdit("Attached text:=Agent Name:").Set "Holly"
    Dialog(descEditLogin).WinEdit("Attached text:=Password:").Set "Mercury"
    Dialog(descEditLogin).WinButton("Class Name:=WinButton", "text:=Cancel").Click
    在这里需要注意有两点:
    1)把经常使用到的对象定义为一个对象变量,方便以后调用,减少代码工作量和错误
    2)使用SPY获取对象的属性和属性值
     
    步骤四:使用自定义的环境变量
    在File>>Settings>>Environment中选择user-defined,增加一个变量
    dlgLogin = “Login”
     
    这样脚本可以被修改为:
    Dim descEditLogin
    Set descEditLogin = Descrīption.Create()
    descEditLogin("Class Name").Value = "Dialog"
    descEditLogin("Regexpwndtitle").Value = Environment.Value("dlgLogin")
     
    Dialog(descEditLogin).WinEdit("Attached text:=Agent Name:").Set "Holly"
    Dialog(descEditLogin).WinEdit("Attached text:=Password:").Set "Mercury"
    Dialog(descEditLogin).WinButton("Class Name:=WinButton", "text:=Cancel").Click
    当然,参数化的方式很多,这边介绍的是使用环境变量
     
    步骤五:从XML文件导入环境变量
    <Enviroment>
           <Variable>
                  <Name>dlgLogin</Name>
                  <Value>Login</Value>
           </Variable>
    </Environment>
    可以使用手工导入,也可以使用LoadFromFile自动导入
     
    总结:
    优点是当对象的一些属性变更后,脚本更容易维护。
    比如说对于一个通用对象,比如save, reset, cancel等按钮,一个页面有3个,30个页面就有90个对象,
    假如save变成保存,reset变成重置,cancel变成取消,那么对象库就会产生很大的变动。
    而使用了描述性编程只需要在导入的XML文件中修改一个值就可以了。
    当然描述性编程的作用远远不止这些,这次只是抛砖引玉,希望大家共同进步。
  • GetROProperty,GetTOProperties,GetTOProperty的区别

    2008-03-20 14:44:58

    一、QTP识别对象的原理(by yabest, http://yabest.net

    QTP里的对象有两个概念,一个是Test Object(简称TO),一个是Runtime Object(简称RO)。
    这两个概念从字面上不大好理解,也容易混淆。
    但从实际作用上来看,应该说TO就是是仓库文件里定义的仓库对象,RO是被测试软件的实际对象。

    QTP识别对象,一般是要求先在对象仓库文件里定义仓库对象,里面存有实际对象的特征属性的值。
    然后在运行的时候,QTP会根据脚本里的对象名字,在对象仓库里找到对应的仓库对象,
    接着根据仓库对象的特征属性描述,在被测试软件里搜索找到相匹配的实际对象,最后就可以对实际对象进行操作了。

    仓库对象TO一般在录制/编写脚本时加入仓库文件,它不仅可以在录制编写时进行修改,
    也可以在运行过程中进行动态修改,以匹配实际对象。

    和TO、RO相关的几个函数有:

    GetTOProperty():取得仓库对象的某个属性的值
    GetTOProperties():取得仓库对象的所有属性的值
    SetTOProperty():设置仓库对象的某个属性的值

    GetROProperty():取得实际对象的某个属性的值


    理解了TO的含义,你就可以自由的用SetTOProperty()定义TO,以灵活的操作RO

    比如有个测试任务,窗口上有很多待检查的记录,每条记录右边都有一个Check按钮,用来检查各条记录。
    记录个数不定,所以Check按钮个数也就不定,只有一个Edit显示记录个数。
    我们要对每条记录进行检查,也就是要点击每个Check按钮。
    但是Check按钮个数不定,不好录制,而且个数可能也很多(上百个),即使能一一录制,那也很麻烦。

    那我有一个好办法,只录制一个按钮对象,它设有两个特征属性 label=OK, index=0
    然后用下面的脚本,就可以完成测试

    buttonNum = CInt(JavaWindow("Test").JavaEdit("Record Num").GetROProperty("value"))
    For buttonIndex = 0 to buttonNum - 1
      JavaWindow("Test").JavaButton("Check").SetTOProperty("index", buttonIndex)
      JavaWindow("Test").JavaButton("Check").Click
    Next


    或者窗口上有New、Modify、Delete、Check等好几个按钮,要把这几个按钮一一按过去
    我在对象仓库里只设置一个按钮对象AnyButton,label特征属性值填任意值,然后用下面脚本执行测试

    JavaWindow("Test").JavaButton("AnyButton").SetTOProperty("label", "New")
    JavaWindow("Test").JavaButton("AnyButton").Click

    JavaWindow("Test").JavaButton("AnyButton").SetTOProperty("label", "Modify")
    JavaWindow("Test").JavaButton("AnyButton").Click

    JavaWindow("Test").JavaButton("AnyButton").SetTOProperty("label", "Delete")
    JavaWindow("Test").JavaButton("AnyButton").Click

    JavaWindow("Test").JavaButton("AnyButton").SetTOProperty("label", "Check")
    JavaWindow("Test").JavaButton("AnyButton").Click

    另外,QTP还支持脚本描述的方法来定义和访问对象,即不需要在仓库里定义,也能访问和操作实际对象
    ( Written by yabest,http://yabest.net

    如上面两个任务,可以如下实现

    1. 不需要在仓库里定义Check按钮对象,直接用下面脚本来实现测试

    buttonNum = CInt(JavaWindow("Test").JavaEdit("Record Num").GetROProperty("value"))
    For buttonIndex = 0 to buttonNum - 1
      JavaWindow("Test").JavaButton("label:=Check", "index:="+CStr(buttonIndex)).Click
    Next

    2. 不需要在仓库里定义New、Modify、Delete、Check按钮对象,直接用下面脚本来实现测试

    JavaWindow("Test").JavaButton("label:=New").Click
    JavaWindow("Test").JavaButton("label:=Modify").Click
    JavaWindow("Test").JavaButton("label:=Delete").Click
    JavaWindow("Test").JavaButton("label:=Check").Click



    二、QTP操作对象的原理(by yabest, http://yabest.net

    QTP为用户提供了两种操作对象的接口,一种就是对象的封装接口,另一种是对象的自身接口。

    对象的自身接口是对象控件本身的接口,只要做过软件开发,使用过控件的人应该很清楚。
    对象的封装接口是QTP为对象封装的另一层接口,它是QTP通过调用对象的自身接口来实现的。


    两种接口的脚本书写格式的差别在于:
      自身接口需要在对象名后面加object再加属性名或方法名,
      封装接口就不用在对象名后面加object。

    具体格式如下:
      对实际对象的操作:
          对象.object.自身属性
          对象.object.自身方法()
          对象.GetROProperty("封装属性")
          对象.封装方法()

      对仓库对象的操作:
          对象.GetTOProperty("封装属性")
          对象.GetTOProperties()      ’获取所有封装属性的值
          对象.SetTOProperty("封装属性", "封装属性值")

    比如操作JavaEdit对象,通过QTP封装的封装接口,脚本如下:
      设置JavaEdit的内容:
         JavaDialog("Add NE").JavaEdit("NE Name").Set "NE1"
      读取JavaEdit的内容:
         msgbox JavaDialog("Add NE").JavaEdit("NE Name").GetROProperty("value")

    如果通过JavaEdit的自身接口,脚本如下:
      设置JavaEdit的内容:
         JavaDialog("Add NE").JavaEdit("NE Name").object.setText("NE1")
      读取JavaEdit的内容:
         Msgbox JavaDialog("Add NE").JavaEdit("NE Name").object.getText()

    QTP执行JavaEdit().Set语句时,是通过执行JavaEdit().object.setText()来实现的。
    QTP执行JavaEdit().GetROProperty("value"),是通过执行JavaEdit().object.getText()来实现的。
    JavaEdit对象的封装接口Set()和GetROProperty("value"),是QTP封装JavaEdit对象的自身接口setText()和getText()而得来的。

    对象的封装接口是QTP使用的缺省接口,我们录制出来的脚本都是使用封装接口,大家用的也都是封装接口。
    但是封装接口不如自身接口丰富,因为QTP只是封装了部分常用的自身接口嘛。
    所以我们在需要时,可以绕过封装接口,直接调用对象的自身接口。
    不过有些自身接口不够稳定,在实践中偶尔会出现问题,但是概率很少。
    封装接口有相应功能的话,就尽量用封装接口吧!
    ( Written by yabest,http://yabest.net

    理解了封装接口和自身接口的原理,我们就可以更加灵活的操作对象了。

    但是我们怎么知道对象都有哪些封装接口和自身接口呢?
    其实很简单,用对象查看器(Object Spy)查看对象,在查看窗口里有列出这些接口,包括属性和方法。
    窗口中间有选择栏让你选择Run-time Object或者Test Object,
    当你选择Runtime Object时,它显示的就是对象的自身接口(自身的属性和方法)
    当你选择Test Object时,它显示的就是对象的封装接口(封装的属性和方法)

    (注意:GetROProperty访问的是实际对象的封装接口,GetTOProperty访问的是仓库对象的封装接口,
                两者访问的都是对象的封装接口,即Object Spy窗口里选Test Object时显示的属性。
                不要以为GetROProperty访问的是自身接口,即Object Spy窗口里选Run-time Object时显示的属性。
                QTP里的Test Object/Run-time Object的概念太容易让人混淆了!
                它既用来区分仓库对象和实际对象,又用来区分对象的封装接口和自身接口。



    明白了这些,你还等什么呢?快拿起对象查看器,看看对象都有哪些封装接口和自身接口,肆意的操作它,玩弄它吧!

    比如执行
      JavaDialog("Add NE").JavaEdit("NE Name").object.setVisible(false)
    哈哈,你的JavaEdit对象就当场消失不见了!!!

    你可以拿这个做恶作剧,指着这个窗口逼问开发人员,JavaEdit对象哪去了?
    开发人员肯定瞪大眼睛看着这个窗口,当场翘掉!!!
  • 在QTP中设置共享对象库

    2008-03-14 15:43:52

    多时候我们总是觉得管理QTP的脚本比较烦.因为除了要对代码的管理之外,还要保证QTP对象库的完整.每一个用例脚本的生成,同时又都会生成一个对象库.那么是不是可以做一个公共的对象库来给各个用例脚本调用呢?接下来,我们就来实现共享对象库的应用.

     

      第一步:把需要加到共享对象库中的各个用例脚本的对象库,分别导出成.tsr文件.

      操作方法:先用QTP打开已经录制完毕的脚本后,选择Resources--> Object Repository .

      然后file-->export....取名导出文件.如下图:

               

      第二步:把需要加入到共享对象库中的各个用例脚本的对象库,合并对象及对象属性,形成一个大的共享对象库.

      操作方法:打开Resources-->Object Repository Manager.找到Tools菜单,然后选择打开Object Repository merge tool.选择两个要合并的对象库文件,进行对象合并.一次只能合并两个.所以如果这里你要合并多个对象库文件的话,先合并两个后,保存成一个新的.tsr文件.然后再重复上面的操作,选择这个新的.tsr文件和另一个准备好的对象库合并.如下图:

             

      合并的时候,你会发现,在两个对象库文件中,相同的对象合并成一个,不同的对象,全部被完整增加进去.然后形成一个大的对象库.现在只要保存这个共享对象库.如果以后有新增的对象,可以重复上述操作.

      第三步:调用上面保存好的共享对象库.给新的脚本使用.

      操作步骤:Resources-->Associate Repository.选择上面保存好的共享对象库的.tsr文件.加入到Associate Repository中.如下图:

      

      完成这一步后,其实整个共享对象库的操作已经完成.你在对象库中可以看到以后的对象.在录制新脚本的时候,如果对象已经存在,就不会再被记录,只有在这个对象库中没有的对象才会被记录进去.回放脚本,对象识别成功.

    (注:此操作只适合与装有QTP9.0的版本.对于8.2版本不适合)

    附:8.2版本中的共享对象库操作

    QTP8.2的共享方法
    1. 选择“测试”>“设置”>“资源”选项卡。
    2. 在“对象库类型”区域,“共享”。
    请指定要用作对象库文件的共享对象库文件。要指定文件,请输入对象库文件名,或单击浏览按钮并从“打开”对话框中选择资源文件。要新建共享对象库文件,请在“共享”框中输入新文件名。
    对象库文件的默认文件扩展名是 .tsr,但是文件可能使用任何扩展名。在“打开”对话框中浏览现有对象库文件时,在“文件类型”框中选择“所有文件”。
    3. 注:请在新测试开始录制前进行设置,已有测试的对象库模式不能进行修改。

    此文来源于51testing博客,转载请注明出处为51testing博客
    原始链接:
    http://blog.51testing.com/?26649/action_viewspace_itemid_2278.html

  • 利用性能测试优化系统

    2008-03-13 14:47:47

      对于一个开发比较成熟的业务系统而言,功能相对已经完善,但在大业务量的情况下往往会出现各种异常。对此,需通过对系统进行配置修改或者产品框架调整来优化系统。在优化系统过程中,最有效的手段就是对系统做性能测试,通过测试结果的收集分析,不断进行系统优化,最终达到系统在大业务量情况下稳定运行的目的。

        一、测试方法

      测试方法主要通过测试过程中的测试步骤体现出来。测试步骤需根据每次的测试结果不断调整,一个完善的测试方法需要不断地进行性能测试和性能调整。在开始性能调整循环之前,必须确定以下两点:一是建立业务模型,通过统计或数学模型的方法建立起科学的业务模型,如业务流程分布比例、平均负荷、峰值负载等;二是设置性能指标,作为判断设计指标和实际性能处理指标的基准值,总体的系统吞吐量、系统的吞吐效率、响应时延等都是用于测量性能的常用度量标准。

      确定以上两点后,开始调整循环,这是一系列重复的受控性能试验。重复图1所示的四个调整循环阶段,直至获得在开始调整过程前建立的系统性能目标。

        二、测试阶段

      测试阶段是调整循环操作的起点,此阶段是根据测试的要求进行相关操作,为下一步结果统计提供相应的测试数据。此阶段需要注意测试环境配置、测试用例的操作两个要点。

        1.测试环境配置

      不同的测试环境会产生不同的测试结果,因此测试前需要对环境配置进行详细的检查。

      (1)检查网络连通性。网络畅通是测试能够正常进行的基本前提。

      (2)检查流量模型是否超出系统负荷。如果将要加的压力大大超出系统的负荷,会对系统产生伤害,并可能在测试过程中出现宕机、告警等异常情况。

      (3)检查被测系统的系统配置。此系统配置包括软件版本和硬件配置两个方面,不同的系统配置会产生不同的测试结果,故测试之前应对被测系统的配置进行严格核对,检查是否是测试所需的系统配置。

      (4)检查测试工具的参数配置。在性能测试中,必须利用测试工具来模拟大业务量。对于一个功能相对完善的测试工具,不但能模拟大业务量,而且还能够配置压力递增方式、压力大小、压力持续时间等参数。在测试之前需要根据测试的需求检查相应参数配置是否满足测试要求。

        2.测试用例操作

      测试过程中,性能测试主要按照测试用例规定的内容去逐步操作。一般来讲性能测试用例内容大体分成测试环境配置、预置条件、测试步骤、预期结果、判定原则、测试结果六个方面。

      环境配置是指按照测试的需求配置测试环境,包括网络的组网、系统的参数配置等;测试预置条件是指为了真实模拟一些场景,需要在测试之前在系统中预置一些条件,例如在邮箱系统的性能测试过程中,为了模拟业务开展的实际情况测试,需要在邮件系统中预先存储一些积压的邮件;测试步骤是指在环境配置完成及预置条件完成后,如何对系统加压的过程,一般而言,首先确定压力的生成形式(如阶梯型递增、二次曲线形式递增等),然后确定压力递增的时间,最后要求压力保持的时间;预期结果是指通过理论及经验分析,对实际测试结果的一个预期指标,此内容是检验测试结果的一个依据;判定原则是制定出一个标准来判断测试是否满足要求,此原则的制定很大程度上依据测试的预期结果;测试结果是根据实际测试情况及参考预期结果和判定原则对测试的一个总体结论,其结论包括此项测试是否通过及测试的相应指标记录两个方面。

        3.结果统计

      此过程是调整循环内容中一个承上启下的环节。此环节统计的数据来源于上一次的测试结果,并为下一步的数据分析提供相关数据。

      结果的统计可以来源于被测系统和测试工具本身两个方面,在统计过程中不但要考虑到从被测系统中统计数据还要兼顾到测试工具本身的数据统计。一般来讲,从被测系统可以直接通过系统的日志统计出系统资源消耗(如CPU、内存的占用率等);从测试工具本身可以统计出压力的大小、业务处理时延、业务处理成功率等指标。结果统计阶段需要将以上两个方面的数据一并统计出来,为下一步数据分析提供重要依据。

    4.结果分析

      通过数据统计收集到系统所需的性能数据后,对这些数据进行分析以确定系统瓶颈。在这里,需要明确的是统计到的体现性能数据仅具有指示性,它并不一定就可以确定实际的瓶颈在哪里,因为一个性能问题可能由多个原因所致。因此,在结果分析阶段需要从系统的角度去分析并查找原因,千万不能走入“头痛医头,脚痛医脚”的误区。在结果分析阶段应该注意到以下几个方面。

      (1)数据发现的敏感性,能够主动发现一些貌似“合理”的数据问题。

      (2)数据分析的系统性,能够通过测试数据的表象,从系统的角度对数据进行分析,发现系统瓶颈。

      (3)数据合理的疑问性,测试工作的目的就是要发现问题,优化系统,所以应该抱着对所有数据怀疑的态度去分析测试数据,这样才能做到不遗漏任何的“可疑”数据。

      (4)结果分析的分步性,通过测试经验,对于测试结果分析可以分成六步进行,包括观察、初步假设、预测、测试、控制和结论,结论由该过程积累的最佳证据集合所支持的假设组成。

        三、总结

      在循环调整的过程中,测试、结果统计、结果分析环节的最终目的是要对系统进行优化。因此,系统优化的依据直接来源于对测试结果的分析。通常来讲,对于一个比较成熟的系统,系统的绝大多数优

      化工作往往是对系统配置的优化,只有少部分的优化工作是对系统设计的修改。

      通过对结果的分析,可以大体定位出系统问题出现在哪里,随后对系统配置进行更改及优化。此优化过程大部分的工作是尝试性和不间断性的,需要不断尝试配置参数的改变,然后验证此配置的修改是否达到预期目的。如果没有达到预期目的,需要进一步对配置进行修改和验证。根据以往的测试经验,实现参数配置更改的最重要规则是一次仅实现一个配置更改。这主要是由于系统某一个模块/单元出现问题可能是由多个模块/单元的瓶颈导致的。因此,分别处理每个问题很重要。如果同时进行多个更改,将不可能准确地评定每次更改的影响。

      实现了配置更改后,必须对修改后的系统进行测试,确定更改对系统所产生的影响。如果幸运,性能提高到预期的水平,这时便可以退出。如果不是这样,则必须重新逐步进行调整循环。

      综合考虑以上的内容,一个调整循环的流程才算基本完成,根据调整的结果来考虑是否进入下一部调整循环的阶段。



  • QTP中可以代替单选框参数化的一段代码

    2008-03-11 16:57:31

    Dim radioNum,indexArray
       radioNum =  Browser("Browser").Page("Page").Frame("dialog_workArea").WebRadioGroup(EmpobjName).GetROProperty("all items")
          IndexArray = Split(radioNum,";")
          If EmpinputValue = "有效" Then
           Browser("Browser").Page("Page").Frame("dialog_workArea").WebRadioGroup(EmpobjName).Select(IndexArray)
                            ElseIf EmpinputValue = "无效" Then
             
    Browser("Browser").Page("Page").Frame("dialog_workArea").WebRadioGroup(EmpobjName).Select(IndexArray())
                End If
  • QTP进行参数化后,无法运行第二行的问题

    2008-03-11 11:15:29

       其实刚接触QTP的时候,按照它自带的教程做过也是遇到过这样的问题,只是没有一个好的记录,以后呢,有什么问题我会在此记录下来,一呢是使自己可以不用像无头苍蝇到处乱撞,有据可查。二呢,还可以告诉自己其实自己也是在努力啦!呵呵。
        下面就说说这个新手都会遇到的一个问题吧!
        问题描述:
        根据 QTP_Tutorial 里面的步骤介绍,先录制预定从 New York 到 San Francisco 航班的机票的操作,然后增加检查点 Checkpoint,最后对fromPort 进行参数化,设置了三个起飞点。
    测试运行后,QTP正常运行完DataTable的第一行,但当第二次运行时出错,提示:Cannot identify the object "fromPort" (of class WebList). Verify that this object's properties match an object currently displayed in your application.
        问题分析:
        仔细观察,可以发现运行完第一行参数的脚本后,开始执行第二行参数时,用户登录不上,登陆的时候,userName填完以后,填写password后,userName被清空了,登录失败造成了后面运行提示找不到起飞地的对象。
        比较后,发现初始的登录页面与录制到最后一处时点击“backhome”返回的登录页面,实际上并不是同一个页面,初始的登录页面是:Welcome: Mercury Tours,而最后点击“backhome”后返回的登录页面却是:Welcome: Mercury Tours_2.
        将最后一行注释掉,在专家视图中,在最后一行脚本前添加REM。或者直接将此句删除, Browser("Welcome: Mercury Tours").Page("Welcome: Mercury Tours_2").Sync  '此句脚本就是导致运行到第二行时出错的原因,REM掉就OK了。
        保存后再次运行,OK。

         此问题让我联想起以前在bidlink时,使用数据表后,运行QTP我经常是运行失败后结果在那手工进行登录,真够傻的。以后再遇到这样的问题,一定要仔细了,做测试就应该是这样!
  • QTP运行错误:对象无法识别的解决办法(转)

    2008-03-10 16:12:17

    1.1 如何去识别对象描述(Identifying Test Object Descrīption Problems)
         如果你能在被测程序中看到对象,但仍出现了“Cannot Identify Object”错误信息,这就表示仓库中对象的描述与程序中对象的描述一定存在着差异。
         解决对象描述问题的第一步是找到差异,最简单的方法是将仓库中对象的属性值与程序中对象的属性值进行比较。(仓库中对象的属性值可在Object Repository窗口中查看,程序中对象的属性值可用Object Spy功能查看。)
         比较仓库中对象的属性值与程序中对象的属性值的操作见1.3。
         在完成比较后,是否发现存在差异?如果是,请参考1.4;如果否,请参考1.5。

    1.2 处理对象丢失问题(Solving Missing Object Problems)
    在运行脚本时,QTP尝试进行某种操作,而该操作的对象在程序中却没有出现,出现这种情况的原因有以下几种:
    >>>对象不再存在。对象已经被从程序中删除。解决方法:见1.2.1。
    >>>对象还没有装载。解决方法:见1.2.2。
    >>>当前的程序页面(或窗口)不正确,不是对象所在的页面(或窗口)。解决方法:见1.2.3。
    >>>前一个步骤没有正确执行。解决方法:见1.2.3。

    1.2.1 解决对象不再存在的问题
    如果对象已经不再在被测程序中存在,则应在脚本中修改或删除相关步骤。

    1.2.2 解决对象装载超时的问题
    如果对象丢失的原因是因为没有足够的时间装载,尝试以下解决方案:
    a.对于Web对象,增加Browser Navigation Timeout(File>Setting>Web页签)时间。
    b.在包括该对象的步骤前使用Wait语句,让QTP在执行该步骤之前等待一段时间。

    1.2.3 检查前面步骤的执行情况
    如果是因为打开了错误的页面(或窗口)导致对象丢失问题,或因为前一步骤执行措误导致对象丢失问题,则请按以下方法检查原因:
    a. 如果怀疑在完成脚本后,被测程序又发生了改变,则检查对象的继承关系以及对象描述。参考1.1。
    b. 如果怀疑脚本错误,则检查脚本的每一个步骤。你可能是遗失了某个步骤,也可能是使用了不正确的方法或参数。

    1.3 测试对象的属性值与Run-time对象的属性值的比较(Comparing Test Object and Run-Time Object Property Values)

    根据以下的步骤比较测试对象与Run-time对象的属性值:
    1) 进入Obecjt Repository窗口(Resources>Object Repository),选择对象。
    2) 记录对象的class以及它的各个属性及属性值。
    3) 打开被测程序,并打开包含被测对象的页面或窗口。
    4) 在QTP中选择菜单Tools>Object Spy或点击Object Spy按钮,打开Object Spy对话框
    5) 选择“Test Object Properties”选项。
    6) 点击右上角的按钮(带有手图标的),这时QTP窗口以及Object Spy对话框都被最小化。
    7) 在程序页面(或窗口)中点击目标对象,恢复Object Spy对话框,并在对话框中显示对象及其父对象(以树的形式显示),并在Properties页签中显示当前对象的属性及属性值。
    8) 这时Object Spy对话框的Properties页签中显示Run-time对象的所有属性,在此查看对象的class,以及它的属性及属性值,并将它与第2步中记下的内容进行比较。

    1.4 解决对象描述存在的问题(Solving Object Descrīption Problems)
         如果发现仓库中对象的属性值与程序中对象的属性值存在不同,你应该判断这个不同是个别对象的问题,还是其它同类对象也存在相同的问题。
         是所有(或多个)同类对象都存在问题吗?如果是,则参考1.6;如果否,则参考1.7

    1.5 关于父对象描述的识别问题(Identifying Parent Object Descrīption Problems)
    对象的识别还与它所继承的父对象有关。
         如果你能在被测程序中看到对象,而且程序中对象的属性值与仓库中对象的属性值也是一致的,但仍然遭遇到了“Cannot identify object”错误,则这个错误可能与它的父对象有关(如仓库中父对象的属性值与程序中父对象的属性值不一致),也可能是仓库中的对象与程序中对象的继承关系不相同导致的。
    要判断是继承关系中的哪个父对象出现了问题,请尝试下面的方法之一:

    >>>重新录制对象,比较新旧对象的父对象。
    欲了解如何完成比较,参考1.8。
    >>>对继承关系中的每个父对象,分别插入一个Exist语句,并运行该部分脚本。
    欲了解如果创建Exist语句,参考1.9。
    注:你也可以使用Object Repository窗口中的Highlight in Application功能,在被测程序中定位对象。
    一旦找到了存在问题的父对象,接下来偿试以下方法:
    >>>修复存在问题的父对象的描述。方法见1.4。
    >>>在专家视图的模式下,查找所有继承存在问题的实例并进行修正。举例:1.8.1。

    1.6 解决某类对象的识别问题(Soving Object Identification Problems for a Test Object Class)
         如果你发现某类对象的对象描述对于被测程序来说都不是很合理,或你预期到对象描述中的某属性值是经常变化的,你可以在Object Identification对话框中改变该类的识别属性的设置,或定义该类的Smart Identification设置并启用Smart Identification机制,这样QTP就可以唯一识别对象了。

    1.7 解决单个对象的描述问题(Solving Individual Test Object Descrīption Problems)
    选择下列方法之一来解决对象的描述问题:
    >>>如果被测程序中对象描述发生了改变,并且你也清楚改变的内容,并且该改变是永久性或长期性的,你可以直接手工修改仓库中对象描述中的相关属性值。
    >>>如果被测程序中的对象的属性值依赖于前面的步骤或其它对象,则将该属性值参数化,这样就可以使用其它步骤的输出值为属性值。
    >>>如果属性值的组成部分中,部分是固定的,部分是动态改变的,则可以将属性值设计为正则表达式。
    >>>如果属性值是遵循某种规则变化的,或者是不可预期的,则从对象描述中移除该属性,并向对象描述中添加一个或多个属性以便于QTP进行对象识别。
    >>>If you can only access the information on the property values during the run session, you can create and use functions that use programmatic descrīptions to identify the object using property values retrieved earlier in the run session.
    For more information on programmatic descrīptions, see Using Programmatic Descrīptions.
    >>>如果在录制过程中对象是唯一的,但现在程序中出现了两个或多个描述相同的对象,但是它们在页面(或窗口)中的位置不相同,则应在Object Properties或Object Repository窗口中,向对象描述中添加一个ordinal identifier(index或location)。

    1.8 重新录制对象,以判断父对象描述是否存在问题(Re-recording an Object to Identify Parent Object Descrīption Problems)
    根据下面的指引,来判断父对象的问题。
    通过重新录制对象,来判断它的父对象是否存在问题:
    1) 打开浏览器或程序,来到包含被测对象的页面或窗口。
    2) 在关键字视图模式,选择最后一个组件(component),或在专家视图模式,将光标放在最后一个脚本步骤的下面。
    3) 点击Record按钮,或选择Automation>Record。
    4) 点击(或操作)页面或窗口中的目标对象。
    5) 点击Stop按钮,或选择Automation>Stop,完成步骤添加。
    6) 右击新添加的步骤,并选择Object Properties右键菜单。
    7) 在Object Properties对话框中,点击Repository,打开Object Repository窗口,并选中了新对象。注意记下该对象的继承关系。
    8) 在Object Repository窗口中找到旧的对象(即存在问题的对象),将它的继承关系与新对象的继承关系进行比较。
    通过比较,可以检查到新旧对象是父对象的描述存在不同,还是它们的继承关系根本就不同。
    a. 如果是父对象的描述问题,则修改父对象的描述。参见1.4.
    b. 如果是对象的继承关系不正确(即具有不同的父对象)引起的问题,则在脚本中找到所有使用该继承关系的实例,将它们替换为正确的继承关系。举例:参见1.8.1。

    1.8.1 举例
         假设有一个带有Frame的网站,你录制了一个操作针对Image对象“Poster”的操作步骤。在Object Repository窗口,你可以Image对象的继承关系如下所示:
    MyCompany(Browser)
         MyCompany(Page)
             Main(Frame)
                  Poster(image)
         当你运行脚本时,网页看起来没有什么不同,但是识别Image对象时却出现了“Cannot identiry object”的错误提示。当你重新录制操作步骤,然后在Object Repository窗口中查看新的Image对象时,发现该对象的继承关系如下所示:
    MyCompany(Browser)
         MyCompany(Page)
              Poster(image)
         从中可以看出,Frame已经从Web Page中移除,所以尽管Image对象“Poster”的描述没有发生任何改变,但它的继承关系已经改变了。
         在Object Repository窗口,你可以看到新旧Image对象“Poster”是两个完全不同的对象:旧的位于已经被移除的Frame对象之下,而新的则直接位于Page“Mycompany”对象之下。
         修复这个问题,可以在脚本步骤中将旧的对象替换为新的对象。
         为了保持Object Repository窗口的整洁,你应删除那些已不再存在的对象(如本例中的Frame)。

    1.9 创建Exist语句,以判断父对象的描述是否存在问题
         QTP在录制发生在某个对象上的操作时,也会同时去了解对象以及它的继承关系。因此,如果在运行过程中,QTP不能识别继承关系中的任何一个父对象,都会导致目标对象的识别失败。
         使用带有Exist方法的Msgbox语句,可以方便的检查出是继承关系中的哪个父对象出现了问题。
         假设在运行下面脚本时,你遇到了“Cannot identify Object”错误信息(但是可以确定对象仓库中Link对象的描述与当前程序中对象的描述是完全一致的):
    Browser("Yahoo!").Page("Yahoo!").Link("Arts & Humanities").Click
    你可以在该语句前面插入以下语句:
    Msgbox Browser("Yahoo!").Exist
    Msgbox Browser("Yahoo!").Page("Yahoo!").Exist
    Msgbox Browser("Yahoo!").Page("Yahoo!").Link("Arts & Humanities").Exist
    然后你从头开始运行脚本,发现第1行语句运

         但是,当QTP运行到第2步时,就弹出信息框,内容为“False”,表示不能找到Page object。这就证明Page对象存在问题。
         确定了出现问题的父对象以后,修复该问题。参见1.4。


    2.       运行错误:对象不唯一(The object is not unique)
    在被测页面或窗口中的同一父对象下,找到多个与仓库中对象描述相符的Run-tim对象。
    请确定是只有个别对象存在此问题,还是此类对象的所有对象(或部分对象)存在此问题。
    此类对象的所有对象(或部分对象)都存在此问题吗?如果是,参考2.1;如果否,参考2.2。

    2.1 为某对象类设置能唯一识别对象的描述规则(Configuring Unique Test Object Descrīptions for a Test Object Class)
         如果你发现某类对象的对象描述都不足以唯一识别对象,你可以在Object Identification对话框中,改变该类的识别属性的设置,或定义该类的Smart Identification设置并启用Smart Identification机制,这样QTP就可以唯一识别对象了。

    2.2 设置通唯一识别对象的对象描述(Creating a Unique Test Object Descrīption for an Object)
    查看当前对象的描述,并偿试在程序中找到其它具有相同描述的对象并查看它们的描述。
    >>>如果你找到了可以将它们区别开来的一个或多个属性,则修改仓库中对象的相关属性(如向描述中添加属性等),以使QTP在运行时可以唯一识别它。
    >>>如果它们的识别属性完全相同,则在对象描述中为对象添加一个ordinal identifier(index或location)。

    3.       运行错误:找不到父对象(Parent not found)
    识别对象时,会先识别它的父对象是否正确。如果遇到“Parent not found”的错误信息,请偿试以下解决方法:
    >>>修复出现问题的父对象的描述。参见1.4。
    >>>在脚本中找到继承关系不正确的实例,并修改为正确的继承关系。例如1.8.1。

    4.       运行错误:无效的参数(Invalid arguments)
    一个或多个方法的参数是无效的。
    参数无效可能是参数类型错误,也可能是参数个数不正确。
    根据以下建议,找到方法的正确语法:
    >>>在Keyword模式,如果方法包括参数,则在Value栏会显示该方法的参数提示。

    >>>在Expert 模式,如果方法包括参数,则当你插入方法然后按下Shift+Ctrl+Space键时,QTP会显示该方法的参数的提示信息。(注:只有在Editor Options对话框的General页签中打开了Statement completion功能时才可以看到参数的提示信息。)


    5.       运行错误:不能识别item(Cannot identify item)
    QTP不能识别方法参数中指定的列表或树对象的item时,请确认指定的item是否存在于对象之中。
    >>>如果item不存在,则删除相关脚本步骤,或修改item。
    >>>如果item存在,但被测程序中它的名字发生了改变,则修改item的名称,或在脚本中使用item的index而不是名字(如“#4”)。注意,不同的对象或方法,它们使用index的语法可能不同。

    6.       运行错误:对象的item不唯一(The object’s item is not unique)
    在列表或树对象中,可能有多个名字相同的item。
    在这种情况下,可以指定item使用index(例如“#4”)。

    7.       运行错误:运行失败(Test run failed)
    测试运行失败,还有可能是其它未知错误造成的。检查出现错误时的脚本步骤。
    如果错误出现在执行检查点或输出值时,请查阅关于检查点与输出值的帮助。
    如果错误出现在使用外部文件时,如数据库表、数据库、环境变量文件、或关联仓库文件等,则检查是否可以正常获取并使用文件,或这些文件的存储格式是否正确。
    如果错误出现在完成某个脚本动作时,请参考QuickTest Object Model Reference帮助,以确认方法或函数的使用是否正确。
    如果错误出现在执行一个标准的VBscrīpt语句时,参考Microsoft VBscrīpt Reference以获得帮助。
  • VBS过程的学习

    2007-07-18 15:01:28

    在 VBscrīpt 中,过程被分为两类:Sub 过程和 Function 过程。

    Sub 过程

    Sub 过程是包含在 SubEnd Sub 语句之间的一组 VBscrīpt 语句,执行操作但不返回值。Sub 过程可以使用参数(由调用过程传递的常数、变量或表达式)。如果 Sub 过程无任何参数,则 Sub 语句必须包含空括号 ()。

    下面的 Sub 过程使用两个固有的(或内置的)VBscrīpt 函数,即 MsgBoxInputBox,来提示用户输入信息。然后显示根据这些信息计算的结果。计算由使用 VBscrīpt 创建的 Function 过程完成。此过程在以下讨论之后演示。

     Sub ConvertTemp()
        temp = InputBox("请输入华氏温度。", 1)
        MsgBox "温度为 " & Celsius(temp) & " 摄氏度。"
     End Sub

    Function 过程

    Function 过程是包含在 FunctionEnd Function 语句之间的一组 VBscrīpt 语句。Function 过程与 Sub 过程类似,但是 Function 过程可以返回值。Function 过程可以使用参数(由调用过程传递的常数、变量或表达式)。如果 Function 过程无任何参数,则 Function 语句必须包含空括号 ()。Function 过程通过函数名返回一个值,这个值是在过程的语句中赋给函数名的。Function 返回值的数据类型总是 Variant

    在下面的示例中,Celsius 函数将华氏度换算为摄氏度。Sub 过程 ConvertTemp 调用此函数时,包含参数值的变量被传递给函数。换算结果返回到调用过程并显示在消息框中。

     Sub ConvertTemp()
         temp = InputBox("请输入华氏温度。", 1)
         MsgBox "温度为 " & Celsius(temp) & " 摄氏度。"
     End Sub Function Celsius(fDegrees)
         Celsius = (fDegrees - 32) * 5 / 9
     End Function

    过程的数据进出

    给过程传递数据的途径是使用参数。参数被作为要传递给过程的数据的占位符。参数名可以是任何有效的变量名。使用 Sub 语句或 Function 语句创建过程时,过程名之后必须紧跟括号。括号中包含所有参数,参数间用逗号分隔。例如,在下面的示例中,fDegrees 是传递给 Celsius 函数的值的占位符:

     Function Celsius(fDegrees)
        Celsius = (fDegrees - 32) * 5 / 9
     End Function

    要从过程获取数据,必须使用 Function 过程。请记住,Function 过程可以返回值;Sub 过程不返回值。

    在代码中使用 Sub 和 Function 过程

    调用 Function 过程时,函数名必须用在变量赋值语句的右端或表达式中。例如:

     Temp = Celsius(fDegrees)

     MsgBox "温度为 " & Celsius(fDegrees) & " 摄氏度。"

    调用 Sub 过程时,只需输入过程名及所有参数值,参数值之间使用逗号分隔。不需使用 Call 语句,但如果使用了此语句,则必须将所有参数包含在括号之中。

    下面的示例显示了调用 MyProc 过程的两种方式。一种使用 Call 语句;另一种则不使用。两种方式效果相同。

     Call MyProc(firstarg, secondarg)
     MyProc firstarg, secondarg

    请注意当不使用 Call 语句进行调用时,括号被省略。

Open Toolbar