发布新日志

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

    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、软件错误流程管理要点

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

    2010-02-26 11:15:29

    俗称,好记性不如烂笔头,记录下来,以备不时只需

    第一步:进入QC的后台,找到要注册的LICENCE项目并打开它;
    第二步:将下面的代码粘贴进去可以用到2099年(代码不能够修改)
    <?xml version="1.0" encoding="UTF-8"?>
    <license>
        <terms>
            <issued_to>rapidhorse.com.cn</issued_to>
            <license_identifier>SN732563653</license_identifier>
            <edition>enterprise</edition>
            <evaluation>N</evaluation>
            <start_date>12/13/2007</start_date>
            <expiration>5/29/2099</expiration>
            <full_test_director>500</full_test_director>
            <additional_defects>500</additional_defects>
            <tolerance>0%</tolerance>
            <requirements>Y</requirements>
            <advanced_reports>Y</advanced_reports>
            <business_process_testing>500</business_process_testing>
            <version_control>Y</version_control>
            <dashboard>Y</dashboard>
        </terms>
        <Signature>lA0FAVrF+UTDW2qVIDjVPCSpPKRUpKcoTO8/GI95D1RLIzQAq/8mv+HnIGQ0Grv9am8QKHfncRsARR153QxqKw==</Signature>
    </license>

  • QC10.0 一些常用设置

    2009-11-06 11:33:17

     
    2009-09-03 14:22

    1. IE浏览器支持添加IE8

         默认安装的QC10.0 是不支持IE8的,需要稍作修改。

         1)打开D:\Program Files\HP\Quality Center\application\20qcbin.war(D:\Program Files\HP\Quality Center\为QC的安装目录)

         2)打开D:\Program Files\HP\Quality Center\jboss\server\default\tmp\deploy\tmp4099820qcbin-exp.war目录

         修改文件 SiteAdmin、SiteAdmin_b、start_a、start_b这几个文件即可(直接搜索这几个文件)

    添加内容

    var fMSIE67 = (ua.lastIndexOf('MSIE 6.0') != -1)|| (ua.lastIndexOf('MSIE 7.0') != -1)|| (ua.lastIndexOf

    ('MSIE 8.0') != -1);

    2. 修改端口访问端口号

         默认端口号为8080,因为8080为许多软件默认端口,所以有必要修改。

        打开目录D:\Program Files\HP\Quality Center\jboss\server\default\deploy\jbossweb-tomcat55.sar

        修改文件server.xml中的    <Connector port="8080" address="${jboss.bind.address}"

  • ASP.NET中常用的26个优化性能方法(z全版)--转

    2008-08-04 18:50:53

     

    1. 数据库访问性能优化 
     
    数据库的连接和关闭

    访问数据库资源需要创建连接、打开连接和关闭连接几个操作。这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器资源。ASP.NET中提供了连接池(Connection Pool)改善打开和关闭数据库对性能的影响。系统将用户的数据库连接放在连接池中,需要时取出,关闭时收回连接,等待下一次的连接请求。连接池的大小是有限的,如果在连接池达到最大限度后仍要求创建连接,必然大大影响性能。因此,在建立数据库连接后只有在真正需要操作时才打开连接,使用完毕后马上关闭,从而尽量减少数据库连接打开的时间,避免出现超出连接限制的情况。   

    使用存储过程  
     
    存储过程是存储在服务器上的一组预编译的
    SQL语句,类似于DOS系统中的批处理文件。存储过程具有对数据库立即访问的功能,信息处理极为迅速。使用存储过程可以避免对命令的多次编译,在执行一次后其执行规划就驻留在高速缓存中,以后需要时只需直接调用缓存中的二进制代码即可。另外,存储过程在服务器端运行,独立于ASP.NET程序,便于修改,最重要的是它可以减少数据库操作语句在网络中的传输。

    优化查询语句
      
    ASP.NET中ADO连接消耗的资源相当大,SQL语句运行的时间越长,占用系统资源的时间也越长。因此,尽量使用优化过的SQL语句以减少执行时间。比如,不在查询语句中包含子查询语句,充分利用索引等。   

    2. 字符串操作性能优化 
     
    使用值类型的ToString方法
      
    在连接字符串时,经常使用"+"号直接将数字添加到字符串中。这种方法虽然简单,也可以得到正确结果,但是由于涉及到不同的数据类型,数字需要通过装箱操作转化为引用类型才可以添加到字符串中。但是装箱操作对性能影响较大,因为在进行这类处理时,将在托管堆中分配一个新的对象,原有的值复制到新创建的对象中。使用值类型的ToString方法可以避免装箱操作,从而提高应用程序性能。   

    运用StringBuilder类   

    String类对象是不可改变的,对于String对象的重新赋值在本质上是重新创建了一个String对象并将新值赋予该对象,其方法ToString对性能的提高并非很显著。在处理字符串时,最好使用StringBuilder类,其.NET 命名空间是System.Text。该类并非创建新的对象,而是通过Append,Remove,Insert等方法直接对字符串进行操作,通过ToString方法返回操作结果。   其定义及操作语句如下所示:


    int num;   System.Text.StringBuilder str = new System.Text.StringBuilder(); //创建字符串   str.Append(num.ToString()); //添加数值num   Response.Write(str.ToString); //显示操作结果3. 优化
    Web 服务器计算机和特定应用程序的配置文件以符合您的特定需要

    默认情况下,ASP.NET 配置被设置成启用最广泛的功能并尽量适应最常见的方案。因此,应用程序开发人员可以根据应用程序所使用的功能,优化和更改其中的某些配置,以提高应用程序的性能。下面的列表是您应该考虑的一些选项。

    仅对需要的应用程序启用身份验证。

    默认情况下,身份验证模式为
    Windows,或集成 NTLM。大多数情况下,对于需要身份验证的应用程序,最好在 Machine.config 文件中禁用身份验证,并在 Web.config 文件中启用身份验证。根据适当的请求和响应编码设置来配置应用程序。ASP.NET 默认编码格式为 UTF-8。如果您的应用程序为严格的 ASCII,请配置应用程序使用 ASCII 以获得稍许的性能提高。
      
    考虑对应用程序禁用 AutoEventWireup。

    在 Machine.config 文件中将 AutoEventWireup 属性设置为 false,意味着页面不将方法名与事件进行匹配和将两者挂钩(例如 Page_Load)。如果页面开发人员要使用这些事件,需要在基类中重写这些方法(例如,需要为页面加载事件重写 Page.OnLoad,而不是使用 Page_Load 方法)。如果禁用 AutoEventWireup,页面将通过将事件连接留给页面作者而不是自动执行它,获得稍许的性能提升。

    从请求处理管线中移除不用的模块。

    默认情况下,服务器计算机的 Machine.config 文件中 节点的所有功能均保留为激活。根据应用程序所使用的功能,您可以从请求管线中移除不用的模块以获得稍许的性能提升。检查每个模块及其功能,并按您的需要自定义它。例如,如果您在应用程序中不使用会话状态和输出缓存,则可以从 列表中移除它们,以便请求在不执行
    其他有意义的处理时,不必执行每个模块的进入和离开代码。

    4. 一定要禁用调试模式  

    在部署生产应用程序或进行任何性能测量之前,始终记住禁用调试模式。如果启用了调试模式,应用程序的性能可能受到非常大的影响。   

    5. 对于广泛依赖外部资源的应用程序,请考虑在多处理器计算机上启用网络园艺  

    ASP.NET 进程模型帮助启用多处理器计算机上的可缩放性,将
    工作分发给多个进程(每个CPU一个),并且每个进程都将处理器关系设置为其 CPU。此技术称为网络园艺。如果应用程序使用较慢的数据库服务器或调用具有外部依赖项的 COM 对象(这里只是提及两种可能性),则为您的应用程序启用网络园艺是有益的。但是,在决定启用网络园艺之前,您应该测试应用程序在网络园中的执行情况。   

    6. 只要可能,就缓存数据和页输出  

    ASP.NET 提供了一些简单的机制,它们会在不需要为每个页请求动态计算页输出或数据时缓存这些页输出或数据。另外,通过设计要进行缓存的页和数据请求(特别是在站点中预期将有较大通讯量的区域),可以优化这些页的性能。与 .NET Framework 的任何 Web 窗体功能相比,适当地使用缓存可以更好的提高站点的性能,有时这种提高是超数量级的。使用 ASP.NET 缓存机制有两点需要注意。首先,不要缓存太多项。缓存每个项均有开销,特别是在内存使用方面。不要缓存容易重新计算和很少使用的项。其次,给缓存的项分配的有效期不要太短。很快到期的项会导致缓存中不必要的周转,并且经常导致更多的代码清除和垃圾回收工作。若关心此问题,请监视与 ASP.NET Applications 性能对象关联的 Cache Total Turnover Rate 性能计数器。高周转率可能说明存在问题,特别是当项在到期前被移除时。这也称作内存压力。


    7. 选择适合页面或应用程序的数据查看机制  

    根据您选择在 Web 窗体页显示数据的方式,在便利和性能之间常常存在着重要的权衡。例如,DataGrid Web 服务器控件可能是一种显示数据的方便快捷的方法,但就性能而言它的开销常常是最大的。在某些简单的情况下,您通过生成适当的 HTML 自己呈现数据可能很有效,但是自定义和浏览器定向会很快抵销所获得的额外功效。Repeater Web 服务器控件是便利和性能的折衷。它高效、可自定义且可编程。   

    8. 将 SqlDataReader 类用于快速只进数据游标  

    SqlDataReader 类提供了一种读取从 SQL
    Server 数据库检索的只进数据流的方法。如果当创建 ASP.NET 应用程序时出现允许您使用它的情况,则 SqlDataReader 类提供比 DataSet 类更高的性能。情况之所以这样,是因为 SqlDataReader 使用 SQL Server 的本机网络数据传输格式从数据库连接直接读取数据。另外,SqlDataReader 类实现 IEnumerable 接口,该接口也允许您将数据绑定到服务器控件。有关更多信息,请参见 SqlDataReader 类。有关 ASP.NET 如何访问数据的信息,请参见通过 ASP.NET 访问数据。   

    9. 将 SQL Server 存储过程用于数据访问  

    在 .NET Framework 提供的所有数据访问方法中,基于 SQL Server 的数据访问是生成高性能、可缩放 Web 应用程序的推荐选择。使用托管 SQL Server 提供程序时,可通过使用编译的存储过程而不是特殊查询获得额外的性能提高。   

    10. 避免单线程单元 (STA) COM 组件  

    默认情况下,ASP.NET 不允许任何 STA COM 组件在页面内运行。若要运行它们,必须在 .aspx 文件内将 ASPCompat=true 属性包含在 @ Page 指令中。这样就将执行用的线程池切换到 STA 线程池,而且使 HttpContext 和其他内置对象可用于 COM 对象。前者也是一种性能优化,因为它避免了将多线程单元 (MTA) 封送到 STA 线程的任何调用。使用 STA COM 组件可能大大损害性能,应尽量避免。若必须使用 STA COM 组件,如在任何 interop 方案中,则应在执行期间进行大量调用并在每次调用期间发送尽可能多的信息。另外,小心不要在构造页面期间创建任何 STA COM 组件。例如下面的代码中,在页面构造时将实例化由某个线程创建的 MySTAComponent,而该线程并不是将运行页面的 STA 线程。这可能对性能有不利影响,因为要构造页面就必须完成 MTA 和 STA 线程之间的封送处理。


    <%@ Page Language="VB" ASPCompat="true" %><% Response.Write(myComp.SayHello) %>


    首选机制是推迟对象的创建,直到以后在 STA 线程下执行上述代码,如下面的例子所示。




    <%@ Page Language="VB" ASPCompat="true" %><% Response.Write(myComp.SayHello) %>

    推荐的做法是在需要时或者在 Page_Load 方法中构造任何 COM 组件和外部资源。永远不要将任何 STA COM 组件存储在可以由构造它的线程以外的其他线程访问的共享资源里。这类资源包括像缓存和会话状态这样的资源。即使 STA 线程调用 STA COM 组件,也只有构造此 STA COM 组件的线程能够实际为该调用服务,而这要求封送处理对创建者线程的调用。此封送处理可能产生重大的性能损失和可伸缩性问题。在这种情况下,请研究一下使 COM 组件成为 MTA COM 组件的可能性,或者更好的办法是迁移代码以使对象成为托管对象。   

    11. 将调用密集型的 COM 组件迁移到托管代码  

    .NET Framework 提供了一个简单的方法与传统的 COM 组件进行交互。其优点是可以在保留现有投资的同时利用新的平台。但是在某些情况下,保留旧组件的性能开销使得将组件迁移到托管代码是值得的。每一情况都是不一样的,决定是否需要迁移组件的最好方法是对 Web 站点运行性能测量。建议您研究一下如何将需要大量调用以进行交互的任何COM 组件迁移到托管代码。许多情况下不可能将旧式组件迁移到托管代码,特别是在最初迁移 Web 应用程序时。在这种情况下,最大的性能障碍之一是将数据从非托管环境封送到托管环境。因此,在交互操作中,请在任何一端执行尽可能多的任务,然后进行一个大调用而不是一系列小调用。例如,公共语言运行库中的所有字符串都是 Unicode 的,所以应在调用托管代码之前将组件中的所有字符串转换成 Unicode 格式。另外,一处理完任何 COM 对象或本机资源就释放它们。这样,其他请求就能够使用它们,并且最大限度地减少了因稍后请求垃圾回收器释放它们所引起的性能问题。   

    12. 在 Visual Basic .NET 或 Jscrīpt. 代码中使用早期绑定  

    以往,开发人员喜欢使用 Visual Basic、VBscrīpt. 和 Jscrīpt. 的原因之一就是它们所谓“无类型”的性质。变量不需要显式类型声明,并能够简单地通过使用来创建它们。当从一个类型到另一个类型进行分配时,转换将自动执行。不过,这种便利会大大损害应用程序的性能。Visual Basic 现在通过使用 Option Strict 编译器指令来支持类型安全编程。为了向后兼容,默认情况下,ASP.NET 不启用该选项。但是,为了得到最佳性能,强烈建议在页中启用该选项。若要启用 Option Strict,请将 Strict 属性包括在 @ Page 指令中,或者,对于用户控件,请将该属性包括在 @ Control 指令中。下面的示例演示了如何设置该属性,并进行了四个变量调用以显示使用该属性是如何导致编译器错误的。

    <%@ Page Language="VB" Strict="true" %><% Dim B Dim C As String ' This will cause a compiler error. A = "Hello" ' This will cause a compiler error. B = "World" ' This will not cause a compiler error. C = "!!!!!!" ' But this will cause a compiler error. C = 0 %>Jscrīpt. .NET 也支持无类型编程,但它不提供强制早期绑定的编译器指令。若发生下面任何一种情况,则变量是晚期绑定的:被显式声明为 Object,是无类型声明的类的字段,是无显式类型声明的专用函数或方法成员,并且无法从其使用推断出类型。   最后一个差别比较复杂,因为如果 Jscrīpt. .NET 编译器可以根据变量的使用情况推断出类型,它就会进行优化。在下面的示例中,变量 A 是早期绑定的,但变量 B 是晚期绑定的。

    var A;   var B;   A = "Hello";   B = "World";   B = 0; 为了获得最佳的性能,当声明 Jscrīpt. .NET 变量时,请为其分配一个类型。例如,var A : String。

    13. 使请求管线内的所有模块尽可能高效  

    请求管线内的所有模块在每次请求中都有机会被运行。因此,当请求进入和离开模块时快速地触发代码至关重要,特别是在不使用模块功能的代码路径里。分别在使用及不使用模块和配置文件时执行吞吐量测试,对确定这些方法的执行速度非常有用。

    14. 使用 HttpServerUtility.Transfer 方法在同一应用程序的页面间重定向  

    采用 Server.Transfer 语法,在页面中使用该方法可避免不必要的客户端重定向。
      
    15. 必要时调整应用程序每个辅助进程的线程数  

    ASP.NET 的请求结构试图在执行请求的线程数和可用资源之间达到一种平衡。已知一个使用足够 CPU 功率的应用程序,该结构将根据可用于请求的 CPU 功率,来决定允许同时执行的请求数。这项技术称作线程门控。但是在某些条件下,线程门控算法不是很有效。通过使用与 ASP.NET Applications 性能对象关联的 Pipeline Instance Count 性能计数器,可以在 PerfMon 中监视线程门控。当页面调用外部资源,如数据库访问或 XML Web services 请求时,页面请求通常停止并释放 CPU。如果某个请求正在等待被处理,并且线程池中有一个线程是自由的,那么这个正在等待的请求将开始被处理。遗憾的是,有时这可能导致 Web 服务器上存在大量同时处理的请求和许多正在等待的线程,而它们对服务器性能有不利影响。通常,如果门控因子是外部资源的响应时间,则让过多请求等待资源,对 Web 服务器的吞吐量并无帮助。为缓和这种情况,可以通过更改 Machine.config 配置文件节点的 maxWorkerThreads 和 maxIOThreads 属性,手动设置进程中的线程数限制。   

    注意:辅助线程是用来处理 ASP.NET 请求的,而 IO 线程则是用于为来自文件、数据库或 XML Web services 的数据提供服务的。分配给这些属性的值是进程中每个 CPU 每类线程的最大数目。对于双处理器计算机,最大数是设置值的两倍。对于四处理器计算机,最大值是设置值的四倍。无论如何,对于有四个或八个 CPU 的计算机,最好更改默认值。对于有一个或两个处理器的计算机,默认值就可以,但对于有更多处理器的计算机的性能,进程中有一百或两百个线程则弊大于利。注意进程中有太多线程往往会降低服务器的速度,因为额外的上下文交换导致
    操作系统将 CPU 周期花在维护线程而不是处理请求上。   

    16. 适当地使用公共语言运行库的垃圾回收器和自动内存管理  

    小心不要给每个请求分配过多内存,因为这样垃圾回收器将必须更频繁地进行更多的工作。另外,不要让不必要的指针指向对象,因为它们将使对象保持活动状态,并且应尽量避免含 Finalize 方法的对象,因为它们在后面会导致更多的工作。特别是在 Finalize 调用中永远不要释放资源,因为资源在被垃圾回收器回收之前可能一直消耗着内存。最后这个问题经常会对 Web 服务器环境的性能造成毁灭性的打击,因为在等待 Finalize 运行时,很容易耗尽某个特定的资源。   

    17. 如果有大型 Web 应用程序,可考虑执行预批编译  

    每当发生对目录的第一次请求时都会执行批编译。如果目录中的页面没有被分析并编译,此功能会成批分析并编译目录中的所有页面,以便更好地利用磁盘和内存。如果这需要很长时间,则将快速分析并编译单个页面,以便请求能被处理。此功能带给 ASP.NET 性能上的好处,因为它将许多页面编译为单个程序集。从已加载的程序集访问一页比每页加载新的程序集要快。批编译的缺点在于:如果服务器接收到许多对尚未编译的页面的请求,那么当 Web 服务器分析并编译它们时,性能可能较差。为解决这个问题,可以执行预批编译。为此,只需在应用程序激活之前向它请求一个页面,无论哪页均可。然后,当用户首次访问您的站点时,页面及其程序集将已被编译。没有简单的机制可以知道批编译何时发生。需一直等到 CPU 空闲或者没有更多的编译器进程(例如 csc.exe(C# 编译器)或 vbc.exe(Visual Basic 编译器))启动。还应尽量避免更改应用程序的 \bin 目录中的程序集。更改页面会导致重新分析和编译该页,而替换 \bin 目录中的程序集则会导致完全重新批编译该目录。在包含许多页面的大规模站点上,更好的办法可能是根据计划替换页面或程序集的频繁程度来设计不同的目录结构。不常更改的页面可以存储在同一目录中并在特定的时间进行预批编译。经常更改的页面应在它们自己的目录中(每个目录最多几百页)以便快速编译。Web 应用程序可以包含许多子目录。批编译发生在目录级,而不是应用程序级。

    18. 不要依赖代码中的异常  

    因为异常大大地降低性能,所以您不应该将它们用作控制正常程序流程的方式。如果有可能检测到代码中可能导致异常的状态,请执行这种操作。不要在处理该状态之前捕获异常本身。常见的方案包括:检查 null,分配给将分析为数字值的 String 一个值,或在应用数学运算前检查特定值。下面的示例演示可能导致异常的代码以及测试是否存在某种状态的代码。两者产生相同的结果。


     try   {   result = 100 / num;   }   catch (Exception e)   {   result = 0;   }   // ...to this.   if (num != 0)   result = 100 / num;   else   result = 0;

    19. 使用 HttpResponse.Write 方法进行字符串串联

    该方法提供非常有效的缓冲和连接服务。但是,如果您正在执行广泛的连接,请使用多个 Response.Write 调用。下面示例中显示的技术比用对 Response.Write 方法的单个调用连接字符串更快。




    Response.Write("a");   Response.Write(myString);   Response.Write("b");   Response.Write(myObj.ToString());   Response.Write("c");   Response.Write(myString2);   Response.Write("d"); 20. 除非有特殊的原因要关闭缓冲,否则使其保持打开

    禁用 Web 窗体页的缓冲会导致大量的性能开销。   

    21. 只在必要时保存服务器控件视图状态  

    自动视图状态管理是服务器控件的功能,该功能使服务器控件可以在往返过程上重新填充它们的属性值(您不需要编写任何代码)。但是,因为服务器控件的视图状态在隐藏的窗体字段中往返于服务器,所以该功能确实会对性能产生影响。您应该知道在哪些情况下视图状态会有所帮助,在哪些情况下它影响页的性能。例如,如果您将服务器控件绑定到每个往返过程上的数据,则将用从数据绑定操作获得的新值替换保存的视图状态。在这种情况下,禁用视图状态可以节省处理时间。默认情况下,为所有服务器控件启用视图状态。若要禁用视图状态,请将控件的EnableViewState 属性设置为 false,如下面的 DataGrid 服务器控件示例所示。




    您还可以使用 @ Page 指令禁用整个页的视图状态。当您不从页回发到服务器时,这将十分有用:


    <%@ Page EnableViewState="false" %>

    注意:@ Control 指令中也支持 EnableViewState 属性,该指令允许您控制是否为用户控件启用视图状态。若要分析页上服务器控件使用的视图状态的数量,请(通过将 trace="true" 属性包括在 @ Page 指令中)启用该页的跟踪并查看 Control Hierarchy 表的 Viewstate 列。有关跟踪和如何启用它的信息,请参见 ASP.NET 跟踪。

    22. 避免到服务器的不必要的往返过程  

    虽然您很可能希望尽量多地使用 Web 窗体页框架的那些节省时间和代码的功能,但在某些情况下却不宜使用 ASP.NET 服务器控件和回发事件处理。通常,只有在检索或存储数据时,您才需要启动到服务器的往返过程。多数数据操作可在这些往返过程间的客户端上进行。例如,从 HTML 窗体验证用户输入经常可在数据提交到服务器之前在客户端进行。通常,如果不需要将信息传递到服务器以将其存储在数据库中,那么您不应该编写导致往返过程的代码。如果您开发自定义服务器控件,请考虑让它们为支持 ECMAscrīpt. 的浏览器呈现客户端代码。通过以这种方式使用服务器控件,您可以显著地减少信息被不必要的发送到 Web 服务器的次数。

    使用 Page.IsPostBack 避免对往返过程执行不必要的处理

    如果您编写处理服务器控件回发处理的代码,有时可能需要在首次请求页时执行其他代码,而不是当用户发送包含在该页中的 HTML 窗体时执行的代码。根据该页是否是响应服务器控件事件生成的。

    使用 Page.IsPostBack 属性有条件地执行代码

    例如,下面的代码演示如何创建数据库连接和命令,该命令在首次请求该页时将数据绑定到 DataGrid 服务器控件。


    void Page_Load(Object sender, EventArgs e)   {   // Set up a connection and command here.   if (!Page.IsPostBack)   {   String query = "select * from Authors where FirstName like '%JUSTIN%'";   myCommand.Fill(ds, "Authors");   myDataGrid.DataBind();   }   }

    由于每次请求时都执行 Page_Load 事件,上述代码检查 IsPostBack 属性是否设置为 false。如果是,则执行代码。如果该属性设置为 true,则不执行代码。注意 如果不运行这种检查,回发页的行为将不更改。Page_Load 事件的代码在执行服务器控件事件之前执行,但只有服务器控件事件的结果才可能在输出页上呈现。如果不运行该检查,仍将为 Page_Load 事件和该页上的任何服务器控件事件执行处理。   

    23. 当不使用会话状态时禁用它  

    并不是所有的应用程序或页都需要针对于具体用户的会话状态,您应该对任何不需要会话状态的应用程序或页禁用会话状态。   若要禁用页的会话状态,请将 @ Page 指令中的 EnableSessionState 属性设置为 false。例如:



    <%@ Page EnableSessi %>注意:如果页需要访问会话变量,但不打算创建或修改它们,则将@ Page 指令中的 EnableSessionState 属性设置为ReadOnly。还可以禁用 XML Web services 方法的会话状态。有关更多信息,请参见使用 ASP.NET 和 XML Web services 客户端创建的 XML Web services。若要禁用应用程序的会话状态,请在应用程序 Web.config 文件的 sessionstate 配置节中将 mode 属性设置为 off。例如:



    24. 仔细选择会话状态提供程序  

    ASP.NET 为存储应用程序的会话数据提供了三种不同的方法:进程内会话状态、作为 Windows 服务的进程外会话状态和 SQL Server 数据库中的进程外会话状态。每种方法都有自己的优点,但进程内会话状态是迄今为止速度最快的解决方案。如果只在会话状态中存储少量易失数据,则建议您使用进程内提供程序。进程外解决方案主要用于跨多个处理器或多个计算机缩放应用程序,或者用于服务器或进程重新启动时不能丢失数据的情况。有关更多信息,请参见 ASP.NET 状态管理。   

    25. 不使用不必要的Server Control

    ASP.net中,大量的服务器端控件方便了程序开发,但也可能带来性能的损失,因为用户每操作一次服务器端控件,就产生一次与服务器端的往返过程。因此,非必要,应当少使用Server Control。   

    26. ASP.NET应用程序
    性能测试  

    在对ASP.NET应用程序进行性能测试之前,应确保应用程序没有错误,而且功能正确。具体的性能测试可以采用以下工具进行:Web Application Strees Tool (WAS)是Microsoft发布的一个免费
    测试工具,可以从http://webtool.rte.microsoft.com/上下载。它可以模拟成百上千个用户同时对web应用程序进行访问请求,在服务器上形成流量负载,从而达到测试的目的,可以生成平均TTFB、平均TTLB等性能汇总报告。Application Center Test (ACT) 是一个测试工具,附带于Visual Studio.NET的企业版中,是Microsoft正式支持的web应用程序测试工具。它能够直观地生成图表结果,功能比WAS多,但不具备多个客户机同时测试的能力。服务器操作系统"管理工具"中的"性能"计数器,可以对服务器进行监测以了解应用程序性能。   

    结论:

    对于网站开发人员来说,在编写ASP.NET应用程序时注意性能问题,养成良好的习惯,提高应用程序性能,至少可以推迟必需的硬件升级,降低网站的成本。

  • 需求---进阶

    2008-07-28 17:05:31

    需求管理

        软件能力成熟度模型(The Capability Maturity Model ,CMM)的第二级(可重复级)中将需求管理做为六个关键过程域(Key Process Areas ,KPAs)的一个:

        需求管理的目的就是在客户和遵循客户需求的软件项目之间建立一种共同的理解。

    需求的目标包括:

    控制指定给软件的系统需求,为软件工程和管理应用建立基线。
    保持软件计划、产品和活动与指定给软件的系统需求一致。

        为了实现第一个目标,必须要控制需求基线的变动,实施需求变更控制和版本控制。为了实现第二个目标,必须要对需求进行跟踪,管理需求和其他联系链之间的联系和依赖。

        虽然并没有要求说软件团体必须要实施CMM,但是CMM的思想对任何的软件团体来说都是有益的,CMM为了实行这两个目标,还确定了一系列的执行约定、执行能力、执行活动来达到这两个目标。但是,CMM并没有强制要求软件团体必须遵循的软件需求管理过程。

        对于产生的需求变更,必须要有变更控制的标准、规范的过程来处理,并且由基于业务和技术的原因来赞同或反对这项变更。在接受了软件变更之后,必须要保证软件开发计划要和需求保持一致,并对需求的版本进行控制,避免同时出现多个需求版本的情况。在保证软件开发计划方面会有很多问题产生,例如进度、质量等。这时候,必须就变更和软件项目各小组达成共识,对软件项目计划作出调整,其中包括人员的安排、任务的安排、用户的沟通、成本的调整,进度的调整等。

        为了能够实现上面所阐述的过程,必须要将需求过程文档化,注意,是需求过程,包括了需求开发和需求管理两个方面。使用适当的Case工具也同样有利于管理工作的开展,按照我自己的经验,采用Office和命名准确的目录就已经足够胜任此工作了,但是如果要能够更高层次的使用Case工具,我建议使用关系数据库来管理你的需求。至于在工具方面,是各软件团体自身的情况而定。我相信,没有最好的工具,只有最适合的工具。

    变更控制

        记得还在大学的时候,和同学讨论一道知名软件企业的考题:如果客户要求你帮助他修改软件一项功能,你应该怎么做?正确的答案是要向你的项目经理报告。这里面就包含了变更控制的思想。在前面我们已经说过,易变是需求的一个特点,但是任何需求的变动都会对项目产生或多或少的影响,如推迟进度,增加人员等。如果没有对变更的控制,那么项目就会失去控制。我就见识过一个软件项目在经历了无数次的因需求变更导致的延期之后,发现改变的功能已经远远偏离了原先的需求定义。

        研究表明,扩展需求对百分之八十的管理信息系统项目和百分之七十的军事软件项目造成风险(Capers Jones 1994)。扩展需求是指在软件需求基线已经确定后又要增添新的功能或进行较大改动。问题不仅仅是需求变更本身,而是迟到的需求变更会对已进行的工作有较大的影响。具体的原因包括在软件系统中引入新功能往往会带来新的问题,新加入的需求和以前的需求有矛盾之处。

        由于需求的可变性,所以没有需求变更是不可能的,并不是说你的需求分析不够完整,业务过程、市场机会、竞争性的产品和软件技术在开发系统期间是可以变更,管理部门也会决定对项目做出一些调整。所以你在你的项目进度安排中一定要给需求变更留下余地,微软的开发方式中在每一个的里程碑(Milestone)间都预留了50%的时间,也是有这方面的理由。

        然而,这并不是说你要接受所有的要求,国内很多软件公司深得“客户就是上帝”的精髓,客户的所有要求都予以满足,这样做的结果往往就是开发人员疲惫不堪,质量得不到保证,项目延期,客户和软件团队双方的利益都受损失。学会对客户说“不”,当然,回绝必须要讲技巧,并不是一句“不行”就可以解决问题的。昨天我去买东西,我问售货员能不能便宜一点,她回答说:“不行,已经很便宜了!”。最后我就没有买,但是她如果换句话说:“对不起,我们的商品的质量都是特别好的,如果您下次再来的话,我们将给你优惠的价格”,我相信我会买下那个商品。所以说不要讲究技巧。客户的要求应该尽量满足,即时现阶段不行,也要向客户解释清楚,并在下一个版本中考虑客户的要求。

        对于需求变更的控制,保证成功的最主要的两点是将变更应用到整个开发链和记录历史变更。你可能需求一份变更控制文档来说明变更需求,大致需要说明的元素包括:

        概述:说明变更的大致内容,应用范围,对开发链的影响,总之让管理变更控制的人明白你的要求是什么。
        上下文:变更的需求在整体需求中的位置,如果需求是用用例表示的,指出他的父用例是什么。
        规模:根据开发进行的程度,指出实施变更需要付出的代价,这个代价是决定接受需求,通知客户项目延期,在下个迭代周期中实现变更的决定参考。
        提交人签字和所属开发组:决定了提交人所处的立场。

        一般来说接受需求变更提交的组织称为变更控制委员会(CCB 有时也称为结构控制委员会),该委员会的组成包括各开发小组的代表,以保证需求变更实施到整个开发链。CCB的工作流程大致是:

        接收到一新的变更要求后评估建议的技术可行性、代价、业务需求和资源限制。执行系统影响分析、风险分析、危害分析及其它评估。这些分析确保能很好理解接受变更所带来的潜在影响。同样也考虑拒绝变更所带来的对业务和技术的影响。

        CCB决定是采纳或还是拒绝请要的变更。给每个采纳的变更需求设定一个优先级或变更实现日期,或将它分配给指定的产品。CCB通过更新请求状态和通知所有涉及到的小组成员来传达变更决定。相关人员可能不得不改变工作产品,如软件需求规格说明文档、需求数据库、设计模型、用户界面部件、代码、测试文档、用户文档。修改者在必要时应更新涉及的工作产品。

        通过检查确保更新后的软件需求规格说明文档、使用实例文档、分析模型均正确反映变更的各个方面。使用跟踪能力信息找出受变更影响的系统的各个部分,然后验证他们实现了变更。属于多个小组的成员可能会通过对下游工作产品测试或检查工作来参与验证变更工作。验证后,修改者安装更新后的部分工作产品并通过调试使之能与其它部分正常工作。(摘自《软件需求》)

        最后,你需要记录变更记录,并建立需求变更跟踪矩阵来确保变更的实施。

    版本控制

        需求版本混乱造成的灾害主要体现在资源的浪费上面,很多软件团体中经常发生开发组花费时日改进了一项功能,却发现整项功能已经取消,发生错误原因是因为开发组没有拿到最新的需求。

        版本控制包括两个方面:保正人人得到的是最新的版本,记录需求的历史版本。

        如果有专门的需求管理商业工具可以助您一臂之力,由于我并没有条件试用所有的需求管理工具,能够向大家推荐的只有瑞理公司的RequisitePro,推荐的一个重要原因是它能够把需求和瑞理的其他工具如Rose、TeamTest等联系起来,从而实现需求链。

        能够借助工具将需求自动化固然很好,不过,工具使用不当也不会提高生产效率。需求管理的工具其实用简单的Office和任一个关系型数据库就可以解决,而且根据企业自身的特点,摸索出最适合企业用的工具。

        版本控制的最简单方法是在每一个公布的需求文档的版本应该包括一个修正版本的历史情况,即已做变更的内容、变更日期、变更人的姓名以及变更的原因并根据标准约定手工标记软件需求规格说明的每一次修改。

    需求链和需求跟踪

        如果你是一个开发人员,一天,市场部的小莉跑过来让你修改你正在开发产品的一个小小的功能,这是应客户的要求添加的,你觉得这个要求很简单,再加上你对小莉有好感,可能你就答应了她的要求。可是实际的情况是怎么样的呢?你会发现小小的修改并没有想象的那么简单,对这项产品的修改导致了进程的延误,最糟糕的是,由于这项修改没有传达到整个需求链,其他的开发人员那里由于你的修改出现了一些要命的错误。

        软件工程重视的是过程能力,如果不能严格的确保过程的每一个环节都被不择不扣的执行,软件过程就会不成功,我们都学过法律常识,都知道有法可依还不够,还必须有法必依,执法必严。遗憾的是,中国的软件组织对过程的严格执行并不是特别重视,上面的例子在各团体中都是很普遍的,这可能和中国人的思维方式有些关系,关于这一点,鲁迅先生在很早的时候已经讨论过了,我们就不用在此罗嗦了。

        需求链的概念指的是需求能够上传下达,从客户传达到需求过程,并从需求过程传达到需求过程的下游开发链。而这个传达是可以逆向的。





        需求跟踪提供了一个表明与合同或说明一致的方法。更进一步,需求跟踪可以改善产品质量,降低维护成本,而且很容易实现重用( Ramesh 1998)。

        在CMM三级中要求软件团体必须具备需求跟踪的能力:“在软件工作产品之间,维护一致性。工作产品包括软件计划,过程描述,分配需求,软件需求,软件设计,代码,测试计划,以及测试过程。”

        实际上,创建需求跟踪能力是困难的,尤其是在短期之内会造成开发成本的上升,虽然从长远来看可以减少软件生存期的费用,软件团体在实施这项能力的时候应循序渐进,逐步实施。

        需求跟踪的一种通用的方法是采用需求能力跟踪矩阵。它的前提条件是将在需求链中各个过程的元素加以编号,例如:需求的实例号,设计的实例号,编码的实例号,测试的实例号。他们的关系都是一对一和一对多的关系。通过编号,你可以使用数据库进行管理,需求的变化能够立刻体现在整条需求链的变化上。

        需求跟踪矩阵并没有规定的实现办法,每个团体注重的方面不同,所创建的需求跟踪矩阵也不同,只要能够保证需求链的一致性和状态的跟踪就达到目的了。
  • 请不要做浮躁的人

    2008-03-20 14:58:58

    1.不要看到别人的回复第一句话就说:给个代码吧!你应该想想为什么。当你自己想出来再参考别人的提示,你就知道自己和别人思路的差异。
    2.初学者请不要看太多太多的书那会误人子弟的,先找本系统的学,很多人用了很久都是只对部分功能熟悉而已,不系统还是不够的。
    3.看帮助,不要因为很难而自己是初学者所以就不看;帮助永远是最好的参考手册,虽然帮助的文字有时候很难看懂,总觉得不够直观。
    4.不要被对象、属性、方法等词汇所迷惑;最根本的是先了解最基础知识。
    5.不要放过任何一个看上去很简单的小问题--他们往往并不那么简单,或者可以引伸出很多知识点;不会举一反三你就永远学不会。
    6.知道一点东西,并不能说明你会写脚本,脚本是需要经验积累的。
    7.学脚本并不难,ASP、PHP等等也不过如此--难的是长期坚持实践和不遗余力的博览群书;
    8.看再多的书是学不全脚本的,要多实践
    9.把时髦的技术挂在嘴边,还不如把过时的技术记在心里;
    10.学习脚本最好的方法之一就是多练习;
    11.在任何时刻都不要认为自己手中的书已经足够了;
    12.看得懂的书,请仔细看;看不懂的书,请硬着头皮看;
    13.别指望看第一遍书就能记住和掌握什么——请看第二遍、第三遍;
    14.请把书上的例子亲手到电脑上实践,即使配套光盘中有源文件;
    15.把在书中看到的有意义的例子扩充;并将其切实的运用到自己的工作中;
    16.不要漏掉书中任何一个练习——请全部做完并记录下思路;
    17.当你用脚本到一半却发现自己用的方法很拙劣时,请不要马上停手;请尽快将余下的部分粗略的完成以保证这个代码的完整性,然后分析自己的错误并重新编写和工作。
    18.别心急,写脚本确实不容易;水平是在不断的实践中完善和发展的;
    19.每学到一个脚本难点的时候,尝试着对别人讲解这个知识点并让他理解----你能讲清楚才说明你真的理解了;
    20.记录下在和别人交流时发现的自己忽视或不理解的知识点;
    21.保存好你做过的所有的源文件----那是你最好的积累之一;
    22.对于网络,还是希望大家能多利用一下,很多问题不是非要到论坛来问的,首先你要学会自己找答案,比如google、百度都是很好的搜索引擎,你只要输入关键字就能找到很多相关资料,别老是等待别人给你希望,看的出你平时一定也很懒!
    23,到一个论坛,你学会去看以前的帖子,不要什么都不看就发帖子问,也许你的问题早就有人问过了,你再问,别人已经不想再重复了,做为初学者,谁也不希望自己的帖子没人回的。
    24,虽然不是打击初学者,但是这句话还是要说:论坛论坛,就是大家讨论的地方,如果你总期望有高手总无偿指点你,除非他是你亲戚!!讨论者,起码是水平相当的才有讨论的说法,如果水平真差距太远了,连基本操作都需要别人给解答,谁还跟你讨论呢。

    浮躁的人容易问:我到底该学什么;----别问,学就对了;
    浮躁的人容易问:xx测试有钱途吗;----建议你去抢银行;
    浮躁的人容易说:我要中文版!我英文不行!----不行?学呀!
    浮躁的人分两种:只观望而不学的人;只学而不坚持的人;
    浮躁的人永远不是一个高手
  • 在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以获得帮助。
  • TestDirector 8.0安装配置【转】

    2007-08-05 12:13:07

     

    1.       安装前环境配置

    TDWEB服务容器为IIS,必须得先安装IIS环境

    TD的后台数据库默认为Access以选择使用Sybase MS-SQL Server Oracle

    TD也支持邮件服务,可以选择安装邮件服务或则暂时不安装。如果需要安装则在安装前做好邮件服务器的相关配置。

    2.       安装事项

    在安装时,要对系统进行一些安装设置,以下对一些关键设置进行简单解释。

    1)数据库连接设置

    设置数据库连接时,Access为默认必选,可以选择另外一种合适的数据库做为TD的连接数据库,该数据库可以在创建TD项目时,选择作为项目的数据库。

    2)虚拟目录设置

    其中的虚拟目录名TDBIN下将保存TD的一些运行文件。

    3.       安装注意

    安装TD时,系统资源消耗比较大,容易造成安装失败或错误,所以在安装时,尽不要进行其他的系统操作,等待安装完成。

    4.       安装后配置

    1)  汉化

    在安装目录TDBIN/Install/下存放的是一些为连接服务的客户端加载的系统文件。其中的tdclientui80.xco文件,该文件会自动加载到客户端的C:\Program Files\Common Files\Mercury Interactive\TD2000_80目录下,并生成为tdclientui80.ocx文件。

    注意其中两个文件的后缀名区别。文件后缀可通过更改方式变换为OCXXCO

    由于Mercury并为发行官方的汉化包,所以采用第三方的资源包进行汉化。汉化方式,把得到的汉化资源dclientui80.xco文件粘贴到服务器TDBIN/Install/目录下,覆盖掉原文件即可。

    在之前访问过服务器的客户端,在下次连接时由于不再加载更新后的数据,所以必须得删除客户端下的C:\Program Files\Common Files\Mercury Interactive\TD2000_80目录下覆盖tdclientui80.ocx文件,使再次访问时自动加载汉化后的新组件。

    也可以通过在客户端C:\Program Files\Common Files\Mercury Interactive\TD2000_80目录下覆盖tdclientui80.ocx文件达到汉化的目的。

    2)  设置MS-SQL的数据库连接

    对数据库的“客户端网络实用工具”进行配置。选择协议Named PipesTCP/IP,别名设置最好选择本机计算机名。

    对数据库的安全性设置--身份验证,设置为SQL ServerWINDOWS

    设置后,在后台PING连接数据库,如果成功,则可正常创建该类数据库的项目。

    3)  IE7.0兼容性

    安装TD后,并不能顺利支持IE7.0的客户端浏览器。此时可以用记事本等打开服务器TDBIN/目录下的start_a.htm源文件,然后进行编辑。

    查找 var fMSIE3456

    然后在该行的末尾处分号前添加一段语句”|| (ua.lastIndexOf('MSIE 7.0') != -1)”

    保存即可。

    4TD系统信息修改

    C:\Program Files\Common Files\Mercury Interactive\目录中的DomsInfo文件夹,该文件夹中保存TD系统的关键信息,其中有TD系统配置信息的数据库doms.mdb文件,该数据库文件已默认被加密,密码为tdtdtd。在Templates文件夹中的文件为初始化生成的项目模板文件,包括TestDir.mdb,该文件为生成项目的初始数据库表。这样的话我们,就可以在每次创建项目时初试化出我们想要的,预定好的数据库表和相关数据来。就可以避免每次创建项目时重复的手工定义字段了,我们可以定制自己的项目数据库模板。

    如当遗忘ADMIN的密码时,可以通过往doms.mdbADMIN表中的ADMIN_PSWD字段更换写入“456711”,登陆时输入密码“test”即可进入。

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 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 语句进行调用时,括号被省略。

  • 收藏个链接,暂时还不熟悉空间的功能

    2007-07-18 14:34:26

  • 初次留抓儿

    2007-06-25 11:53:05

       很怕遗忘照顾个人空间,所以很少去申请开通!在这里看到好多很有价值的空间,于是没有抑制住对这里空间的狂热,遂顺了自己主观上的意愿,也希望自己能锁定技术论坛,不再花大把大把的时间在其它8卦的论坛上!

       给自己一点鼓励,尽量多在这里留下爬行的抓儿印!嘿嘿……

Open Toolbar