专注于自动化测试,性能测试.......

发布新日志

  • 推荐书籍《ApacheJMeter》(英文版)

    2011-02-21 17:18:21

      最近在学习Jmeter,在网上想查找一下讲解比较系统的资料或书籍,可惜资料比较少且都千篇一律,只能抱着Apache网站上的用户手册看了。书籍方面就更少了,只找到这本入门级的《ApacheJMeter》。很薄的一本书,也就130多页,大致的看了一下,讲的都很浅显,不过对于我这样的入门小白还是比较合适的,英文也比较简单易懂,英语不太好的也应该能看懂。具体内容我就不介绍了,大家可以去Amazon上看看简介。电子书籍在下面的附件中。

  • JMeter逻辑控制 之 Switch控制器(Switch Controller)

    2011-02-21 14:39:49

    Switch控制器

    Switch控制器通过给该控制器中的Value赋值,来指定运行哪个采样器。有两种赋值方式:

    1.第一种是数值,Switch控制器下的子节点从0开始计数,通过指定子节点所在的数值来确定执行哪个元素。

    2.第二种是直接指定子元素的名称,比如采样器的Name来进行匹配。当指定的名称不存在时,不执行任何元素。

    Value为空时,默认执行第1个子节点元素。

    控制面板

    参数:

    Name:控制器名称

    Switch Value: 指定需要运行的子元素的名称或所处的数值。

    示例:

    线程组的各参数都设置为1switch value中设置“Login.aspx”,运行测试计划,在“view results tree”中查看结果

    仅仅执行了Name为“Login.aspx”的Http请求。

  • JMeter逻辑控制 之 ForEach控制器

    2011-02-19 17:39:24

    ForEach控制器

     

             ForEach控制器在用户自定义变量中读取一系列相关的变量。该控制器下的采样器或控制器都会被执行一次或多次,每次读取不同的变量值。所以ForEach总是和User Defined Variables一起使用。下面会以实例的形式介绍它的用法。

     

    控制面板

      参数

    Name:控制器名称

    Comments:备注

    Input Variable Prefix:输入变量前缀

    Output variable name:输出变量名称

    Add”_”before number:输入变量名称中是否使用“_”进行间隔。

     

    示例:

     该示例中在ForEach控制器中添加了一个HTTp请求(登录页面),需要输入用户名,密码。我们这里把用户名作为变量在用户自定义变量中设置。

    User Parameter面板中设置

    ForEach控制器面板中设置:

    HTTP请求采样器面板中设置:

    这样执行测试计划时,ForEach控制器会遍历User Parameter查找符合设置条件的变量名,这里就是”Name”+”_”+”循环次数。查到符合的变量后就把值赋给输出变量(Vname)。然后就可以在ForEach控制器下的采样器或控制器中使用了,使用的格式是${输出变量名}

             运行测试计划,在“察看结果树”中就可以看到,每次请求使用了不同的参数。

  • JMeter逻辑控制 之 事务控制器(Transaction controller)

    2011-02-17 18:00:12

     事务控制器

     

    事务控制器会生成一个额外的采样器来测量其下测试元素的总体时间。值得注意的是,这个时间包含该控制器范围内的所有处理时间,而不仅仅是采样器的。

     

    对于Jmeter2.3以上的版本,有两种模式的操作

    • 事务采样器是添加到其下采样器后面的
    • 事务采样器是作为其下采样器的父采样器。

     

     生成的事务采样器的测量的时间包括其下采样器以及其他的一切时间。由于时钟频率的问题,这个时间可能略大于单个采样器的时间之和。时钟开始时间介于控制器记录开始时间与第一个采样器开始之间,时钟结束时间亦然。

     

     

     事务采样器只有在其子采样器都成功的情况下才显示成功。

     

    在父模式下,事务控制器下的各个采样器只有在the Tree View Listener里才能看到。同时,子采样器的数据也不会在CSV文件中显示,但是在XML文件中可以看到。

     

     控制面板

     

     

    参数

     

    Attribute

    Description

    Required

    Name

     

    事务控制器的名称

    Yes

    Generate Parent Sample

     

    如果点中,事务采样器作为其下采样器的父采样器,否则,作为额外采样器添加在子采样器的后面。

    Yes

     

     

    示例:

    其中线程组中设置1Users1 Loop


    1.
    Generate Parent Sample不选中情况下,Aggregate Report显示为

    其中事务采样器采集的数据排在子采样器数据之后,同时各列数据略大于子采样器数据之和。

     

    2. Generate Parent Sample选中情况下,Aggregate Report显示为

    其中仅显示事务采样器采集的数据,而不会显示子采样器采集的数据。

  • JMeter逻辑控制 之 包含控制器(Include controller)

    2011-02-16 17:21:50

    Include Controller 包含控制器

     

      包含控制器用于使用外部的Jmx文件。为了演示使用它,可以添加一个simple controller,然后在其中添加一个采样器(sample),比如一个http请求。然后把这个simple controller保存为一个jmx文件。这样在include controller中设置该jmx文件就可以在测试计划中使用了。值得注意的是,包含测试的测试计划中不能有线程组,仅仅只能有simple controller,然后其下可以添加任何采样器,控制器。

     

      如果用户需要使用cookie manage 或者 用户自定义变量,都应该在顶层的测试计划中设置,不应该包含在外部文件中,否则不会它们不会起作用。

    This element does not support variables/functions in the filename field.
    However, if the property includecontroller.prefix is defined, the contents are used to prefix the pathname.

     

    如果在prefix+filename的路径中找不到文件,控制器会尝试在JMX存放目录中根据文件名进行查找。

     

    控制面板

     

    参数

    Attribute

    Description

    Required

    Filename

    包含的文件

    Yes

  • WatiN自定义TextField对象

    2011-02-16 09:20:24

      今天遇到一个问题,Watin在运行过程中定位一个日期输入框时,无法找到该控件。报错信息为“ Could not find INPUT (hidden) or INPUT (password) or INPUT (text) or INPUT (textarea) or TEXTAREA element tag matching criteria”。

      该控件的Html代码为“<input type="calendar" mod_calendar_rangestart="#" mod_notice_tip="mm-dd-yyyy" mod="notice|calendar" name="depart_date" id="depart_date" class="pubglobal_input pubglobal_inputfix" style="color: gray;" autocomplete="off">”。经过查找原因,发现该控件的Type属性为自定义的“calendar”,而致使Watin无法查找到该控件。这样的话只能通过自定义一个calendar类,来继承TextField类来扩展发现该控件。具体做法如下:

    1.创建一个自定义的类,这里比如创建calendar类,继承于TextField类,代码如下:

     [ElementTag("input", InputType = "calendar", Index = 2)]
         public class calendar:TextField
        {
            public   calendar(DomContainer domContainer, ElementFinder finder):base( domContainer,  finder)
            { }
            public calendar(DomContainer domContainer, INativeElement element)
                : base(domContainer, element)
            { }

    2.然后就可以在测试代码中编写代码来定位到该类型的控件,代码如下:

      var depart_date = ie.ElementOfType<calendar>("depart_date");
                depart_date.TypeText("Feb-15-2011");

    这样就可以查找并定位到该控件了。这仅仅是针对“type=‘calendar’”类型的控件,同理如果type类型为别的类型也是通过类似的方法实现。

     

  • 了解性能测试-Part 2

    2010-09-24 22:36:12

    了解性能测试-Part 251Testing软件测试网,F/yh wQ6i

    OkMk R.LjM61753作者: Dale Perry

    Part 1V)v*dn k B @ V.wr0l61753
    • 测试过程中测试员的职责
    • 确定性能和商业目标
    • 如何把性能测试加入到开发过程

    Part 2

    _k qw i9M|61753
    • 系统架构和基础结构
    • 选择要运行的测试类型

    Part 351Testing软件测试网,yo e"` T!qgY

    • 了解负载(业务概况)
    • 测量的量化和界定

    Part 4

    Zgz-[^C v61753
    • 了解工具
    • 执行测试和报告结果

      本系列的第二部分,我将关注处理架构和基础设施的问题,选择合适的测试类型。本文的目标并不会涉及到所有的架构和基础设施,也不会涉及到所有的测试类型。但是会提供一般性的指导以帮助测试人员完成一份比较合理的性能测试报告。
     
    系统架构和基础设施

     
    架构和基础设施可能是致使软件性能测试失败最常见的原因。为了正确的测试一个系统或者应用程序,有几个关键的因素必须得到确保,至少也要提供相关有用的信息。

      
    我们将首先涉及有关物理架构的相关问题。这里有两个主要元素:1)应用程序和系统 2)软件运行所处的平台和网络

      
    如果部署的测试系统和生产环境(或目标环境)完全不同,那么测试就不能提供准确的性能数据。当我们涉及到系统的物理层,有几个关键的元素必须要阐述。

     
    系统的物理痕迹是很关键的。如果生产系统工作在一个多服务器集群,而测试环境是一个单服务器(没有服务器集群),由于可测量性因素(scalability factor),测试可能是没有价值的。可测量性因素是测试环境设备与生产环境设备的比例。一些人认为101的比例是可以接受的,但是我发现一旦比例超过51,就无法确保架构和基础设施的真实性。
    1展示一个3:1比例模型

     

    Figure 1



     
    这可能是一个合理的数字,但是它们并不是一定契合生产环境的保证。在上图中我们漏掉了一个关键因素,在服务器集群中,你需要构建负载平衡。测试环境配置中没有这个因素。生产环境中的负载均衡是个瓶颈,因为所有事务都必须通过它来到达各自服务器。

    除了物理层的可测量性问题外,我们也不得不检查每个平台的内部特性,以包含在测试中。

    Production

    Test Lab

    Three servers per function

    One server per function

    DB server

    DB server

    10CPU, 20GB memory

    2CPU, 10GB memory

    APP server

    APP server

    20CPU, 10GB memory

    2CPU, 10GB memory

    Web server

    Web server

    5CPU, 10GB memory

    2CPU, 10GB memory

    Has a load balancer

    Has no load balancer

     

    Figure 2




       上述模型在测试实验室是31,然而,在如下领域是有可疑的。它们之所以被怀疑是因为以下元素。第一部分描述一个系统和产品。第二个部分描述测试系统。他们在规模上是大大不同的。

    • 生产环境的DB服务器是10 CPU20GB内存
      • 相当于1CPU对应2GB内存
    • 测试环境的DB服务器是2CPU分享10GB内存
      • 每个CPU5GB内存
    • 生产环境的APP服务器是20CPU分享10GB内存
      • 相当于1CPU对应0.5GB内存
    • 测试环境的APP服务器有2CPU分享10GB内存
      • 每个CPU5GB内存
    • 生产环境的Web服务器是5CPU分享10GB内存
      • 相当于1CPU对应2GB内存
    • 测试环境的Web服务器是2CPU分享10GB内存
      • 每个CPU5GB内存


     
    架构的内部差异可能使测试环境产生或隐藏的问题而在生产系统中不会出现。如果你因为出现在测试环境下的问题而对系统或架构进行调整的话,你可能已经犯下了致命的错误并带到了生产系统中。

      确认架构和设施模型尤其是具有风险的。一些关系数据库的功能在不同的比例模型下的表现是有很大不同的。有很多方面需要调查:

    • 驱动器的数量和大小
      • 分发表和数据驱动器
      • 表中的混合数据
    • 索引,关键字,信号量的使用,等等
    • 数据库管理系统的使用
      • 参照完整性,存储过程
    • 连接类型
      • SANNAS,直接地
    • 物理属性
      • RAID, Mirrored, etc.
      • 被其它应用程序分享



     
    当评估基础设施相关的物理层和可测量行问题时,我们也需要考虑某些要素的性质。一些机构中的元素是非线性的。拥有相等数量的资源不一定获得相应的性能。

     
    查看系统中的CPU使用情况。如果单处理器可以支持100用户,这样的话,是否再加一个处理器就可以支持200用户?不是这样的,这是不会发生的。两个处理器还要消耗部分能力用于处理它们之间的交互。添加第三个处理器可以进一步增加处理用户的数量,但同时降低效率。最后添加另外的处理器可能造成负面影响,进一步减少所支持的用户数量。
    一个简单的CPU可扩展性的例子如下:

    Figure 3




    下面介绍架构和基础设施的最后一个元素 网络。 网络是一个类似管道系统的复杂的系统。小管道连接到大管道,大管道连接到更大的管道。信息从小管道流向大管道然后再返回。甚至可能你有一些控制点(阀门?)来管理流向。
    How does the network in the test lab compare to the production environment? As with every aspect of the architecture and infrastructure, there are several key issues that need to be addressed, as shown in figure 4.

      测试环境的网络如何与生产环境的进行比较呢?有几个关键的问题需要解决,如下:

    网络类型和配置

    • LAN, WAN, Internet, 等等.
    • 单独的或者共享的网络?

    物理元素数量

    • Bridges, routers, gateways, etc.
    • Non-application elements (firewalls, etc.)

    带宽配置

    • Star
    • Bus
    • Ring
    • Hub or switched
    • Etc.

     

    Figure 4



    有两个途径评判系统和应用程序的可扩展性:

    • 当前架构缩放比例(规划方面的能力)
      • 测试瓶颈是为了防止系统处理过大的工作量
      • 测试系统的功能和特性被忽视,但是它会随着系统的增长而变得重要。
    • 一旦当前系统达到有效容量,架构要自我调整。
      • 为了执行测试,需要额外的架构和设施


     
    由于各种类型的数据需要相当数量的架构和设施来模拟真实的目标环境(还有支持负载生成工具的环境),大多数组织不能承受这些费用,这使我们又想到了外推法。

     
    外推法是一种趋势预测的方法。随着被测试系统的负载逐步递增,数据库或网络也呈现相当的递增级数。性能测试团队根据绘制的趋势图表

     
    问题是这种方法准确吗? 外推法本质上是一种系统功能的线性推测。正如我们早期关注的可扩展问题,系统和应用程序在很多关键方面的趋势并不是线性的。

    如果你的环境不是很均衡的,预测将会更加不准确。

     
    当这种技术应用到复杂的系统或应用程序时具有很大的潜在隐患。所以最好在可行且存在的架构或者设施中进行测试,而不是靠推测。

      外推法可以应用到很有限的情况下。如果性能只是关注单一组件或者系统方面。

    而且该部分具有线性特性,只有这样该方法才能应用。

    • 举例来说,评估数据库一系列事务消耗空间数量是一个线性行为。数据的分散可能或可能不使用线性算法。如果只关注磁盘的使用情况,那么每个事务消耗的存储空间是有具体数量的。

    正如我们所见,架构和设施需要的性能测试是非常难以确定和管理的。甚至还有很多问题这里都没有涉及到,如果在测试实验室中测试系统失败了,在生产环境中也可能失败。

    选择测试类型

      
    当在确定哪种性能测试类型之前,我们必须首先知道我们需要解决什么问题。一旦你知道测试的总体目标和对问题有充分的来哦接,你就可以选择一个测试或者一系列的测试去审查那些问题。

    通常地,我盟把性能测试分为3种普遍的类型:

    • 基于负载源或类型的测试
    • 基于我们想测量什么(测量目的)的测试
    • 测试系统压力或发现瓶颈

    上述列出的这些分类都有多种子分类和变种。我不会尝试去涉及每个可能的变种,但是会关注每个类型的子分类。那些测试可以回答我们在本系列之前部分讨论的大多数问题。下面让我们来看看具体内容。

    大部分性能测试是由一种或多种测试类型(一个或多个分类)组成的。

    基于负载源或类型的测试

    • 基于使用的测试:根据业务概况,在测试环境下以同样的方式实际运行系统。
      • 用户场景:一系列真实的活动,取决于用户如何实际操作系统。功能测试人员使用标准测试用例设计技术设计常规测试。就如边界值法,一个功能对应一个测试用例。这常常用在各个事务之间有复杂的交互的场景。
    • 基准测试:使用标准的工作量,而不是用户指定的,当很难确定系统实际上如何被使用时,大多数的商业基准通过TPC.org公布。
    • 负载变化和活力测试: 在模拟的真实环境中,观察负载在一段时间内的变化,以及相应的各种性能指标的变化。模拟系统需要在早期部署好。
    • 可扩展性测试: 通过增加每个用户的工作量,并发用户数量,数据库的大小,连接到网络设备的数量等等,考察系统增长能力(能否适应这些增长)
      • 正如我们之间提到的,有两种可扩展类型。在当前架构和基础设施达到满负荷下扩展;自行的扩展架构和基础设备。
    • 特定组件测试:考察性能和系统组件的健壮性。在被测组件准备好就可以进行测试,不必等其它组件。
    • 校准测试: 检查系统是否符合委托的标准。

    基于测量目的的测试

    • 响应时间测试:测量系统完成一个或一组任务的时间
      • 响应时间通常关注使用者和客户的感受。
      • 一些响应时间测试可能是由组件和SLA驱动的,比如测试第三方接口(比如电子商务程序的信用卡处理过程)
    • 吞吐量测试:测量一个单元的吞吐量,比如系统中一个点会通过多少流量,在指定的时间內或者指定的压力下完成多少任务。
    • 可用性测试:记录系统或组件运行时间的百分比
      • 一个通用的行业参考,被称为5个九 – 99.999%。这是一个可用性和可靠性都相当高的水准。
    • 资源利用测试:监视系统资源使用的情况,如内存,CPU,线程等等。
    • 出错率测试:有些地方也称为“健壮性”。测量当系统处于正常或过重负载情况下的功能出错率。还有当负载增加或者改变时可能引起错误的增加。
      • 系统和应用程序是否可以处理错误的增加?如果用户不能使用功能,再快的响应和再大的吞吐量也是没用的。

    测试系统压力或者发现瓶颈

    • 斜坡式测试:对于这个概念有几个解释。
      • 测量启动进程所需的时间。
        • 比方说,一个未工作的网络设备在需要它工作而被启动时,它必须在50毫秒内开始工作。
      • 术语斜坡式测试也可以被解释:在系统开始运转期间, 逐渐地增加测试负载而不是突然增加到最大负载以避免系统崩溃。
        • 在极端情况下,可能出现在系统上的活动突然激增。这方面的一个例子是如果用户尝试登录崩溃后重新回复的系统,突然增加的活动可能再次导致系统崩溃。
    • 持续和耐力测试:有人把这个当作可靠性测试的一部分。在测试环境下持续运行被测系统一段时间(几天或者几周),这样可以用来发现那些需要运行长时间才会出现的bug,比如内存泄漏。这对于那些不间断的系统特别重要,比如电子商务系统或自动柜员机。
    • 热点测试:关注系统中指定的,有限的一部分以确定该部分是否是个薄弱点。
      • 在一个应用程序的通常部分也能可能进行该类型测试。比如,待电子商务网站出售特殊时刻的礼品。可以预见在节假日会出现蜂拥而至的交易。然而目标系统应对这种情况是非常困难的。在母亲节,整个网站都处于活跃状态,但是在情人节,大多数活动都集中在单个产品区域(长茎红玫瑰和巧克力)。我们就可以在这些点设立“热点”进行测试。
    • 钉子测试:在非常短的时间内使系统处于高负荷的工作状况下,用于确定系统如何处理突然增加的高负载需求。此测试用以验证系统能够应对快速的重大变化以及改变资源的使用。比如,使用负载均衡。
      • 这种测试类型的有效性取决于被测系统的类型
        • 主机,局域网/广域网和局域网类型的程序对连接到系统中的设备数量只有相当有限的潜力。
        • Web 和 基于局域网应用程序拥有几乎无穷尽访问的可能。某些安全攻击,拒绝服务攻击和分布式拒绝服务攻击是极端的由黑客引起负荷的例子。
    • 断点或故障测试:增加负载直到系统出现故障或达到测试环境负荷极限。它也许不可能生成足够的负载以使系统发生崩溃,取决于负载生成的用户(授权的数量是个关键因素)
      • 这个测试对于验证系统工程师是否已经对系统进行了安全设置有帮助,比如应用程序阀值。这些内在的控制可以防止应用程序或系统发生崩溃。
    • 死锁测试:运行高容量测试(可能来自不同应用程序源)来发现系统中是否存在资源竞争,比如多请求试图同时访问同一数据库,并造成由于区域冲突而被系统锁定用户请求,比如数据库记录锁定。
    • 运行退化模式测试:在不是所有资源在工作的情况下,确定系统是否仍能提供预期的服务水准。(一个降级模式测试的例子是在服务器集群中故意断电一台服务器,并试图继续正常操作。)

    使用哪种类型的测试取决于早期确定的性能目标和潜在问题存在于应用程序,系统或者架构中的位置。测试的压力类型通常与测量类型结合。我们使用业务跟踪(在本系列第三部分介绍)来创建我们需要的应用程序或系统的活动类型,进而评估出那些我们感兴趣的区域。

    如果我们对以用户的角度看端对端的响应时间感兴趣,我们应该运行基于使用的测试并结合测量类型。(测量CPU,内存使用,线程等等)。当我们不知道问题将发生的位置时,我们需要结合几种测试类型。如果我们发现响应时间的异常,我们需要采取措施帮助性能测试团队的技术人员定位和解决问题。

     
    我们已经了解性能测试过程,性能目标,以及已经涉及了架构和基础设施问题,我们需要关注测试的内容。在本系列的下一部分,我将介绍确定负载(操作跟踪) 和 测试中的测量。

    原文地址:http://www.stickyminds.com/sitewide.asp?Function=edetail&ObjectType=COL&ObjectId=14891&tth=DYN&tt=siteemail&iDyn=2

    `!@*H5Z Ae2E.C61753

      本文章由本人翻译供大家学习之用,版权归原作者所有。原作者如有任何异议,请通知本人删除,且未经书面授权许可,任何网站或个人不得转载。另由于本人翻译水平有限,很多不当之处请见谅。

  • 了解性能测试-Part 1

    2010-09-22 09:27:06

    了解性能测试-Part 1

    作者: Dale Perry
       多数软件性能测试项目失败,这里我所说的失败,并不是意味着测试不正常的终止,而是不能给需求方提供任何有用的信息。

      
    引起失败的原因有很多。在这个系列的文章中,我将讲述性能测试中出现的基本问题和如何去避免他,你将理解很多问题以及你能不能解决它们。本系列并不能涉及到所有问题,也不适合于高级性能测试工程师。希望大多数读者可以学到如何从失败中找到解决的方法。
     
    本系列文章中将涵括以下几个方面的内容:
    Part 1

    • 测试过程中测试员的职责
    • 确定性能和商业目标
    • 如何把性能测试加入到开发过程

    Part 2

    • 系统架构和基础结构
    • 选择要运行的测试类型

    Part 3

    • 了解负载(业务概况)
    • 测量的量化和界定

    Part 4

    • 了解工具
    • 执行测试和报告结果


    以上这些内容可以按照很多不同的次序讲述。但我将按照我认为最有效的次序进行阐述。这种方法已经被应用到各种类型的平台:大型机,C/S,嵌入式,web等等。 第一部分讲述测试者的职责,了解性能目标以及如何使性能测试适合开发过程。
    测试者的职责


     
    在性能测试中,性能测试员很像一个顾问,你指导和协助技术人员识别和改正问题。性能测试员进行测试,并不改正,调试或者关闭发现的问题。成功的性能测试是团队共同努力的结果。任何关键的成员都可能不得不条则会调整,修复,调试系统或应用程序,做出对实现性能目标有益的事情。
     

    完整的性能测试团队应该包含如下关键成员:

    •  测试/质保团队
    •  用户/顾客
    •  经理
    •  市场销售人员
    •  开发全体人员
    •  网络管理员
    •  系统管理员
    •  安全管理员

     没有尽早的使关键人员加入到测试过程中,几乎一定会有问题在后面被提出。促使关键人员尽早的加入到性能测试计划可以确保减少后面出现问题,尤其是在测试结果不是太好的时候。

     

     验证性能和商业目标.
    接下来,我们需要明确验证的目标和性能测试的目的。人们在性能测试中最好犯的一个错误是思考的全是他们需要的性能测试工具(我们将在第四部分讨论工具)。当然工具是必不可少的,工具提供了解决问题的答案。但是在此之前,你需要知道问题是什么。不知道哪些性能问题需要你解决,就很难鉴定你的性能测试是成功还是失败。
      
    我经常被问到的第一个问题是“我如何分析工具产生的测试结果?”。我的回答是“你希望你的工具做些什么?”。大多数人不能回答这个问题。这是第一个指标指示你的性能测试可能是没有什么价值的。
      
    大多数情况,测试员从经理那里获取整体的指导。然而,经理倾向于关注投资效益和用户满意度,但是那些都不是性能指标。不了解性能测试项目目标和目的,即使工具带给你的大量信息,你也无法解释,乃至达到经理的预期。
      
    收集和确定性能测试目标可能是整个性能测试过程中最枯燥的部分。然而,时间会告诉你有些事情必须在前期就要做。如果你不能获取你需要的性能指标,进行性能测试是没有任何意义的。
     
    了解性能指标的第一步就是把它们从商业目标中分离出来。如下图1

    1:从商业目的中分离出性能指标

     
    为了达到软件性能指标,有一些系统或者应用程序的指标是需要我们在测试过程中去度量的。糟糕的性能表现通常是在压力或者即将到达最大容量的时候发生的。如果你不能设计这些方面的测试,那么就不能算是完成任务。下面是一些问题,这些问题对于确定性能目标与测试目标的异同点是很有好处的:

    • 我将执行什么测试?
    • 我将收集哪些数据?
      • 为了度量“ 性能”,你必须收集系统和应用程序运行时的相关信息
    • 我如何证明目标已经实现?
      • 我测量什么才能证明制定目标或目的已经达到?


    “性能”定义是在给定的环境下的行为表现。比如你评审一个用户的效率。没有系统指标给你去测量以证明哪个用户效率更高。


    如何使性能测试融入到开发过程

    很多人把性能测试看作产品在交给客户之前才要做的最后一件事。这既是错误的也是危险的。图2显示了性能测试的通用做法。它依赖于一个完整的系统或者应用程序。


    2:性能测试的一般做法

    使用这个方法的主要问题是:如果有问题产生而要做需求变更时可能要重新测试变更对功能的影响。这时重点需要注意的是同一时间超过一个功能变更就将很难协调。多个技术团队将问题变得复杂且难于协调。也有可能产生模糊不清的解决方案。同时调整数据库和程序代码可能会出现彼此覆盖的情况。因此,很多团队是使用一次一个的方法(OFAT

    遗憾的是,OFAT在如下的情况下并不能很好的工作:

    • OFAT假设元素是彼此孤立的
    • 有很多复杂的,难于理解和隐藏的依赖关系
    • OFAT花费时间太长
    • 其它方法很难很好的应用

    举例来说,一旦问题被“fixed”并重新进行测试,我们可能发现新的关于网络或程序的问题而不得不去“fixed”。而这可能又产生更多的问题。这可能最终成为死循环,周而复始。
      
    是的,性能测试需要一个稳定的环境和软件。然而,这并不意味着所有功能都要是完整的。可以使用预防性思维(静态测试)和增量迭代开发方法,在有几个稳定可用功能的情况下也可以进行性能测试。
      
    增量和迭代开发模式给尽早的执行性能测试提供了便利。通过在开发过程早期确定性能问题,就有很多机会在解决问题成本提高之前去改正设计和架构


    3:增量和迭代开发过程中允许早期进行性能测试

    一旦第一个build版本的功能测试结束,在开发团队继续开发下一个迭代时性能团队就可以开始测试了。这样做有两个好处:基本架构得到了尽早的测试,由于只是局限于一个完整的功能,修改架构和设计的代价也很小。缺点是协调开发团队和性能测试团队比较复杂。


    http://www.stickyminds.com/BetterSoftware/image_uploads/webobject_image_no584.JPG 如下列出开发过程早期可能通过静态方法发现的在网络,应用程序以及数据库中存在的问题
       
    网络问题:

    • IP连接和HTTP的使用情况
    • 过度的使用安全功能
    • 负载均衡的类型和特征
    • 应用程序服务器与数据库服务器之间的交互
    • 包的大小(应用程序网络规模的大小)
    • 连接池和连接共享
    • 服务器在网络中的位置
    • 增加的延迟

    应用程序问题:

    • 过多的内存分配和取消分配
    • 不正确的任务初始化和管理
    • 不正确的垃圾收集,特别是产生失败或故障之后
    • 缓存丢失或者缓存存在太久
    • 持久性应用,比如黑莓设备
    • 应用程序配置参数冲突
    • 高资源消耗的功能(CAD/CAM,等等)

    数据库问题:

    • 索引设计
    • 动态索引的使用
    • 锁定连接中可能存在的死锁
    • 使用效率低的缓存
    • 过度使用的缓存
    • 使用资源集中的功能,比如参照完整性
    • 存储过程和触发事件的使用
    • 表碎片(第三范式过度使用)
    • 不正确的时间表和索引重组


    如果你能在他们系统设计之前发现性能问题,他们将节约很多的钱去做正确的事情。诚然,这将减缓项目进度用以整治和改正需求或者设计。然而,项目后期做设计修改将对项目有更大的影响,而且重新设计还要承受影响项目进度的风险。

    无论选择哪种方法,性能测试的设计和分析活动都必须从需求阶段就开始。等待太久对于性能测试团队就意味着灾难。测试者是性能专家的眼睛和耳朵(典型的是系统管理员,数据库管理员,网络工程师,和开发人员)

    由于性能测试的复杂性,需要大量的资源。有些公司会外包一些或全部的测试工作。通常情况下,会外包那些与业务知识关联不大的而不是那些需要精通公司业务的测试者参与的测试工作(比如性能测试)

    专注于性能测试的公司具有很多重要的技术。但是,除非你有妥善的计划,否则不要指望外包测试。外包测试者需要做同你一样的任务,而且他们要从你那获取信息。这相当于你付钱让别人告诉你已经知道的答案。如果你请昂贵的专家帮助你解决性能问题,确保在他们抵达之前你已经准备好初步的性能测试脚本。这可以节省大量昂贵的“闲暇”时间。

    如果性能测试是远程的,而且应用程序或者系统在开发或测试以及处在组织的防火墙下,要进行可行性测试以确保远程测试员可以通过防火墙访问被测试系统。

    大多数的外包承包商可以分为以下一个或多个类型:

    • 现场顾问 顾问在客户的县城工作
    • 远程顾问 顾问在他们自己地方工作,系统或者应用程序位于客户端。
    • 测试实验室 应用程序或系统处于远程测试的位置,在那儿顾问可以安装和测试他们
    • 应用服务提供商或管理服务供应商 - 内部工作人员利用硬件和软件托管在第三方的位置测试他们部署在自己站点的应用程序或系统。

    了解关于性能测试各种作用以及把性能测试尽早得整合到开发过程中是测试成功的关键。如果你没有把握关键和尽早的开始计划,成功地几率是很低的。一旦那些关键问题处于可控状态,我们就可以开始分析问题,设计一套必要的性能测试。在本系列的下一部分,我将把问题通架构和基础结构结合起来,从而确定需要进行的性能测试类型。

    原文地址:http://www.stickyminds.com/BetterSoftware/magazine.asp?fn=cifea&id=118

      本文章由本人翻译供大家学习之用,版权归原作者所有。原作者如有任何异议,请通知本人删除,且未经书面授权许可,任何网站或个人不得转载。

     
  • Watin系列文章暂时告一段落,新的起点开始了

    2010-09-16 10:49:52

      之前花了几天的时间对Watin相关的知识进行了一些梳理,内容还是显得很粗糙的。原本按照我的设想,应该还有几篇文章需要写的。比如 Watin如何处理Ajax网站,如何实现Watin的数据驱动测试,Watin的一些FAQ等等。
      通过写这些文章的时候,我发现了自己很多的不足。特别是对Web开发相关知识的匮乏。只要是做Web测试,web开发相关知识是绕不开的,HTML,CSS,javascript,Ajax这些知识都需要去学习。所以接下来一段时间要静下心好好学习一下这些知识,希望通过这次学习可以对web开发,web测试有更深层次的了解。我也会不定时的写一些学习笔记与大家共享。同时也意识到英语在测试工作中的重要性,接下来也会陆续翻译一些英文的测试文章,希望可以提高一下自己的英文水平.
  • Watin系列之六 Watin与Httpwatch工具结合进行测试

    2010-09-14 23:41:01

    概述

       Httpwatch是一款强大的网页数据分析工具,安装后集成在IEFirefox工具栏中。它可以在不改变浏览器和网络设置的基础上捕捉HttpHttps数据。查看底层的HTTP数据,包括headers,cookies,cache等等,同时统计发送接收请求的时间,并提供完备的日志记录系统。同时该款工具具有完备的COM接口,用于给用户通过编程的方式操纵httpwatch

    Httpwatch自动化对象介绍

     Httpwatch自动化对象的结构如下:

    Controller

      Controller类总是控制的起点,它用于创建Httpwatch插件接口或者读取log文件,通过IE属性和Firefox属性的new()方法或者Attch()方法返回Plugin实例对象

    Plugin

      Plugin类是Httpwatch与浏览器交互的接口。它提供了方法用于开始和停止http流量的记录。还有很多方法和属性用于管理Httpwatch的日志文件和配置自动化记录。

    Log

      Plugin对象的Log属性是Log对象的入口。它包含了一系列通过Httpwatch记录的日志。Log对象中具有很多重要的类,比如Pages,Entries类。

     

    Entry

    每个Log对象都包含一组Entry对象,它代表的是单个HTTP事务的详情。(比如http请求)

    后面我们会通过实例来进一步说明该类的方法和属性。

     

    通过把WatinHttpwatch结合进行自动化测试,可以很大程度的扩展自动化测试的范围,比如在自动化测试过程中验证链接的连通性,网页传输的速率和时间,查看网页的详细信息等等。


    使用C#操作Httpwatch

      使用C#操纵httpwatch大致分为以下几个步骤:

    1)  添加HTTPwath 自动化类库到你的项目中

    2)  创建与Httpwatch工具的联系

    创建新的IE接口

    HttpWatch.Controller controller = new HttpWatch.Controller();

    HttpWatch.Plugin plugin = controller.IE.New();

    创建新的Firefox接口

    HttpWatch.Controller controller = new HttpWatch.Controller();

    HttpWatch.Plugin plugin = controller.Firefox.New("");

    附加一个已存在的IE窗口

    SHDocVw.IWebBrowser2 ieBrowser = new SHDocVw.InternetExplorer();

    ieBrowser.Visible = true;    // Required to see the new window

     . . .

    HttpWatch.Controller controller = new HttpWatch.Controller();

    HttpWatch.Plugin plugin = controller.IE.Attach(ieBrowser);

    附加一个已存在的Firefox窗口

    HttpWatch.Controller controller = new HttpWatch.Controller();

    HttpWatch.Plugin plugin = controller.Firefox.Attach("FirefoxProfileName");

     

    3)  通过接口读取HTTP详细信息

    plugin.Log.Save("E:\\baidu.hwl");

    foreach (HttpWatch.Page page in plugin.Log.Pages)

    {

    Console.WriteLine(page.Title);//输出网页的标题

    }

     

    WatinHttpwatch结合

      我们依然以访问百度网站为例,并进行查询操作.最后输出访问过程中HTTP请求各个资源的时间和状态。我们可以加入判断,判断哪些请求的状态有异常,哪些请求的时间过长。(请使用IE6,IE7好像有些问题)具体代码如下:

     

     using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using WatiN.Core;

    namespace ConsoleApplication1
    {
        class Program
        {
            [STAThread]
            static void Main(string[] args)
            {
                //新建IE实例
                IE ie = new IE();
                //建立Httpwatch控制类
                HttpWatch.Controller controller = new HttpWatch.Controller();
                //将ie实例附加到Httpwatch接口,从而使Watin和httpwatch与同一IE建立关联
                HttpWatch.Plugin plugin = controller.IE.Attach((SHDocVw.IWebBrowser2)ie.InternetExplorer);
                //Httpwatch开始记录
                plugin.Clear();
                plugin.Record();
                //导航到百度
                ie.GoTo("www.baidu.com");
                //搜索“watin”
                ie.TextField(Find.ById("kw")).TypeText("Watin");
                ie.Button(Find.ById("su")).Click();
                //停止httpwatch记录
                plugin.Stop();
                //创建Log实例
                HttpWatch.Log log = plugin.Log;
                //输出请求异常的url
                Console.WriteLine("请求异常的地址:");
                foreach (HttpWatch.Page page in log.Pages)
                {
                   
                    Console.WriteLine("------------"+page.Title+"--------------");
                    foreach (HttpWatch.Entry entry in page.Entries)
                    {
                        if (entry.Result != "200" & entry.Result != "(Cache)")
                        {
                            Console.WriteLine(entry.URL + " : " + entry.Result);
                        }
                    }
                   
                }
                Console.WriteLine("\r\n\r\n");
                //输出请求超过0.1s的url
                Console.WriteLine("请求超过0.1s的地址:");
                foreach (HttpWatch.Page page in log.Pages)
                {
                   
                    Console.WriteLine("------------" + page.Title + "--------------");
                    foreach (HttpWatch.Entry entry in page.Entries)
                    {
                        if (entry.Time > 0.1)
                        {
                            Console.WriteLine(entry.URL + " : " + entry.Time + "s");
                        }
                    }
                }

                Console.ReadLine();
            }
        }
    }

    结果显示如下:

     

    结束语

     我在本篇文章中只是列举了httpwatch的一些简单应用,有对http信息分析有更深入需求的可以参考HttpWatch Automation Reference ,进一步了解httpwatch的自动化对象。

     

    资源及资源

    1.       Httpwatch官网

    2.       Using HttpWatch with WatiN

  • WatiN系列之五 Watin与Nunit结合进行测试

    2010-09-12 10:12:37

    概述

      上篇文章中介绍了在VSTS中如何使用watin。本篇文章介绍如何在NUnit中使用Watin

    Nunit作为一款老牌的单元测试工具,在开发人员中得到广泛的应用。

     

    准备工作

      在开始介绍如何在Nunit中使用Watin之前,需要做一些准备工作。

    l  下载及安装NUnit

    l  创建演示Web程序

    l  创建及配置测试程序

      下载及安装Nunit

        NUnit官方站点下载Window Installer

      创建演示Web程序

    我们将创建一个ASP.NET网站,接下来的测试代码将是针对这个简单Web站点的。先创建一个新项目。

    接下来在解决方案中创建业务逻辑层的类库BusinessLayer,其中添加一个类Arithmetic,用于一些算术操作。

    创建及配置测试程序

    然后在解决方案中创建一个新的类库WebAppUITesting,这个就是测试程序。

    在类库WebAppUITesting中添加应用配置文件App.config,内容如下:

    <?xml version="1.0" encoding="utf-8" ?>

    <configuration>

      <configSections>

        <sectionGroup name="NUnit">

          <section name="TestRunner" type="System.Configuration.NameValueSectionHandler"/>

        </sectionGroup>

      </configSections>

      <NUnit>

        <TestRunner>

          <!-- Valid values are STA,MTA. Others ignored. -->

          <add key="ApartmentState" value="STA" />

        </TestRunner>

      </NUnit>

    </configuration>

     备注:Watin只能在STA下运行,Nunit确是在MTA下运行的。所以直接在Nunit中运行watin代码会报错,所以为了解决这个问题,在测试程序中加入App.config配置文件可以解决这个问题。

     

    在类库WebAppUITesting中添加引用

    然后右键点击该类库,在右键菜单中选择“属性”,在属性->调试面板中,“启动外部程序”设置为Nunit.exe。这样在调试代码后会自动打开Nunit

    最后解决方案的目录结构如下:

    编写测试程序,运行测试

     准备工作完成之后,把生成的被测试演示Web程序(WebApp)部署到IIS中,当然你也可以使用VS中自带的web服务器。Web页如下

     这个站点的功能很简单,就是输入两个数字,然后提交后返回相加的结果。

    然后我们就可以编写针对这个站点功能的测试代码了。我们主要编写测试用例。

     用例一 输入两个数字,验证加法是否正确

    用例二 输入非数字字符,验证异常处理是否正确

    测试代码如下:

    using System.Diagnostics;

    using WatiN.Core;

    using NUnit.Framework;

    using System;

    using BusinessLayer;

    namespace WebAppUITesting

    {

        [TestFixture]

        public class UITesting

        {

            IE ie=null;

            [TestFixtureSetUp]

            public void InitTest()

            {

                ie = new IE("http://localhost/WebApp/Default.aspx");

            }

            //测试加法

            [Test]

            public void AdditionTest()

            {

                    int number1 = 1;

                    int number2 = 2;

                    //Watin测试代码

                    ie.ShowWindow(NativeMethods.WindowShowStyle.Maximize); 

                    ie.TextField(Find.ById("num1")).TypeText(number1.ToString());

                    ie.TextField(Find.ById("num2")).TypeText(number2.ToString());

                    ie.Button(Find.ById("btnCheck")).Click();                              

                    //预期结果

                    Arithmetic ac = new Arithmetic();

                    string expected =  ac.addition(number1,number2).ToString();

                    //实际结果

                    string actual = ie.Span(Find.ById("lblResult")).Text;

                    //断言测试结果是否正确

                    Assert.AreEqual(expected,actual);        

            }

            //测试异常处理

            [Test]

            public void ExceptionTest()

            {

                //Watin测试代码

                ie.TextField(Find.ById("num1")).TypeText("A");

                ie.TextField(Find.ById("num2")).TypeText("1");

                ie.Button(Find.ById("btnCheck")).Click();

                //预期结果

                string expected = "输入字符格式不正确!";

                //实际结果

                string actual = ie.Span(Find.ById("lblResult")).Text;

                //断言测试结果是否正确

                Assert.AreEqual(expected, actual);

            }

            [TestFixtureTearDown]

            public void ClearTest()

            {

                ie.Close();

            }

        }

    }

     

    测试结果如下:

    结束语

      Nunit中使用Watin测试思路就是这样的。如果有兴趣的话可以自己动手试试看,这是学习的最佳途径。也可以下载附件中的代码进行学习。

  • Watin系列之四 Watin与VSTS单元测试工具结合

    2010-09-10 17:20:30

       概述

    Watin是做一个UI自动化测试工具进行开发的而非单元测试工具。但并不意味着单元测试中不可以使用Watin。有时候作为纯粹单元测试的补充,适当的UI测试也是必要的。在VSTS单元测试工具和Watin结合使用具有很多。

    1)   VSTS测试工具提供了良好的运行和结果查看工具以及其它强大的功能

    2)   MSunit具有丰富的断言语句进行结果判断

    3)   可以在单元测试代码中穿插VSTS web测试代码,以丰富WatinUI测试

    4)  Watin进行UI测试可以使单元测试更直观易懂。

     

      VSTS中使用Watin的大体步骤

    1)       VSTS中创建测试项目,然后创建单元测试

    2)       测试项目中引用WatiN.core,创建StaticBrowserInstanceHelper

    3)       编写测试代码,加入断言

    4)       运行测试,查看测试结果

        如何创建测试项目,如何创建单元测试这里就不赘述了,下面从第2步骤讲起。

     

      为何使用StaticBrowserInstanceHelper

       在第二步骤中创建了StaticBrowserInstanceHelper类(该类代码在附件中)。创建这个类没有别的目的,就是解决一个在VSTS中运行watin会出现的一个问题。按照平常思路,我们直接创建单元测试,在其中编写测试代码,如下:

            //定义静态IE对象

            private static IE ie;

            //单元测试初始化

            [ClassInitialize]

            public static void testInit(TestContext testContext)

            {

                ie = new IE("http://baidu.com");

            }

    [TestMethod]

    [TestMethod]

    ………

    使用上述编写代码思路是对的,但是会出现一个问题(Watin本身的问题),运行第一个测试方法可以通过,其他测试方法均为失败。大家可以自己试一下,确实是这样。所以Watin开发人员给出了解决方案是编写一个StaticBrowserInstanceHelper类用于解决这个问题。你在编写初始化代码时,就可以这样写

     

           static StaticBrowserInstanceHelper<IE> ieStaticInstanceHelper;

            [ClassInitialize]

            public static void testInit(TestContext testContext)

            {

                ieStaticInstanceHelper = new StaticBrowserInstanceHelper<IE>();

                ieStaticInstanceHelper.Browser = new IE("http://baidu.com");

            }

            public IE IE

            {

                get { return (IE)ieStaticInstanceHelper.Browser; }

                set { ieStaticInstanceHelper.Browser = value; }

            }

            [ClassCleanup]

            public static void MyClassCleanup()

            {

                ieStaticInstanceHelper.Browser.Close();

                ieStaticInstanceHelper = null;

    }

    [TestMethod]

    [TestMethod]

     

    编写测试代码,加入断言

     单元测试初始化准备代码编写之后,就可以编写测试方法了。以百度页面为例来演示测试代码编写。

      验证页面是否存在指定文本文字

            [TestMethod]

            public void testOne()

            {    //页面是否包含“百科”文字

                Assert.IsTrue(IE.ContainsText("百科"));

    }

     验证页面中指定元素的Value是否正确

            [TestMethod]

            public void testThree()

            {

                Assert.AreEqual("MP3", IE.Link(Find.ByUrl("http://mp3.baidu.com/")).Text);

    }

     

    运行测试,查看测试结果

    在测试列表编辑器中运行单元测试

     

    勾选需要测试的测试方法后,右键菜单中选择“运行选择的测试”进行测试。然后开始运行测试。测试运行结果后,会在“测试结果”面板中列出测试结果,如下

    双击每项测试结果可以查看测试详细信息。

     

    至此,在VSTS测试中使用Watin的整个过程就是这样。限于篇幅限制,只能对大体的过程做些简单的介绍。

     

  • WatiN系列之三 Watin如何处理Web页面弹出窗口,对话框,提示框

    2010-09-09 18:10:26

    WatinWeb页面弹出窗口,对话框,提示框的处理

     

    处理弹出窗口

      首先创建一个web页,用于演示弹出窗口。

     

    <input id="Button1" type="button" value="button" onclick ="openwindow()" />

        <script type ="text/javascript">

        function openwindow()

          {

              window.open("http://localhost/Test/test2.htm");

          }

        </script>

    上述代码,点击“Button1”后,弹出窗口test2.htm.我们要做的是如何处理test2.htm页面

    Watin处理代码如下:

    IE ie = new IE("http://localhost/Test/");

    //点击按钮,打开新窗口test2

    ie.Button(Find.ById("Button1")).Click();

    //查找新窗口test2并赋给新的IE对象

    IE newie = IE.AttachTo<IE>(Find.ByTitle("test2"));

    //使用新的IE对象就可以继续对新窗口进行操作了

    newie.TextField(Find.ById("Text1")).TypeText("this is new ie");

     

     

      处理confirm弹出框

      首先创建一个web页,用于演示confirm对话框。

    <input id="myButton1" type="button" value="this is a button"

          onclick="confirmMe(); return false;"><br>

        <script>

          function confirmMe() {

            var answer = confirm ("Are you having fun?")

            if (answer)

              document.getElementById("myButton1").value="Clicked OK";

            else

              document.getElementById("myButton1").value="Clicked Cancel";

          }

        </script>

     

    相应的Watin测试代码如下:

     

    IE ie = new IE("http://localhost/Test/");

    //创建一个ConfirmDialogHandler对象

    ConfirmDialogHandler cdh = new ConfirmDialogHandler();

    //ConfirmDialogHandler对象与ie建立关联

    ie.AddDialogHandler(cdh);

    //点击按钮,这里需要注意的是:使用的是ClickNoWait()方法

    ie.Button(Find.ById("myButton1")).ClickNoWait();

    //等待Confirm对话框出现

    cdh.WaitUntilExists();

    //点击Confirm对话框的OK按钮

    cdh.OKButton.Click();

    ie.WaitForComplete();

    //ConfirmDialogHandler对象与ie取消关联

    ie.RemoveDialogHandler(cdh);

    Console.WriteLine(ie.Button(Find.ById("myButton1")).Value);

    Console.ReadLine();

     

    处理Alert弹出框

    首先创建一个web页,用于演示Alert对话框。

    <input id="myButton2" type="button" value="this is a button2"

          onclick="alertMe(); return false;"><br/>

        <script>

          function alertMe() {

            var answer = alert("this is a alert dialog");

            if(answer)

              document.getElementById("myButton2").value="Clicked OK";

          }

        </script>

     

    相应的Watin测试代码如下:

    IE ie = new IE("http://localhost/Test/");

    //创建一个AlertDialogHandler对象

    AlertDialogHandler adh = new AlertDialogHandler();

    //ConfirmDialogHandler对象与ie建立关联

    ie.AddDialogHandler(adh);

    //点击按钮,这里需要注意的是:使用的是ClickNoWait()方法

    ie.Button(Find.ById("myButton2")).ClickNoWait();

    //等待Alert对话框出现

    adh.WaitUntilExists();

    //点击Alert对话框的OK按钮

    adh.OKButton.Click();

    ie.WaitForComplete();

    //AlertDialogHandler对象与ie取消关联

    ie.RemoveDialogHandler(adh);

    Console.WriteLine(ie.Button(Find.ById("myButton2")).Value);

    Console.ReadLine();

     

    处理Fileupload弹出框

    首先创建一个web页,用于演示Fileupload对话框。

    <input id="File1" type="file" /></p>

    相应的Watin测试代码如下:

                IE ie = new IE("http://localhost/Test/test2.htm");

                //打开文件对话框并加载指定文件

                ie.FileUpload(Find.ById("File1")).Set(@"D:\Data.txt");

     

  • WatiN系列之二 解析Watin

    2010-09-09 18:00:32

     概述

    Watin作为一个自动化测试库,具有轻便,灵活的特点。而这都建立在对复杂操作封装的基础之上。Watin的原理和其它web自动化测试工具基本类似,就是通过操纵浏览器和web页面中的DOM对象来实现模拟用户操作网页。Watin封装了复杂的DOM操作并提供了大量的扩展,使对web网页的操作更灵活,更简便。本篇文章并不能做到深入解析Watin具体的原理,内部架构,也没必要去深究。我们要做的就是以使用者的角度去分析如何使用watin并不断在工作中完善。

     

    HTML元素与Watin类的映射

       在介绍watin类和方法用途之前,大家最好对HTML元素与watin类的映射关系进行一个大体的了解。因为你在编写测试代码之前,首先是通过工具查看web页面中元素的信息,确定该元素的类型时候,通过映射关系才能确定使用watin中的哪个类。所以这个映射关系很重要。

     

    详细的映射关系,请查看映射表

     

    Web页面常用元素操作

       介绍Watin如何对web页面中常见的一些元素进行操作。以及watin相关类和方法的介绍。在详细说明之前,首先创建一个页面,其中加入常用的页面元素(比如inpu,label),用来演示测试代码。具体代码见附件。

       然后再介绍一下,在编写测试代码过程中常用的类和主要的方法。

    Watin中常用的类和方法

       IE:最基础,最重要的一个类,用于访问Web页面中的元素以及操纵IE浏览器。

    Goto( string): 导航到某个地址的网页。

    Close() :关闭浏览器

    ContainsText(String): 是否包含指定的文本文字

    CaptureWebPageToFile(string): 对当前web页截图并保存到指定位置

    ClearCache(): 清除Cache

    ClearCookie(): 清除Cookie

    ……… 

     Find:也是必须用到的一个类,用于查找并定位web页面中的元素。

    Byid() : 通过元素的id属性进行查找

    Byname():通过元素的name属性进行查找

    ………

     其它类和方法请详见 MSDN style. online documentation  

     Watin对常用页面元素的操作

    <A>元素

     

     <a>标签对应DOM中的Anchor对象。表示Html中的超链接。

    <a id ="baidu" href = "http://wwww.baidu.com">百度</a>

    Watin操作<a>元素的代码如下

    ie.Link(Find.Byid("baidu")).Text; //返回超链接文字

    ie.Link(Find.Byid("baidu")).Url; //返回超链接的Url

    ie.Link(Find.Byid("baidu")).Click();//点击超链接

    备注:有些开发不规范的web页,有可能只有href属性存在的现象,这时只有通过Find.ByUrlurl)进行查找。

     

    <input type="text"> 元素

     <input type="text">元素对应HTML DOM中的 Text对象。表示一个单行的标准输入框。

    <input id="Text1" type="text" />欢迎!</p>

    Watin操作<a>元素的代码如下

    ie.TextField (Find.Byid("Text1")).Value; //返回输入框中的文字

    ie.TextField (Find.Byid("Text1")).TypeText("Watin"); //输入框中输入Watin

     

     

    <input type="button">元素

    <input type="button">元素对应HTML DOM中的 Button对象。表示一个按钮

    <input id="btn" type="button" />登录</p>

    Watin操作<a>元素的代码如下

    Ie.Button (Find.Byid("btn")).Text; //返回按钮中的文字

    ie.Button (Find.Byid("btn")).Click(); //点击按钮

     

     

    <input type="checkbox">元素

    <input type="Checkbox">元素对应HTML DOM中的 Checkbox对象。表示一个选择框

    <input id="chk" type="checkbox" />勾选</p>

    Watin操作<a>元素的代码如下

    Ie.CheckBox (Find.Byid("chk ")).Text; //返回选择框的文字

    ie.CheckBox (Find.Byid("chk ")).Click(); //点击选择框

    ie.CheckBox (Find.ById("chk ")).Checked = true; //设置Checkbox的勾选状态

     

    <area>元素

    <area>标签对应HTML DOM中的area对象。表示图像映射的一个区域(图像映射指的是带有可点击区域的图像)

    <img src="map/map.jpg" alt="校区地图" width="1004" height="601" border="0" usemap="#Map" />

    <map name="Map" id="Map">

    <area  shape="rect" alt ="a1" coords="134,59,255,92" href="edushiMap.html"  />

    <area shape="rect" alt ="a2" coords="345,122,464,160" href="edushiMap.html" />

    </map>

     

    Watin操作<area>元素的代码如下

    ie.Area(Find.ByAlt("a1")).Url; //返回area区域的url

    ie.Area(Find.ById("area1")).Click();//点击area区域

    ie.Area(Find.ByAlt("a1")).Click();//点击area区域

     

    <Select>元素

    <Select>元素对应HTML DOM中的 Select对象。表示一个下拉列表

    <select id="Select1">

        <option>1</option>

        <option>2</option>

    </select>

    Watin操作<Select>元素的代码如下

    ie.SelectList(Find.ById("Select1")).Select(string); //返回选择框的某项

     

     

    <table>元素

    <table>元素对应HTML DOM中的 table对象。表示一个表格

    <table style="width: 100%;" id ="table1"  class = "class1">

        <tr>

            <td class="style1">

                第1行第1列</td>

            <td class="style1">

                &nbsp;

                第1行第2列</td>

        </tr>

        <tr>

            <td>

                第2行第1列</td>

            <td>

                &nbsp;

                第2行第2列</td>

        </tr>

        </table>

    Watin操作<table>元素的代码如下

    ie.Table(Find.ByClass("class1")).TableRows[0].TableCells[1].Text; //返回表格中项的数据

     

  • WatiN系列之一 初识Watin

    2010-09-09 10:41:19

    简介

    WatiN是一个开源的用于Web测试自动化的类库,从watir中获得的灵感,使用C#开发。WatiN通过与浏览器的交互来实现自动化,使用起来具有轻便,简单的特点。目前最新版本为2.0,加入了对Firefox的支持,使其功能更趋于完善和多样。

      在具体介绍如何使用WatiN之前,要先了解一下WatiN.Core这个类库下主要的命名空间。

    WatiN.Core: Watin的核心部分,与浏览器的交互都包含在此模块中。

    WatiN.Core.DialogHandlers:该命名空间提供用于操作浏览器对话框的对象。其中包括AlertDialogHandler, ConfirmDialogHandler, FileUploadDialogHandler, PrintDialogHandler, and LogonDialogHandler

    WatiN.Core.Exceptions:该命名空间里的对象用于处理各种异常,比如: ElementNotFoundException, IENotFoundException, TimeoutException, and a generic WatiNException

    开始

      我们先以一个简单的示例为例来介绍说明Watin是如何与浏览器交互,watin有哪些主要的部分组成的。

      在介绍这个示例之前,大家需要到Watin官网上下载Watin。同时,为了更好的协助你的工作,你需要下载安装IE Developer Toolbar,用来查看网页的元素信息。

      下面是一段Watin代码, 效果是打开百度网页,然后在搜索 “Watin”,最后返回搜索结果。

    我们编写Watin代码一般使用Vistual Studio作为IDE,在建立一个项目后,要把之前下载的Watin.Core.dll引用到项目中,并在代码之前加“using WatiN.Core”。

     

     具体代码如下:

     

                //实例化IE类,可以把实例化的ie看成是页面,以后的操作基本都是它打交道

                IE ie = new IE("http://www.baidu.com/");

                //找到搜索输入框,并输入“Watin”

                ie.TextField(Find.ById("kw")).TypeText("Watin");

                //找到搜索按钮并点击

                ie.Button(Find.ById("su")).Click();

                //查询结果中找到搜索的相关信息

                string result = ie.Table(Find.ByClass("bi")).TableRows[0].TableCells[1].Text;

                //打印搜索信息

    Console.WriteLine(result);

                Console.ReadLine();

    上段代码大体的作用应该比较清楚了,其中具体的类和方法的用法将会在下一章中介绍。

     

    资料及资源:

    资料:

    资源:

     

  • 使用SMO比较表结构差异(原创)

    2009-09-28 23:00:36

       今天因为工作需要,需对比SQL Server2005数据库中相同表的字段是否相同。之前,在SQL server2000数据库中做过同样的事情,利用的是VBS脚本操作DMO来实现的。不过很可惜,在SQL server2005已经不在使用DMO,而是启用了新的SMO。而且VBS脚本也不再支持SMO。所以,只能用C#来进行了。具体思路:先比较两个数据库,找到相同的表,然后比较表的列,找出差异。

    使用SMO,需先引用Microsoft.SqlServer.ConnectionInfo,

    Microsoft.SqlServer.Smo 这两个命名空间。

    源代码:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.SqlServer.Management.Smo;
    using Microsoft.SqlServer.Server;
    using Microsoft.SqlServer.Management.Common;
    using Microsoft.SqlServer;
    using System.Data.SqlClient;
    using System.Collections;


    namespace SMOsample
    {
        class Program
        {
            static void Main(string[] args)
            {
                string connectionString1 = "server =192.168.40.148;database = JcyPD;uid =sa;pwd=1";
                SqlConnection connection1 = new SqlConnection(connectionString1);
                Server server1 = new Server(new ServerConnection(connection1));
                Database db1 = server1.Databases["JcyPD"];

                string connectionString2 = "server =192.168.40.110;database = Jcy40 ;uid =sa;pwd=sa";
                SqlConnection connection2 = new SqlConnection(connectionString2);
                Server server2 = new Server(new ServerConnection(connection2));
                Database db2 = server2.Databases["Jcy40"];

                ArrayList al1 = new ArrayList();
                ArrayList al2 = new ArrayList();

                for (int x = 0; x < db1.Tables.Count; x++)
                {
                    al1.Add(db1.Tables[x].Name.ToString());
                }

     

                for (int y = 0; y < db2.Tables.Count; y++)
                {
                    al2.Add(db2.Tables[y].Name.ToString());
                }

                for (int m = 0; m < al1.Count; m++)
                {
                    for (int n = 0; n < al2.Count; n++)
                    {
                        if (al1[m].ToString() == al2[n].ToString())
                        {
                            ArrayList cal1 = new ArrayList();
                            ArrayList cal2 = new ArrayList();
                           
                            foreach(Column c1 in  db1.Tables[al1[m].ToString()].Columns)
                            {
                                cal1.Add(c1.Name.ToString());
                            }

                            foreach (Column c2 in db2.Tables[al2[n].ToString()].Columns)
                            {
                                cal2.Add(c2.Name.ToString());
                            }

                            foreach (string s in cal2)
                            {
                                if (!cal1.Contains(s))
                                {
                                    Console.WriteLine(al2[n].ToString() + " : " + s);

                                }
                            }

                        }
                    }
                }
                Console.WriteLine("完毕!");
                Console.ReadLine();

            }
        }
    }

  • 使用VBS脚本从Exce中读取测试数据(原创)

    2009-09-24 21:39:34

      这是以前为了在测试工具中方便的读取Excel数据写的脚本(一个轻量级框架的一部分)。总体思路是:利用Excel的com接口,把数据读取到字典(键值对,也就是测试字段对应测试数据)中,然后在通过键值对的key把测试数据读取出来。(这种方法虽然比较简陋,但是胜在简单易用)。下面就具体说明一下:

     首先,我们先看一下Excel中的测试数据格式,

    Field   DataType     DataValue     DataValue 
    姓名     string           姓名1      姓名2
    性别     string           男          女
    年龄       int            34         45

    第一列 字段名称

    第二列 数据类型

    第三列及之后 测试数据

    具体代码如下:

    Dim objexcel 'excel对象
    Dim objworkbook 'excel的workbook对象
    Dim objsheet 'sheet对象
    Dim objDictionary '字典对象

    '=========================
    '获取sheet对象
    'sheetname: sheet名称
    'path: 文件路径
    '=========================
    Function Getexcelobject(sheetname,filepath)

      Set bjexcel = CreateObject("excel.application")
      Set bjworkbook = objexcel.Workbooks.Open(filepath)
      Set bjsheet = objworkbook.Sheets(sheetname)
    End Function

    '========================
    '关闭excel
    '========================

    Function ExcelColse()
      objworkbook.Close
    End Function 

    '========================
    '获取测试字段与默认测试数据的键对数组
    '========================

    Function GetDictionary()
      Set bjDictionary = CreateObject("Scripting.Dictionary")
      x=2
      Do While Not (objsheet.cells(x,1).value ="")
      objDictionary.Add CStr(objsheet.cells(x,1)),CStr(objsheet.cells(x,3))
      x=x+1
      Loop 
    End Function

    '========================
    '获取测试字段与指定测试数据的键对数组
    '========================

    Function GetSpecDictionary(y)
      Set bjDictionary = CreateObject("Scripting.Dictionary")
      x=2
      Do While Not (objsheet.cells(x,1).value ="")
      objDictionary.Add CStr(objsheet.cells(x,1)),CStr(objsheet.cells(x,y))
      x=x+1
      Loop 
    End Function

    '=========================
    '获取默认测试数据值
    'field:AUT字段
    '=========================
    Function Getvalue(field)
      GetDictionary()
      Getvalue = objDictionary(field)
    End Function 

    '=========================
    '获取测试数据的数量
    '=========================
    Function Getvaluenumber()
      GetDictionary()
      Getvaluenumber = objDictionary.Count
    End Function 


    '========================
    '获取指定列数据,field为字段名,colnumber为列值
    '========================
    Function Getspecvalue(field,colnumber)
      GetSpecDictionary(colnumber)
      Getspecvalue = objDictionary(field)
    End Function


    如果想读取默认测试数据,也就是读取第三列,需如下进行:

    Call Getexcelobject("sheet1","E:\TestData\查询.xls")
    WScript.Echo Getvalue("姓名") 
     

    如果想读取任意列的测试数据,需:

    Call Getexcelobject("sheet1","E:\TestData\查询.xls")
    WScript.Echo Getspecvalue("姓名",4) 




  • 生成C#的win32api非托管代码工具

    2009-09-23 21:26:40

      这几天在研究如何用C#利用win32api编写GUI测试工具,由于经常要编写win32的非托管代码,比较麻烦。微软好像也没有相关工具。现找到一个生成win32的c#非托管代码的工具,与大家共享。界面如下:

    打开工具,File->open,打开win32api.txt文件,win32api的常量,结构以及类型就会加载。选中你需要的项,点击“Add”,就会生成相应代码了。

    注意: 我编译工具时,窗口初始化时会自动加载win32api.txt,而且文件路径是硬编码的,所以在打开工具之前,要把win32api.txt放到C:\下。当然,也可以用源代码重新修改编译。

    工具:

    CSharpAPITextViewer.rar(8.59 KB)

    win32api.txt :

    WIN32API.rar(531 KB)

    源代码:

    CSharpAPITextViewer(源代码).rar(218 KB)

  • 使用python测试网页中超链接的连通性(原创)

    2009-09-21 22:24:27

      在web测试,对网页中的超链接进行测试是最基本的工作,最简便的方法当然是使用像xenu之类的工具。但它具体是怎么实现的呢?我想也无外乎是通过http协议,根据超链接地址,向服务端发送请求,然后根据返回的信息进行判断连接的状态。下面是根据这种思路,用python编写的检测网页链接连通性的程序。

    首先,建立一个示例网页,其中link1,lin3是不连通的,link2,link4是有效链接

    <head>Test</hest>
    <body>
     <a href="http://ggdfgdfg.com/erwerwe.html">link1</a>
     <a href="/sample/lik.html">link2</a>
     <a href="/sample/lik2.html">link3</a>
     <a href="http://google.com">link4</a>
    </body>

    使用python进行链接检测,要使用到4个重要模块,过程就是通过urllib抓取目标网页的html代码,然后通过sgmllib模块解析html,获取超链接的列表。然后使用urlparse解析超链接的url,供httplib使用。然后由httplib模块进行最后的请求及验证回复的过程。

    sgmllib :用于HTML解析,解析出网页中包含的超链接

    httplib:用于Http协议的操作

    urllib:用于获取网页的html代码

    urlparse:解析url地址,把url地址解析成几个部分。

    具体实现代码如下:

    #-×-coding:gb2312-*-
    import httplib,urllib,urlparse
    from sgmllib import SGMLParser
    #解析指定的网页的html,得到该页面的超链接列表
    class URLLister(SGMLParser):
        def reset(self):
            SGMLParser.reset(self)
            self.urls = []

        def start_a(self, attrs):
            href = [v for k, v in attrs if k=='href']
            if href:
                self.urls.extend(href)
    #遍历超链接列表,并逐个的发送请求,判断接收后的代码,200为正常,其他为不正常
    def fetch(host):
            usock = urllib.urlopen(host)
            parser = URLLister()
            parser.feed(usock.read())
            uhost = urlparse.urlparse(host)
            for url in parser.urls:
                up = urlparse.urlparse(url)
                #因为超链接有两种方式:一种是直接的http://...... 一种是相对路径,/.../sample.html
              #所以要分别处理
                if up.netloc =="":
                    http = httplib.HTTP(uhost.netloc)
                    http.putrequest("GET", "/"+up.path+"?"+up.params+up.query+up.fragment)
                    http.putheader("Accept", "*/*")
                    http.endheaders()
                else:
                    http = httplib.HTTP(up.netloc)
                    http.putrequest("GET", up.path+"?"+up.params+up.query+up.fragment)
                    http.putheader("Accept", "*/*")
                    http.endheaders()
                errcode, errmsg, headers = http.getreply()
                if errcode == 200:
                    print url," : ok"
                else:
                    print url," : ",errcode

    #测试
    fetch("http://localhost/Sample/sample.html")

    代码运行的结果:

    http://ggdfgdfg.com/erwerwe.html  :  404
    /sample/lik.html  : ok
    /sample/lik2.html  :  404
    http://google.com  : ok

     

    版权声明:本文出自wxf_xsfy的51Testing软件测试博客:http://www.51testing.com/?61753

    原创作品,转载时请务必以超链接形式标明文章原始出处、作者信息和本声明,否则将追究法律责任。

  • 使用DotNetSkin 更换winform的皮肤

    2009-09-19 21:33:34

       在日常工作中经常会使用C#开发一些测试辅助小工具,不过工具一承不变的外观确实会使人审美疲劳,所以就尝试更换一下form的皮肤,经google后,发现一个非常简单易用的控件-DotNetSkin。

    官方给出的效果图:

    首先下载链接:

    http://files.cnblogs.com/mgod/dotnetskin2005.rar  里面有演示代码
    然后下载http://files.cnblogs.com/mgod/v1.20.1.rar 将对应DLL版本覆盖到Bin目录中

    安装:

    1.右键点击vs的工具栏的常规Tab,选择“添加项”

    2.添加DotNetSkin.dll后,确定。DotNetSkin控件就出现在了工具栏中。

    使用方法:

    1 把SkinUI控件拖放到Form窗口上

    2 设置skinUI.FileName属性,选择*.skin文件

    3 设置skinUI.active 为true

    4 编译并运行你的程序就可以了

792/4<1234>
Open Toolbar