做最好的自己~·

发布新日志

  • 转-LoadRunner中Web_submit_form和Web_submit_data的区别详细解释

    cqian 发布于 2010-06-10 14:40:44

    在LoadRunner中有两个常用函数:Web_submit_form和Web_submit_data,在群里有人问这两个函数有什么区别。为什么会有两个不同却功能相似的函数。区别在哪里。

    首先,从工具的角度来说,厂商推荐使用Web_submit_form函数,因为这个函数看起来更易用,需要关注的东西较少。但是,从个人的角度来说,我推荐使用Web_submit_data函数。因为这个函数提供更多技术细节。在测试的过程中可控性更高。下面我就详细解释一下两个函数的工作机制:

    首先看一下下面这段HTML代码

    <Form. Action=login.asp Method=POST>

    <input name=user value=“”>

    <input name=password value=“”>

    <input type=hidden name=sessionID value=15379>

    </Form>

    在录制的过程中,当打开这个页面的时候,这个页面会放在LR的Cache中,之后当我们输入了用户名、口令之后,点了一下提交。Browser会向LR Record Proxy发送一个提交请求,提交内容应该是这样的:

    POST login.asp HTTP/1.1

    user=steve password=buba

    sessionID=15379

    这时候,LR会自动比较提交的内容和Cache的内容,首先它会比较提交的数据项和Cache中的数据项是否一致。页面中有三个输入域user、password、sessionID,而提交的内容也有这三项数据,所以它认为提交数据使用了Cache中的页面,之后它会继续比较具体数据的值。它会发现sessionID的值和Cache中的值是一样的。但是user和password的值不一样。

    这时候,Web_submit_form和Web_submit_data的区别就出现了:

    web_submit_form(”start",

    ITEMDATA,

    "name=user", "value=steve", ENDITEM,

    "name=password", "value=bean", ENDITEM,

    LAST);

    web_submit_data(”start",

    Action=login.asp,

    Method=POST

    ITEMDATA,

    "name=user", "value=steve", ENDITEM,

    "name=password", "value=bean", ENDITEM,

    "name=sessionID", "value=15379", ENDITEM,

    LAST);

    可以看到,Web_submit_form只提供了和Cache中有差别的数据,其余的数据会自动从Cache中取。而Web_submit_data则提供了所有的数据,不管Cache存在不存在Web_submit_data都是可以工作的。

    所以厂商会推荐使用Web_submit_form,因为它看起来更易用,甚至关联都不需要作,就能直接回放。但是这种情况只能对于简单系统适用。对于一些银行或者移动的复杂系统来说,有时侯会对Cache作特殊操作,Web_submit_form有时侯就会报一些莫名其妙的错出来。而Web_submit_data则跟Cache内容无关。稳定性和可控性都要比Web_submit_form要高很多。所以个人推荐尽量使用Web_submit_data函数。

  • Oracle数据导入导出命令集

    btnn 发布于 2011-08-16 10:01:05

    数据导出:
     1 将数据库TEST完全导出,用户名system 密码manager 导出到D:\daochu.dmp中
       exp system/manager@TEST file=d:\daochu.dmp full=y
     2 将数据库中system用户与sys用户的表导出
       exp system/manager@TEST file=d:\daochu.dmp wner=(system,sys)
     3 将数据库中的表inner_notify、notify_staff_relat导出
        exp aichannel/aichannel@TESTDB2 file= d:\data\newsmgnt.dmp tables=(inner_notify,notify_staff_relat)

     4 将数据库中的表table1中的字段filed1以"00"打头的数据导出
       exp system/manager@TEST file=d:\daochu.dmp tables=(table1) query=\" where filed1 like '00%'\"
     
      上面是常用的导出,对于压缩,既用winzip把dmp文件可以很好的压缩。
      也可以在上面命令后面 加上 compress=y 来实现。

    数据的导入
     1 将D:\daochu.dmp 中的数据导入 TEST数据库中。
       imp system/manager@TEST  file=d:\daochu.dmp
       imp aichannel/aichannel@HUST full=y  file=file= d:\data\newsmgnt.dmp ignore=y
       上面可能有点问题,因为有的表已经存在,然后它就报错,对该表就不进行导入。
       在后面加上 ignore=y 就可以了。
     2 将d:\daochu.dmp中的表table1 导入
     imp system/manager@TEST  file=d:\daochu.dmp  tables=(table1)
     
  • 软件测试工程师 最常用最好用的截图工具

    luoxipei 发布于 2011-07-21 09:19:46

      FastStone Screen Capture(FSCapture)是一款很棒的图像浏览、编辑和抓屏工具,支持包括BMP、JPEG、JPEG 2000、GIF、PNG、PCX、TIFF、WMF、ICO 和TGA在内的所有主流图片格式,其独有的光滑和毛刺处理技术让图片更加清晰,提供缩放、旋转、减切、颜色调整功能。只要点点鼠标就能随心抓取屏幕上的任何东西,拖放支持可以直接从系统、浏览器或其他程序中导入图片。一款非常好的屏幕截图软件。

    软件测试工程师必不可少的截图工具。最好用,最灵活,最实用。

  • Loadrunner 压力测试结果分析

    gzsoftwaretest 发布于 2011-07-27 09:29:09

    分析原则:
      1. 具体问题具体分析(这是由于不同的应用系统,不同的测试目的,不同的性能关注点)
      2. 查找瓶颈时按以下顺序,由易到难。
      服务器硬件瓶颈 网络瓶颈(对局域网,可以不考虑) 服务器操作系统瓶颈(参数配置) 中间件瓶颈(参数配置,数据库web服务器等) 应用瓶颈(SQL语句、数据库设计、业务逻辑、算法等)
      分析的信息来源:
      1. 根据场景运行过程中的错误提示信息
      2. 根据测试结果收集到的监控指标数据
      一.错误提示分析
      分析实例:
      1.Error: Failed to connect to server “172.17.7.230″: [10060] Connection
      Error: timed out Error: Server “172.17.7.230″ has shut down the connection prematurely
      分析:
      A、应用服务死掉。
      (小用户时:程序上的问题。程序上处理数据库的问题,实际测试中多半是服务器链接的配置问题)
      B、应用服务没有死
      (应用服务参数设置问题)
      对应的Apache和tomcat的最大链接数需要修改,如果连接时收到connection refused消息,说明应提高相应的服务器最大连接的设置,增加幅度要根据实际情况和服务器硬件的情况来定,建议每次增加25%!
      C、数据库的连接
      (数据库启动的最大连接数(跟硬件的内存有关))
      D、我们的应用程序spring控制的最大链接数太低
      2. Error: Page download timeout (120 seconds) has expired
      分析:
      A、应用服务参数设置太大导致服务器的瓶颈
      B、页面中图片太多
      C、在程序处理表的时候检查字段太大多
      D、实际测试时有些资源需要请求外网,而我们的测试环境是局域网环境
      3. Error “http://172.17.7.230/Home.do....”
      分析:
      A、脚本设计错误,造成页面异常。服务器有响应!
      B、并发数过大,造成服务器响应延迟。
      4. Error page “text=xxxxx”
      分析:
      A、脚本设计问题,例如,前一脚本修改了某些内容,造成后面的脚本访问异常。
      B、不确定因素,有时候回放正常的脚本,一放到场景中就出现这样的错误。只能反复修改脚本!
      二.监控指标数据分析
      1.Vusers数
      Loadrunner 系统设置的虚拟用户数目。Vuser去实际调用事先制作的脚本文件中的应用。
      每个Vuser产生响应的操作,所有的操作对服务器形成并发。
      颜色 比例 度量 图最小值 图平均值 图最大值 图中间值 图SD
      1 Run 0.0 21.25 44 41 21.276
      在实际测试中,Vusers可以根据实际情况的需要,在测试过程中增加或者减少。
      2.最大并发用户数:
      颜色 比例 度量 最小值 平均值 最大值 SD
      100 Apache CPU 使用情况(Apache):172.17.7.210 0.777 0.852 0.93 0.043
      0.01 已发送 KB/秒(Apache):172.17.7.210 6 1430.371 2689.333 327.924
      0.1 点击次数/秒(Apache):172.17.7.210 0.333 114.352 533.667 40.201
      应用系统在当前环境下能承受的最大并发用户数。
      在方案运行中,如果出现了大批用户的业务操作失败,或出现了服务器shutdown的情况,则说明在当前环境下,系统承受不了当前并发用户的负载压力,那么最大并发用户数就是前一个没有出现这种现象的并发用户数。
      从上图可以看出:在测试运行到4个小时左右的时候,apache的点击数/秒开始迅速增加!
      3.业务操作响应时间:
      使用“事务性能摘要”图,可以确定在方案执行期间响应时间过长的事务。
      颜色 比例 度量
      1 最小值
      1 平均值
      1 最大值
      分析事务的响应情况,要每次详细分析,目前还只能观察到响应时间过长的事务!
      4.每秒点击数
      负载测试期间每秒内 Vuser 在 Web 服务器上点击的次数。可根据点击次数来估算 Vuser 生成的负载数。
      颜色 比例 度量 图最小值 平均值 图最大值 图中间值 图SD
      1 点击次数 69.908 105.736 130.244 103.666 12.186
      从图中不难看出,在4小时的时候,点技数明显增高。和apache的每秒点击数增大的时间相吻合!
      5.吞吐量
      负载测试期间 Web 服务器上的吞吐量(字节)。吞吐量表示在任何指定秒内 Vuser 从服务器接收到的数据量。此图可估计 Vuser 生成的负载量(服务器吞吐量)。
      颜色 比例 度量 图最小值 平均值 图最大值 图中间值 图SD
      1 Throughput 1257502.795 1375591.372 1525865.047 1372743.691 49130.473
      同样,从图中可以看出,在4个小时的时候,web服务器的吞吐量开始增高。

    在图中还可以看到吞吐量的走势图,从开始到进行到4个小时反弹之前呈降低的趋势,这是因为系统在初期调用的资源都是直接来之服务器,运行一段时间后系统的部分资源来自缓存。
      6.下载组件大小
      每个页面的组件大小,且包括组件的标头的大小!
      页面组件大小的分析表格比较复杂,实际分析中可以通过loadrunner的报告分析工具来分析。页面组件大小分析主要是找到页面中比较庞大的组件,如果其影响到了页面的下载速度,则要想办法将其改小!
      7.Apache资源
      显示APACHE web服务器上的资源摘要。前面已经提到过以并发点击数为主。
      颜色 比例 度量 最小值 平均值 最大值 SD
      100 Apache CPU 使用情况(Apache):172.17.7.210 0.777 0.852 0.93 0.043
      0.01 已发送 KB/秒(Apache):172.17.7.210 6 1430.371 2689.333 327.924
      0.1 点击次数/秒(Apache):172.17.7.210 0.333 114.352 533.667 40.201
      三.服务器资源监控指标
      (目前通过top监察)
      内存:
      Linux资源监控中指标内存页交换速率(Paging rate),如果该值偶尔走高,表明当时有线程竞争内存。如果持续很高,则内存可能是瓶颈。也可能是内存访问命中率低。
      实际测试中,当并发点击数出现突然剧增前后,内存的PR 值则居高25不下。说明目前测试的系统中内存存在瓶颈!
      内存资源成为系统性能的瓶颈的征兆:
      很高的换页率(high pageout rate);
      进程进入不活动状态;
      交换区所有磁盘的活动次数可高;
      可高的全局系统CPU利用率;
      内存不够出错(out of memory errors)
      处理器:
      Linux资源监控中指标CPU占用率持续超过80%(对该值的要求,根据具体应用和机器配置而要求不同,有资料表明95%),表明瓶颈是CPU。
      实际测试中,当并发点技数出现突然增加前后,cpu的占用率持续保持在86%以上!
      说明,目前系统用应用的cpu也是测试的瓶颈!
      CPU资源成为系统性能的瓶颈的征兆:
      很慢的响应时间(slow response time)
      CPU空闲时间为零(zero percent idle CPU)
      过高的用户占用CPU时间(high percent user CPU)
      过高的系统占用CPU时间(high percent system CPU)
      长时间的有很长的运行进程队列(large run queue size sustained over time)
      四.数据库服务器
      数据库服务器目前测试观察,当web服务器点击率增大时,观察mysql数据库的最大连接数,仍未超过系统设置的最大连接数。所以,暂时未发现数据库的瓶颈!
      五.结论
      以上报告分析中的数据、图标均来自同一次测试。是在平时测试中挑出的一次现象比较明显,比较利于观察的作为分析案例。
      根据以上综合分析,当前测试环境下,当应用系统产生最大533.667的并发压力。平均负载压力114.352。根据分析,用户在4个小时的时候,并发数迅速增加前后的值在400左右!分析结果跟实际测试的硬件环境以及测试脚本有一定关系。同时,测试服务器的硬件配置和实际服务器的配置还有一定的差距!

  • 学习资料的一些网站收藏

    张晓南 发布于 2011-02-17 11:38:18

    一、新手必看资料


    1、软件开发的科学和艺术之软件测试
    http://bbs.51testing.com/thread-137737-1-29.html
    2、回报社会大集合
    http://bbs.51testing.com/thread-179155-1-1.html
    3、web测试的一些经验分享
    http://bbs.51testing.com/thread-171903-1-1.html
    4、软件测试综合资料库
    http://bbs.51testing.com/thread-79154-1-20.html
    5、软件测试总结----新手必看 【
    http://bbs.51testing.com/thread-107659-1-2.html
    软件测试基本理论简介,介绍了软件测试中基本所有的术语、自动化工具分类。可以作为面试基础教材看。很全面,但比较简略。
    6、软件测试新手学习宝典
    http://bbs.51testing.com/thread-96312-1-1.html
    7、软件测试职业道德和工作责任
    http://bbs.51testing.com/thread-55158-1-1.html
    8、关于web测试资料集
    http://bbs.51testing.com/thread-253078-1-1.html

    二、做好测试工程师要会哪些知识技能、自学方向


    1、知识技能、空闲时自学方向
    http://bbs.51testing.com/thread-137662-1-7.html
    说的比较宽泛,感觉对我没太多帮助,建议还是根据自己的需求来。。
    2、软件测试培训、是否可以自学测试
    http://bbs.51testing.com/thread-140054-1-1.html
    挺有道理的,适合没上路的新人朋友
    3、软件测试从这里开始V1.0.0.0
    http://bbs.51testing.com/thread-78735-1-1.html
    4、经典《测试指南》
    http://bbs.51testing.com/thread-134848-1-1.html
    5、软件测试基础知识培训PDF
    http://bbs.51testing.com/thread-2160-1-1.html
    6、软件测试基本方法
    http://bbs.51testing.com/thread-13775-1-3.html

    三、了解别人的测试经历,学习别人经验


    1、我的测试历程[精华] 【
    http://bbs.51testing.com/thread-173152-1-2.html
    很好的资料,前两篇介绍的经验很重要,安装测试文档很经典。
    2、6年的测试经历
    http://bbs.51testing.com/thread-95214-1-4.html
    感觉写的是软件开发经历,不过某些观点可以看看
    3、对于测试感到迷茫该怎么办
    http://bbs.51testing.com/thread-139934-1-3.html
    我很迷茫,但我看了这个没啥收获。没有实质内容。
    4、写给新朋友的,我的经历
    http://bbs.51testing.com/thread-131041-1-10.html
    挺朴实,挺感人的
    5、写给测试新手——作者阳光
    http://bbs.51testing.com/thread-113232-1-2.html
    6、半年内学好软件测试不是神话
    http://bbs.51testing.com/thread-151951-1-5.html

    四、借鉴别人的经验


    1、我的测试观
    http://bbs.51testing.com/thread-172024-1-1.html
    2、[新手上路]给想要学习软件测试同学们的建议
    http://bbs.51testing.com/thread-65437-1-1.html
    3、经典软件测试网站
    http://bbs.51testing.com/thread-51985-1-17.html
    4、软件测试从零开始
    http://bbs.51testing.com/thread-145021-1-1.html
    5、新手怎么入手软件测试
    http://bbs.51testing.com/thread-155804-1-1.html
    6、【转帖】我的测试观点与经验--cleverman
    http://bbs.51testing.com/thread-184349-1-1.html
    7.写给软件测试新手:我的软件测试的学习过程加资料。
    http://bbs.51testing.com/thread-209521-1-2.html


    五.测试人员要掌握的知识及模板


    1、测试的基本概念
    http://bbs.51testing.com/thread-51190-1-9.html
    2、软件测试网络资料大集合
    http://bbs.51testing.com/thread-3229-1-10.html
    3、测试资料
    http://bbs.51testing.com/thread-129350-1-29.html
    4、测试基础资料
    http://bbs.51testing.com/thread-119493-1-31.html
    5、测试人员要掌握的数据库知识
    http://bbs.51testing.com/thread-133499-1-3.html
    6、软件测试专业术语对照表
    http://bbs.51testing.com/thread-107534-1-10.html
    7、软件测试的详细流程
    http://bbs.51testing.com/thread-131087-1-5.html
    8、教你如何书写测试计划
    http://bbs.51testing.com/thread-81583-1-24.html
    9、一个可供参考的软件测试报告
    http://bbs.51testing.com/thread-36263-1-3.html
    10、精典测试计划模板实例
    http://bbs.51testing.com/thread-24839-1-4.html

    六.测试类书籍


    1、软件测试的艺术[第二版中文]
    http://bbs.51testing.com/thread-67373-1-2.html
    2、《软件测试自动化》
    http://bbs.51testing.com/thread-73329-1-3.html
    5、测试书籍
    http://bbs.51testing.com/thread-130536-1-6.html
    3、《软件测试工程师培训教程》
    http://bbs.51testing.com/thread-134377-1-3.html
    4、有效软件测试的50条建议中文版+英文原版
    http://bbs.51testing.com/thread-112262-1-4.html
    5、《软件测试经验与教训》
    http://bbs.51testing.com/thread-117962-1-5.html
    6、软件测试(原书中文第二版)PDF版
    http://bbs.51testing.com/thread-140368-1-1.html
    7、软件测试[(美)Ron Patton]基础知识读书笔记
    http://bbs.51testing.com/thread-66400-1-26.html
    雪舞奉天的读书笔记,原来他是17testing的版主。该笔记通俗易懂,很多概念和思想都来源于此。
    8、软件测试文件编制规范和单元测试
    http://bbs.51testing.com/thread-171480-1-1.html

    七、QTP资料



    QTP 功能自动化工具,适合在回归测试阶段和冒烟测试中使用,局限性比较大。
    1、QTP9.2软件下载
    http://hi.baidu.com/%B9%FE%C2%DE ... 3102d98db10d91.html
    3、QTP视频----入门与实践
    http://bbs.51testing.com/thread-106440-1-1.html
    4、QTP板块上的常用辅助工具
    http://bbs.51testing.com/thread-75966-1-1.html
    5、【QTP版资料大汇总】
    http://bbs.51testing.com/thread-137554-1-1.html
    6、QTP学习入门资料征集
    http://bbs.51testing.com/thread-170892-1-1.html
    7、征集QTP的问题
    http://bbs.51testing.com/thread-146249-1-1.html
    8、QuickTest Pro资料大集合(第20楼有好东西哦Main_Users_Guide.pdf这个很难找但很有用哈哈)
    http://bbs.51testing.com/thread-30476-1-1.html

        八、软件评测师考试资料
    1、软考 软件评测师复习知识点
    http://bbs.51testing.com/viewthread.php?tid=115736&highlight=%C8%ED%BC%FE%C6%C0%B2%E2%CA%A6
    2、软件评测师考试考点分析与真题详解[下载][pdg]
    http://bbs.51testing.com/viewthread.php?tid=141580&highlight=%C8%ED%BC%FE%C6%C0%B2%E2%CA%A6
    3、分享05-09年软件评测师试题及答案
    http://bbs.51testing.com/viewthread.php?tid=147078&highlight=%C8%ED%BC%FE%C6%C0%B2%E2%CA%A6
    4、软件评测师考试交流群
    http://bbs.51testing.com/viewthread.php?tid=283225&highlight=%C8%ED%BC%FE%C6%C0%B2%E2%CA%A6
    http://bbs.51testing.com/viewthread.php?tid=132143&highlight=%C8%ED%BC%FE%C6%C0%B2%E2%CA%A6
    http://bbs.51testing.com/viewthread.php?tid=295911&highlight=%C8%ED%BC%FE%C6%C0%B2%E2%CA%A6

    九、附加资料学习类


    1、要学SQL的往这看,sql学习资料(免费)更新
    http://bbs.51testing.com/thread-101279-1-1.html
    2、想学习sql的,看看这个吧
    http://bbs.51testing.com/thread-170231-1-1.html
    3、Oracle学习资料
    http://bbs.51testing.com/thread-173195-1-1.html
    4、oracle傻瓜手册
    http://bbs.51testing.com/thread-72991-1-7.html
    5、历史上最全的Oracle SQL函数大总结
    http://bbs.51testing.com/thread-66758-1-7.html
    6、sql试题查询答案
    http://bbs.51testing.com/thread-175348-1-1.html
    7、《Red Hat Linux 9系统管理员完全学习手册》
    http://bbs.51testing.com/thread-48966-1-28.html
    8、关于linux系统学习资料大全
    http://bbs.51testing.com/thread-171168-1-1.html
    9、分享---职业发展板块好文
    http://bbs.51testing.com/thread-171277-1-1.html
    *资源共享篇
    1.软件测试资料大派送中
    http://bbs.51testing.com/thread-165543-1-1.html
    2.软件测试视频大派送
    http://bbs.51testing.com/thread-283175-1-1.html
  • 事务Transaction

    iory 发布于 2010-05-22 22:09:08

    对LoadRunner来说事务是非常非常重要的概念,具体如下所述:
    1、事务是LoadRunner度量系统性能指标的唯一手段;
    2、事务能够用于度量高风险业务流程的性能指标;
    3、事务能够度量在一组操作中每一步的性能指标;
    4、通过事务计时实现了不同压力负载下的性能指标对比;
    5、通过事务计时可以帮助定位性能瓶颈;
    从性能测试的 角度出发,我们需要知道不同的操作所花费的时间,这样我们就可以衡量不同的操作对被测系统所造成的影响。

    在脚本中插入事务的方法:
    方法一:脚本生成后,手动插入事务;
    注:事务命名必须具有实际意义,最好能表征步骤的业务含义,如login命名为"登陆",withdraw命名为"取款"等等。
    方法二:在脚本录制过程中插入Start Transaction和End Transaction(推荐这种方法)
    方法三:通过Run-time Settings中的Automatic Transactions自动生成事务
    注:该种方法插入的事务仅能在LoadRunner Controller中的图表和报告中看到在脚本的log中看不到。

    事务函数:
    lr_start_transaction 为性能分析标记事务的开始
    lr_end_transaction 为性能分析标记事务的结束
    lr_start_sub_transaction 标记子事务的开始
    lr_end_sub_transaction 标记子事务的结束以便进行性能分析
    lr_start_transaction_instance 启动嵌套事务(由它的父事务的句柄指定)
    lr_end_transaction_instance 标记事务实例的结束以便进行性能分析
    lr_get_transaction_duration 获取事务的持续时间(按事务的名称)
    lr_get_trans_instance_duration 获取事务实例的持续时间(由它的句柄指定)
    lr_get_transaction_think_time 获取事务的思考时间(按事务的名称)
    lr_fail_trans_with_error 将打开事务的状态设置为 LR_FAIL 并发送错误消息
    lr_get_trans_instance_wasted_time 获取事务实例浪费的时间(由它的句柄指定)
    lr_get_transaction_wasted_time 获取事务浪费的时间(按事务的名称)
    lr_resume_transaction 继续收集事务数据以便进行性能分析
    lr_resume_transaction_instance 继续收集事务实例数据以便进行性能分析
    lr_set_transaction_instance_status 设置事务实例的状态
    lr_set_transaction_status 设置打开事务的状态
    lr_set_transaction_status_by_name 设置事务的状态
    lr_stop_transaction 停止事务数据的收集
    lr_stop_transaction_instance 停止事务实例

    例子:
    Action()
    {
        long parent_trans_handle;
        long child1_handle;
        long child2_handle;
        double trans_time;
        int rc;
      //lr_start_transaction_instance(const char *transaction_name,long handle);
     //This function returns a unique long number which identifies the specific transaction instance. On error, a negative number is returned.
        parent_trans_handle =lr_start_transaction_instance("ParentTransaction",0);
        lr_output_message ("Parent transaction instance handle is %ld.", parent_trans_handle);
        web_url("web_url",
                  "URL=http://www.51testing.com",LAST);
     //lr_get_trans_instance_status(long transaction_handle);
        rc = lr_get_trans_instance_status(parent_trans_handle);
        lr_output_message("Parent Transaction status is %d.", rc);
        if (rc == LR_FAIL) {
     //lr_end_transaction_instance(long parent_handle,int status);
         lr_end_transaction_instance(parent_trans_handle, LR_FAIL);
         return;
        }
    //lr_start_transaction_instance(const char *transaction_name,long handle);
        child1_handle =lr_start_transaction_instance("ChildTransInstance", parent_trans_handle);
        lr_output_message("First child transaction instance handle is %ld.",child1_handle);
    http://www.51testing.com/?114582/
        web_url("web_url",
            "URL=http://www.51testing.com/html/blog.html",LAST);
    //lr_get_trans_instance_duration(long trans_handle);
        trans_time = lr_get_trans_instance_duration(child1_handle);
        lr_output_message("First child instance time is %lf seconds.",trans_time);
    //get_trans_instance_think_time(long trans_handle);
        trans_time =lr_get_trans_instance_think_time(child1_handle);
        lr_output_message ("First child instance think time is %lf seconds.",trans_time);
     //get_trans_instance_wasted_time(long trans_handle);
     trans_time = lr_get_trans_instance_wasted_time (child1_handle);
        lr_output_message("irst child instance waste time is %lf seconds.", trans_time);

    // tart_transaction_instance(const char *transaction_name,long handle);
      child2_handle = lr_start_transaction_instance("ChildTransInstance",parent_trans_handle);
      lr_output_message("Second child instance handle is %ld.", child2_handle);

          web_url("web_url",
            "URL=http://www.51testing.com/?114582/",LAST);
    //lr_get_trans_instance_duration(long trans_handle);
        trans_time =lr_get_trans_instance_duration(child2_handle);
        lr_output_message("Second child instance duration is %lf seconds.",trans_time );
        lr_end_transaction_instance(child2_handle, LR_PASS);
        lr_end_transaction_instance(child1_handle, LR_PASS);
       trans_time =lr_get_trans_instance_duration(parent_trans_handle);
        lr_output_message ("Parent Transaction duration is %lf seconds.",trans_time );
        lr_end_transaction_instance(parent_trans_handle, LR_PASS);

        return 0;

    }

  • 再说“事务”

    iory 发布于 2010-05-23 23:24:38

    从下面的例子我们可以得出几个结论:

    只要是步骤都会消耗时间,包括lr_start_transaction(),lr_end_transaction()等

    lr_get_transaction_duration:duration可以是lr_start_transaction到lr_get_transaction_duration之间,lr_stop_transaction到lr_get_transaction_duration之间,而transaction stop之前的时间不算在内

    lr_stop_transaction:stop transaction之前的时间不计算

    lr_resume_transaction:一旦resume transaction,那就要从start transaction开始计时

    例子:
    Action()
    {
    int i;
    int iteration=100;
    char aStr[100];
    lr_start_transaction("stop&start");
    for(i=0;i<iteration;++i)
    {
    sprintf(aStr,"%d",i);
    lr_log_message("%d",i);
    }

    lr_output_message("First time=%f",lr_get_transaction_duration("stop&start"));//0.985325=start transaction+iteration1

    lr_stop_transaction("stop&start");
    lr_output_message("Immediatly after stop=%d",lr_get_transaction_duration("stop&start"));//-1639921593
    for(i=0;i<iteration;++i)
    {
    sprintf(aStr,"%d",i);
    lr_log_message("%d",i);
    }
    lr_output_message("After stop and loop = %f",lr_get_transaction_duration("stop&start"));//0.991988=stop
    transaction+iteration2

    lr_resume_transaction("stop&start");
    lr_output_message("After resume time=%f",lr_get_transaction_duration("stop&start"));//2.011729=start transaction from start transaction to here1
    for(i=0;i<iteration;++i)
    {
    sprintf(aStr,"%d",i);
    lr_log_message("%d",i);
    }
    lr_output_message("After resume and loop = %f",lr_get_transaction_duration("stop&start")); //3.124461=all the time from start transaction to here2
    lr_end_transaction("stop&start", LR_AUTO);
    //3.1340=all the time from strart transaction to here3

    return 0;

    }

  • Loadrunner脚本编程1

    iory 发布于 2010-05-24 16:16:33

    就目前的了解。Loadrunner的脚本语言其实和C没什么区别。他内部的好多机制都是C实现的。

    不过是一种“类C”

    所以我从几个方面分析

    1:定义常量变量和C一样

    2:LR函数的参数使用与C有点不一样, 在LR中,C的变量和LR的参数是不一样的。
    任何C的变量都不能被LR的函数直接调用。
    应该用lr_eval_string来取值。

    3:什么循环语句,选择语句都和C一样

    4:一些函数的定义和C不一样。虽然名字一样,参数有不同

    5: 输入输出也有些不同。


    所以重点要突破的地方就是理清参数和变量直接的关系。和多熟悉一LR些函数,其他就是C语言的知识了。

    lr它有自己管理的变量,也叫参数,这种参数只能通过reg或者lr_save_方式定义,或者通过文件定义.

    1.参数的赋值和取值

    lr_save_string("hello world","param");
    lr_eval_string("{param}");


    2.变量到参数
    int x;
    x=10;
    lr_save_string(x,"param");
    lr_eval_string("{param}");


    3.变量读参数
    char x[100];
    strcpy(x,"{param}");
    lr_save_string("hello world","param");
    lr_log_message("%s",lr_eval_string(x));

    LoadRunner没有提供对参数的算术运算的函数。所以LR的参数必须:

    1) 转换成C的整数

    2) 使用C的函数来运算最后返回一个C的字符串

    3) 把返回的字符串保存成参数


    view plaincopy to clipboardprint?
    // 1. 转换成C的整数:      
         
    i = atoi( lr_eval_string("{pNum_in}") );      
         
    // 2. 使用C的函数来运算最后返回一个C的字符串:      
         
    sprintf( cBuf, "%d", i+1);       
         
    // 3.把返回的字符串保存成参数:      
         
    lr_save_string( cBuf, "pNum_out");   
    // 1. 转换成C的整数:  

    i = atoi( lr_eval_string("{pNum_in}") );  

    // 2. 使用C的函数来运算最后返回一个C的字符串:  

    sprintf( cBuf, "%d", i+1);   

    // 3.把返回的字符串保存成参数:  

    lr_save_string( cBuf, "pNum_out");  


    lr_eval_string()

    函数的主要作用:返回脚本中的一个参数当前的值,

    返回值类型:char

    一般多用在调试脚本时输出参数的值.具体用法如下:
    lr_output_message("The parameter1's value is %s",lr_eval_string("{parameter1}")),其中参数parameter1在之前已经定义了的参数

    lr_log_message(lr_eval_string("{parameter1}"))


    在LR中,C的变量和LR的参数是不一样的。
    任何C的变量都不能被LR的函数直接调用。
    应该用lr_eval_string来取值。
    比如{NewParam}(LR中参数化的变量)直接用这个引用是没有问题的。
    但是如果如下:

    Action()
    {
        char a[10];
        a="{param}";
        lr_message(a);
        return 0;
    }

    这就不对了。
    lr_message(a);就会报错。但是写成lr_message(lr_eval_string(a));就可以。

    Action()
    {
    char a[10];
        lr_save_string("hello","param");
        strcpy(a,"{param}");
        lr_message("%s",lr_eval_string(a));
        return 0;
    }
    因为这里的值已经取出来了。

    ********** 参数和变量传递 ***********/
    Variable( )


    char* ip =lr_get_vuser_ip();//获取当前用户的IP地址,保存在IP变量里。
    char* gname =lr_get_host_name();//获取当前用户的机器名,保存在GNAME变量里。

    if(ip)
    /* 参数转变量 */   //RunTime是已定义的参数,下文也可以直接调用
              lr_vuser_status_message("Ip地址: %s ,参数 : %s",ip,lr_eval_string("{RunTime}"));
    else
               lr_vuser_status_message("未启动IP欺骗……");

    /* 变量转参数 */
       lr_save_string(gname, "GN" );//把变量IP存在“GN”参数里,下文可以直接用 {GN} 调用。


    /* 参数输出 */
    web_submit_data("StatusReporter",
        "Name=title", "Value={RunTime}",ENDITEM,
       "Name=content", "Value={GN}",ENDITEM,
       LAST);


    /* 变量输出 */
       lr_output_message("当前IP地址: %s ",ip);

       lr_think_time(2);//停顿两秒便于观察。

       return0;
    }

    最初我想实现用web_reg_save_param()取到的数保存在数组中,并lr_eval_string()来显示数组中的各个元素。代码如下:
    web_reg_save_param("test","LB=","RB=","ORD=All",LAST);
    web_url();
    count = lr_eval_string("{test_count}");
    for (i=1;i<=count,i++)
    sprintf(str,lr_eval_string("{test_%d}"),i);
    但是每次得到的数据总是
    str = test_1 test_2.....都不是数组中的元素。
    其实这个问题就是没有搞懂lr中内部参数和外部参数的区别
    web_reg_save_param()中取到的数组,是属于lr的内部函数,在其内部函数中再使用变量,即(test_%d,i),是不能直接取到元素的值。这个中间必须要通过变量(外部变量)来传递。
    上述代码改为:
    web_reg_save_param("test","LB=","RB=","ORD=All",LAST);
    web_url();
    count =atoi( lr_eval_string("{test_count}"));
    for (i=1;i<=count,i++)
    {
    sprinf(tmp,"{test_%d}",i);
    sprintf(str,lr_eval_string(tmp));
    }
    这样就能实现了。


    lr_save_string


    The lr_save_string function assigns the specified null-terminated string to a parameter. This function is useful in correlating queries. To determine the value of the parameter, use the lr_eval_string function.

    来自: http://hi.baidu.com/cbxm/blog/item/7bfed4ac972ab3024b36d6b9.html

  • Loadrunner脚本编程2

    iory 发布于 2010-05-24 16:26:20


    Web用户Action


        在VuGen中,脚本产生的默认模式是基于HTML的--“描述用户的动作的脚本”直接与用户的动作是对应的:

        * web_url是浏览器地址栏的URL.

        * web_link是点击在<a href= P>

        * web_image是点击HTML的<img href= P>

        * web_submit_form. 是在前面操作的上下文中的GET或PUT表单上点“提交”--可能前面的操作被VuGen在基于HTML模式下录制下来了。

        * web_submit_data 是在GET或PUT表单上点“提交”,而没有带前面操作的上下文--可能是在基于URL模式下录制,或者是基于HTML模式,并且选择了“A scrīpt containing explicit URLs only”选项。

         不用HTML产生的资源是.gif和.jpg图片。资源属性的列表只能当对这些资源的路直选项设置成“Record within the current scrīpt step”时被插入。这也是默认的设置。

          如果你在“Tools > Internet Procotol > Recording”中选择“a scrīpt containing explicit URLs only”,这将会产生URL-based的脚本录制,只使用web_url和web_submit_data函数,将不会使用 web_link 和 web_image函数,或包含在 applets, XML, ActiveX或javascrīpt中的非HTML元素。

    在进行下一页录制之前(如点击链接或者图标),暂停录制,把该页屏幕的标题拷贝下来粘贴到注释中。录制完成之后,这将会在后面的给事务命名上用到。

    在每一个页面显示之后,暂停录制,把决定是否是期望页的文本拷贝下来,粘贴到注释中。录制完成之后,这将会用到文本验证检查点的脚本编写中。

         录制中产生的各种信息都保存在RecordingLog.txt文件中,删除它不会对脚本的回放产生影响。

    额外录制的Action脚本


        录制脚本的时候,当浏览器没有安装SSL根证书的时候,会捕获的下面这些代码行。这个信息意思是“这个证书不能被信任证书验证”。

       web_url("authrootseq.txt",

    "URL=http://www.download.windowsupdate.com/msdownload/update/v3/static/trustedr/en/authrootseq.txt",

    "Resource=1",
    "RecContentType=text/plain",
    "Referer=",
    web_url("authrootstl.cab",

    "URL=http://www.download.windowsupdate.com/msdownload/update/v3/static/trustedr/en/authrootstl.cab",
    "Resource=1",
    "RecContentType=application/octet-stream",

    "Referer=",

    LAST);


    录制脚本的时候,但浏览器遇到Macromedia flash组件的时候,会产生下面的代码行:

    "URL=http://fpdownload.macromedia.com/pub/flashplayer/update/current/xml/version_en_win_ax.xml",
    "Resource=0",
    "RecContentType=text/html",
    "Referer=",

    "Snapshot=t8.inf",
    "Mode=HTML",
    LAST);
    web_url("version_en_win_ax.xml",


          如果你安装有Google Toolbar,即使你没有访问Google,也会录制上发到Google的请求。
    脚本语言规则:
    在LoadRunner中,大小写是敏感的,甚至在被检验的值中。所以上面的脚本会因为大写字母的原因,不会识别“Welcome”的。所以Steve Cheney 建议使用“ic”忽略大小写的文字标志:
    web_reg_find("Text/ic=Welcome",LAST);
    括号里的参数包含了LAST 是为了指定最后的一个参数。这样做是很方便的,因为上面的例子漏掉了一个指定期望是“found”还是“notfound”的属性。默认是“found”,所有我经常忽略它。
    另一个文本标志是“/BIN”用来指定是二进制的字符集。例如,查找“Adams”:
    web_reg_find("Text/BIN=\\x00A\\x00d\\x00a\\x00m\\x00s",LAST);
    注意两个反斜杠,一个是转义字符,代表是使用了一个符号。如果错误的只使用一个反斜杠,LR会认为它是一个空的终止。
          下面的例子脚本是在UTF8服务器上支持获得newquoteuid为UTF-16编码。因为LoadRunner中,UTF16编码的“Red”用ASCII是 R\x00e\x00d\x00 这样的,所以需要把它保存到buffer中。
    lr_eval_string_ext("{newquoteuid_temp}",
    strlen("{newquoteuid_temp}") + 2,
    &Buf, &BufLen, 0, 0, -1);
    对字符数组变量NewBuf使用lr_save_var函数来去掉额外的填充(x00):
    for (i=0; i if (Buf[i]!=0) NewBuf[NewBufLen++]=Buf[i];
    lr_save_var(NewBuf, NewBufLen-1, 0, "newquoteuid");
    注:lr_save_var 需要四个参数(不需要使用LAST)
    1.param_value 参数值
    2 value_len 参数的长度。
    3 options 参数的选项,一般为0
    4。param_name 参数名称

    lr_save_var

    Saves a variable length string to a parameter.

    lr_eval_string function.

    Returns the string argument after evaluating embedded parameters.

    The lr_save_var function assigns the specified variable length string to a parameter. This function is useful in correlating queries. To determine the value of the parameter, use the


    LoadRunner 7.8不支持正则表达式,但是有他自己的通配符:
    为了使任何[0-9] 的数字在指定的数字位置,使用/DIG做标志:
    web_reg_save_param("pSer","LB/DIG=Serial XXX-###-ZZZZ","RB=\r\n", LAST );
    有三种使用^做通配符的方法:
    * 忽略大小写,并且允许在指定的字符位置使用任意字符:
       web_reg_find("Text/ALNUMIC=^ercury", LAST);
    * 允许任何小写字符[a-z] 在指定位置:
       web_reg_find("Text/ALNUMLC=^ercury", LAST);
    * 允许任何大写字符[A-Z]在指定的字符位置:
       web_reg_find("Text/ALNUMUC=^ercury", LAST);
    把一个字符串变成大写:strupr()
    错误信息:
    请添加一些其他的错误信息来帮助其他人:
    Could not resolve address of host ... [MsgId: MERR-27798]
    如果网络不能用或者域没有注册的话,显示一个404的DNS错误

    Contents unexpectedly not in cache. [MsgId: MERR-26549]
    当一个文件为空时会显示该错误。在空文件中添加空格来满足LoadRunner的错误检查。BTW,因为当创建的iframe没有文件时,IE会产生一个错误,这样就指定了一个空文件。

    事务时间脚本编写:

    我更喜欢给一个action命名事务,而不是一个结果页面。

    lr_start_transaction("00.1 Invoke URL");
    ...
    lr_end_transaction("00.1 Invoke URL",LR_AUTO);
    ...
    lr_start_transaction("01.2 Top menu");

    ...
    lr_end_transaction("01.2 Top menu",LR_AUTO);


    lr_start_transaction("02.0 Updating");

    lr_start_sub_transaction("02.1 Update menu","02.0 Updating");

    web_url( ...

    lr_end_sub_transaction("02.1 Update menu",LR_AUTO);
    lr_start_sub_transaction("02.2 Update submit","02.0 Updating");

    web_submit_form( ...
    lr_end_sub_transaction("02.2 Update submit",LR_AUTO);
    lr_start_sub_transaction("02.3 Update OK","02.0 Updating");
    ...
    lr_end_sub_transaction("02.3 Update OK",LR_AUTO);


    lr_end_transaction("02.0 Updating",LR_AUTO);
    我喜欢在一个层次结构中使用0填充的事务名称,这样来确保控制器能够正确的给事务排序。

    我对不同类型的action上的事务名称上加不同的关键字
    Contact Link = Click "Contact" link on Menu
    Contact Icon = Click "Contact" Icon
    Regis. Sub = Page Submit
    OK = Pop-up dismiss with OK
        事务名可以是变量,但是它只能被VuGen作为字符串来编译,不能在控制器的接口中显示。无论如何,他们会显示在分析结果文件中。

         对于web脚本,LR自动创建和决定事务的的持续时间,但是C语言脚本可以使用这些函数:

         使用lr_start_transaction_instance函数来显式获得指定事务实例的句柄,事务名称在函数lr_user_data_point_instance或lr_user_data_point_instance_ex中使用。

          使用 lr_start_sub_transaction在一个事务中来操作思考时间和消耗的时间。

    来自: http://hi.baidu.com/cbxm/blog/item/a7a8e9f56a6b0ee47609d7ba.html

  • Loadrunner脚本编程3- 检查点,关联等函数

    iory 发布于 2010-05-24 16:29:13

    1. 错误预防和恢复

    参数默认是用{}括起来的,但也可以指定用<>

    NTLM或用户登录验证

    web_set_user("X\\Y", "Z", "A.com:80");

    在域与X上的用户名为Y的用户,使用密码Z来登录到A.com:80。在windows基本验证的时候这个脚本被默认录制下来,但如果web服务器需要更安全的NTLM或更深层次的验证,需要手动的添加这个函数到脚本中。对于NTML验证,用户名必须在域名之后,并且以\分割。使用\等符号,需要使用\\,前面的\用来做转义用,否则会出现警告提示。

    zibeike注:在论坛中也看到了一些朋友讨论windows弹出登录框的操作LR无法录制到,导致回放出错,一般出错信息多为“Error -26547: Authentication required, please use web_set_user, e.g. web_set_user("domain\\user", "password", "host:port");   [MsgId: MERR-26547]”,其实这种情况错误信息已经很明显的给你提示了,需要往脚本中添加web_set_user函数即可。

    2. IP欺骗(略)

    3. 验证检查点

    通常脚本录制完后需要手动添加些脚本来来确保预期的操作确实进行了正确的响应(如在操作之后后验证显示的一段文本或者图片)。这些检查可以使用正则表达式。

    Web虚拟用户脚本中不会录制到检查点,需要手动添加或者使用VuGen的用户接口来添加函数代码。

    最常用的检查点函数是web_reg_find。这个注册函数会查找脚本中下一个操作如web_url后产生的一段文本。它是从返回的缓冲区扫描而不是在接收的页面中查找。这是比web_find更高效的一个函数。

    可以使用下面的代码来验证文本出现的次数:

    web_reg_find("Text=ABC", "SaveCount=abc_count", LAST);
    web_url("Step", "URL=...", LAST);
    if (strcmp(lr_eval_string("{abc_count}"), "0") == 0)
    lr_output_message("not found");

    else

    lr_output_message("{abc_count} found");

    如果想保存并且显示找到的文本,可以使用web_reg_save_param界定左右边界把找到的信息保存到参数中。如下:

    char *str1,*str2;
    str1="desired text";
    // Register the left and right beacons sought:
    web_reg_save_param("param","LB/ic=xxx","RB=xxx");
    // Do the monitored deed:
    web_url("some url","URL=www.xxx.com",LAST);
    // Compare:
    str2=lr_eval_string("{param}");
    if(strcmp(str1,str2)==0) {
    lr_output_message("param found");

    }else{

    lr_output_message("Value found is %s",str2);

    }

    zibeike注:1)这里想跟大家说下注册函数,在web/http协议的脚本中,注册函数均以web_reg为前缀,这种注册型的函数都是从缓冲区扫描或者获得数据,因此需要提前声明即需要在能获得该查找信息的函数之前添加这些注册函数。例如,web_url()请求了一个页面,我需要验证该页面中是否有某个特定的文本,那需要在web_url()函数之前加上web_reg_find,类似的还有关联的函数web_reg_save_para是一样的,需要放到能获得想要的数据的请求的函数之前。但如果想查看这些函数最终保存的结果,如想打印关联函数web_reg_save_para中保存的参数内容,打印的操作就需要放到请求的函数之后了。

    2)web_find和web_reg_find的区别:前面的是查找页面显示的数据,因此需要放在请求页面的函数之后,而且查找的信息是显示的web页面上的信息。后者是注册型函数,需要放到请求的页面之前,而且查找的内容是服务器返回的缓冲数据中查找,所以查找内容应该看html源代码的内容。

    基于HTML录制方式的代码,可以使用web_image_check对HTML页面中包含的图片进行验证。并且需要注意的是只有在Runtime Settings > Internet Protocol Preferences 选择了"Enable Image and text check" 检查点才有效。

  • Loadrunner脚本编程4-数据类型操作和字符串操作

    iory 发布于 2010-05-24 16:31:16

    一,数据类型转换

    没有使用过C编程的LoadRunner脚本编写者会发现在数据类型转化方面比较困难。下面介绍这方面的知识。

    1. 相似函数的输出在不同的位置

    象很多C函数一样,使用atoi函数的结果即为返回值

    如intResult = atoi( charY );

    而:itoa的返回结果为第二个参数。

    itoa( intX, charY, 10);

       第一个参数是需要转换的数字,第二个参数是转换后存储的字符数组,需要注意的是数组必须定义为固定的长度,如:char chary[20];

    数组的最大长度为32064(32K),否则会出现“too many variables”编译错误。

    如果定义为变长的字符串如char *charY,则程序会出错。

       第三个参数不是数组的长度,而是数字的基数,10进制是最常用的,其他还有二进制,八进制,十六进制。

    2. 有一些函数实现了同样的功能

    itoa不是一个标准的ANSI C函数但是是C的stdlib.h中的一个函数。所以它不被包括在unix机器上的LibC中。我们可以使用标准的sprintf函数来代替:

    sprintf(charY,“%d”,intX);

    sprintf

    Writes formatted output to a string.

    3. 是用%X来转换一个十六进制数

    int intNum;

    sscanf(“ffff”,“%X”,&Num);

    lr_output_message(“%d”,intNum); // 打印65535 ,ffff的整数值

    sscanf

    Reads formatted input from a string.

    4. 从文本中提取数字的规则

    如果第一个字符不是数字或者为空,atoi返回0,即“e24”会返回0

    atoi 转换一个非数字的字符会返回组成这个字符的数字,如“-3.2”返回-3.0。“123XXX345”返回123。

    Converts a string to an integer value.

    atoi reads the initial portion of the string only, by stopping at the first non-numerical character.

    5. LoadRunner脚本中的参数必须转换成C字符串。有两种方式来转化LR的参数为C语言的数字。

    i = atoi( lr_eval_string("{pX}") );

    sprintf( intX, "%d", lr_eval_string("{pX}") );

    lr_eval_string

    Returns the string argument after evaluating embedded parameters.

    The lr_eval_string function returns the input string after evaluating any embedded parameters. If string argument contains only a parameter, the function returns the current value of the parameter.

    Embedded parameters must be in brackets.

    6. 参数的算术运算

    LoadRunner没有提供对参数的算术运算的函数。所以LR的参数必须:

    1) 转换成C的整数

    2) 使用C的函数来运算最后返回一个C的字符串

    3) 把返回的字符串保存成参数


    view plaincopy to clipboardprint?
    char cBuf[10];    
      
    int i;    
      
    // 1. 转换成C的整数:   
      
    i = atoi( lr_eval_string("{pNum_in}") );   
      
    // 2. 使用C的函数来运算最后返回一个C的字符串:   
      
    sprintf( cBuf, "%d", i+1);    
      
    // 3.把返回的字符串保存成参数:   
      
    lr_save_string( cBuf, "pNum_out");    
      
    //Print out the parameter value after incrementing it.   
      
    lr_message("**** Parameter from %s to %s",   
      
         lr_eval_string("{pNum_in}"));    
      
         lr_eval_string("{pNum_out}"));  
    char cBuf[10];

    int i;

    // 1. 转换成C的整数:

    i = atoi( lr_eval_string("{pNum_in}") );

    // 2. 使用C的函数来运算最后返回一个C的字符串:

    sprintf( cBuf, "%d", i+1);

    // 3.把返回的字符串保存成参数:

    lr_save_string( cBuf, "pNum_out");

    //Print out the parameter value after incrementing it.

    lr_message("**** Parameter from %s to %s",

         lr_eval_string("{pNum_in}"));

         lr_eval_string("{pNum_out}"));

    zibeike注:除了对于数字类型的参数的运算之外,对于文本形式的参数的操作,可以参考我的另一篇文章的内容:http://www.51testing.com/?34866/action_viewspace_itemid_75592.html

    二.字符串操作

    在C语言中,字符串是固定长度的,因为他们本身由独立的字符组成的字符数组。数组是只读的。任何修改字符串长度的函数调用都会报错:

    Error: "C interpreter runtime error - memory violation error during replay.

    在LoadRunner的as_web.h库中的字符串函数可以使用“prototyping”声明的方式读写内存:

    char *strtok(char *, char *); // tokenizer prototype
    char *strstr(char *, char *); // substring prototype
    char *strdup(char *); // String duplication prototype
    float atof(); // alpha to return float datatype
    #include "as_web.h"
    char *strtok(char *, char *); // prototype function call.

    ActionX()
    {
       char aBuffer[256]; // input string to be parsed.
        char *cToken; // individual token from strtok.
       char cSeparator[] = " "; // blank separator.
       int i; // incrementer
       char val[3][20]; // output array of strings.
       char modified_val[20];
       
       // 创建一个参数pDate:
       lr_save_string("January 2, 2001", "pDate");
    // 把参数放到字符串缓冲Put parameter into a string buffer:
       //strcpy:Copies one string to another.
    //lr_eval_string:Returns the string argument after evaluating embedded parameters.
       strcpy( aBuffer,lr_eval_string("{pDate}"));

       //在调试中显示这个buffer Show the buffer for debugging:
    //lr_output_message:Sends a message to the log file and Output window
       lr_output_message("%s\n",aBuffer);

       // get first word (to the first blank):
    //strtok:Returns a token from a string delimited by specified characters.
        cToken = strtok( aBuffer,cSeparator);
       i = 1;

       if(!token) { // first token was not found:
               lr_output_message("No tokens found in string!");
               return( -1 );
       } else {
               while( cToken != NULL) { // tokens are not NULL:
                       lr_output_message("Token=%s", cToken);

                       // Stuff in another array:
                       strcpy( val[i], cToken );

                       // Get next token:
                       cToken = strtok( NULL, cSeparator);
                       i++; // increment
               }
               lr_output_message("Val #1 is: %s", val[1]);
               lr_output_message("Val #2 is: %s", val[2]);
               lr_output_message("Val #2 is: %s", val[3]);

               strncpy( modified_val, val[2], 1 );
               modified_val[2] = '\0';
               while (modified_val[2] != NULL) {
                       lr_output_message("===>%s", modified_val);
                       modified_val[2] = strtok(NULL, " ");
               }
       }
       return 0;
    }

    strcat 连接两个字符串

    strchr 返回指向第一个要查找的字符出现的位置的指针

    strcmp 比较两个字符

    strcpy 复制字符串到另一个

    stricmp 执行一个大小写敏感的比较

    其他还有strdup,strncat,strncpy,strnicmp,strrchr,strset,strspn,strstr等字符串操作的函数。

    zibeike注:关于更多字符串操作的脚本编写,可以参考我的另一篇文章:

    http://www.51testing.com/?34866/action_viewspace_itemid_75428.html

    zibeike翻译自:http://www.wilsonmar.com/1lrscrīpt.htm

    LoadRunner中常用的字符串操作函数有:

                   strcpy(destination_string, source_string);

                   strcat(string_that_gets_appended, string_that_is_appended);

                   atoi(string_to_convert_to_int); //returns the integer value

                   itoa(integer_to_conver_to_string, destination_string, base); // base is 10

                   strcmp(string1, string2); // returns 0 if both strings are equal

    对各函数的定义:

                 strcpy( ):拷贝一个字符串到另一个字符串中.

                 strcat( ):添加一个字符串到另一个字符串的末尾。

                strcmp( ):比较两个字符串,如果相等返回0。

                atoi():转换一个ASCII字符串为一个整型。

                itoa():根据给定的进制,转换一个整型数据为ASCII字符串

    下面的例子使用了上面这些函数:


    view plaincopy to clipboardprint?
                    
      
    Actions()   
      
    {   
      
            char MyString1[20] = "";   
      
            char MyString2[20] = "";   
      
            char MyString3[20] = "Mercury2";   
      
            char Cstring[10] = "12345";   
      
            int Cint;   
      
        
      
        
      
            // MyString1 is empty    
      
            //   
      
            lr_output_message(">>>>>>>>>> MyString1 = %s",MyString1);   
      
        
      
            // copy "Mercury1" into MyString1   
      
            //   
      
            strcpy(MyString1,"Mercury1");   
      
        
      
            // Now MyString1 contains "Mercury1"   
      
            //   
      
            lr_output_message(">>>>>>>>>> MyString1 = %s",MyString1);   
      
        
      
        
      
            // Copy MyString3 into MyString2   
      
            //   
      
            lr_output_message(">>>>>>>>>> MyString2 = %s",MyString2);   
      
            strcpy(MyString2,MyString3);   
      
            lr_output_message(">>>>>>>>>> MyString2 = %s",MyString2);   
      
        
      
        
      
            // Catenate MyString2 to MyString1   
      
            //   
      
            strcat(MyString1,MyString2);   
      
            lr_output_message(">>>>>>>>>> MyString1 = %s",MyString1);   
      
        
      
            // Cstring is converted to integer Cint   
      
            //   
      
            lr_output_message(">>>>>>>>>> Cstring = %s",Cstring);   
      
            Cint = atoi(Cstring);   
      
            lr_output_message(">>>>>>>>>> Cint = %d",Cint);   
      
        
      
            // Cint is converted to string   
      
            Cint = 100;   
      
            itoa(Cint,Cstring,10);   
      
            lr_output_message(">>>>>>>>>> Cstring = %s",Cstring);   
      
        
      
            return 0;   
      
    }
                

    Actions()

    {

            char MyString1[20] = "";

            char MyString2[20] = "";

            char MyString3[20] = "Mercury2";

            char Cstring[10] = "12345";

            int Cint;

            // MyString1 is empty

            //

            lr_output_message(">>>>>>>>>> MyString1 = %s",MyString1);

            // copy "Mercury1" into MyString1

            //

            strcpy(MyString1,"Mercury1");

            // Now MyString1 contains "Mercury1"

            //

            lr_output_message(">>>>>>>>>> MyString1 = %s",MyString1);

            // Copy MyString3 into MyString2

            //

            lr_output_message(">>>>>>>>>> MyString2 = %s",MyString2);

            strcpy(MyString2,MyString3);

            lr_output_message(">>>>>>>>>> MyString2 = %s",MyString2);

            // Catenate MyString2 to MyString1

            //

            strcat(MyString1,MyString2);

            lr_output_message(">>>>>>>>>> MyString1 = %s",MyString1);

            // Cstring is converted to integer Cint

            //

            lr_output_message(">>>>>>>>>> Cstring = %s",Cstring);

            Cint = atoi(Cstring);

            lr_output_message(">>>>>>>>>> Cint = %d",Cint);

            // Cint is converted to string

            Cint = 100;

            itoa(Cint,Cstring,10);

            lr_output_message(">>>>>>>>>> Cstring = %s",Cstring);

            return 0;

    }

    //To send an error message to the LoadRunner output window or Application Management agent log,
    use the lr_error_message function.
    It is not recommended that you send a message to the output window or agent log in the middle of a transaction,
    as it will lengthen the execution time. To send a message to the Vuser execution log or Application Management Web site,
    but not to the Output window, use lr_log_message.

  • loadrunner编写脚本5

    iory 发布于 2010-05-24 16:35:16

    VUser_Init部分

    这里是Vuser_init部分的一些例子:

    操作系统的User ID

    下面显示了使用advapi32.dll的GetUserNameA函数获得的操作系统的用户ID

           char   sUserID[1024]; // Maximum possible UserID length.

           long   lUserIDSize = sizeof(sUserID)-1;

           int   rc;


           rc=lr_load_dll("advapi32.dll");

           if( rc != 0 ){

                  lr_error_message("lr_load_dll of advapi32.dll failed. Aborted for rc=%d",rc);

                  lr_abort();

           }else{

                  GetUserNameA(sUserID, &lUserIDSize);

                  lr_message("UserID='%s'", sUserID);

           }

    所有的变量声明需要一块放到最上方。在vuser_init部分创建的本地C变量(如int或char)对其他部分的脚本是不可见的。所以使用lr_save_string函数来创建对所有脚本可用的全局参数。例子:

     

    char *itoa ( int value, char *str, int radix );

    vuser_init(){

           int x = 10;

           char buffer[10];

           lr_save_string(itoa( x, buffer, 10) , "pX" );

           lr_message ( "int x = %s", lr_eval_string("{pX}" ));

    return 0;

    }

     

    运行时设置的附加属性(Additional Attribute)

    8.0版本引进了一个非常有价值的特性:在运行时设置中指定属性,这个属性可以对不同的虚拟用户组设置不同的值。


    下面的代码是从运行时设置的附加属性中读取名为“usertype”的参数。然后使用参数值来对应的设置全局的"thinktime1"变量。

     

    int thinktime1=0;


    vuser_init(){


    LPCSTR strUsertype; // Define *str.

    str Usertype =lr_get_attrib_string("usertype");

    if (strUsertype==NULL){

    lr_output_message("### Run-time Settings Additional Attribute usertype not specified. Cannot continue.");


    lr_abort();


    }

    else{

     


    lr_message("### Run-time Settings Additional Attribute usertype=\"%s\"", strUsertype );

    if( strcmp( strUsertype,"advanced") == 0 )

    { thinktime1=2; }
    else
    if


    ( strcmp( strUsertype,"intermediate") == 0 ){ thinktime1=4; }


    else
    }

    if( strcmp( strUsertype,"basic") == 0 )

    { thinktime1=8; }

    else

    {

    lr_error_message("### ERROR: Value not recognized. Aborting run." );

    lr_abort();

    }

    }
    return 0;

    }


    Time Structure Fix(不知道怎么翻译,呵呵,“时间结构的解决“?)

    根据知识库34195的文章,默认当前时间戳的毫秒部分不被更新,除非ftime使用的时间结构被重新定义:


      

    typedef long time_t;

    struct _timeb {

      time_t time;

      unsigned short millitm;

      short timezone;

      short dstflag;

    };

    struct _timeb t;

    _tzset(); \\使用ftime设置变量

    _ftime( &t );

    lr_message( "Plus milliseconds: %u", t.millitm );

    控制信息的显示:

    在运行时,当脚本的事务失败后继续,你怎么知道哪个用户失败了?

    在每个失败的事务之后,发出一个能够唯一确定该用户的信息。

    Loadrunner提供了一些函数来在运行时显示信息:

     

    ·//往输出日志上发送消息,这个消息前边会带有action的名称和行数

    lr_output_message("an output message");


    --------------------------------------------------------------------------------

     

      例子:

    ·Actions.c (4): an output message

    ·//往输出日志和虚拟用户日志上发消息:

     

    ·  lr_message("*** a message"

    +"\r"+"A new line."

    );

    把");"放到另一行,这样可以容易的在命令上添加或者删除代码项。

      在UNIX/Linux机器上,使用"\n"来添加一个换行。

      在Windows机器上,使用"\r"来添加一个换行。

    //往输出日志上发送不带action名称和行数的信息
    lr_log_message("number\t"+ numvar +"\t");


    //只给控制器上的虚拟用户状态区域发送信息(当在VuGen中运行时,只是简单的显示):lr_vuser_status_message("a vuser status message");


    //给LoadRunner控制器或者Tuning模块的控制台输出窗口显示一个红色高亮度显示的-17999信息。lr_error_message("an error message");

     

  • 调试信息函数

    iory 发布于 2010-05-24 22:55:14

    int lr_set_debug_message (unsigned int message_level, unsigned int on_off);


    中文解释:lr_set_debug_message函数设置脚本执行的调试消息级别message_lvl.通过设置消息级别,可以确定发送哪些信息。 启动设置的方法是将LR_SWITCH_ON作为on_off传递,禁用设置的方法是传递LR_SWITCH_OFF.参数message_level说明:

     日志级别

     C语言标志

     值

     Runtime-setting - Log操作

     Disabled  LR_MSG_CLASS_DISABLE_LOG  0  不勾选Enable logging
     Brief  LR_MSG_CLASS_BRIEF_LOG  1  勾选Standard log
     Extended Log  LR_MSG_CLASS_EXTENDED_LOG  16  勾选Extended log
     Result Data  LR_MSG_CLASS_RESULT_DATA  2  勾选Data returned by server
     Parameter Substitution  LR_MSG_CLASS_PARAMETERS  4  勾选Parameter substitution
     Full Run-Time Trace  LR_MSG_CLASS_FULL_TRACE  8  勾选 Advanced trace
     Only on error  LR_MSG_CLASS_JIT_LOG_ON_ERROR  512  勾选send messages only when an error occurs

    参数on_off说明:
     
      「LR_SWITCH_ON」启用设置
     
      「LR_SWITCH_OFF」禁用设置

    lr_get_debug_message返回的int数其实是所有勾选操作的代表值相加!

    例子:

    Action()
    {
    //设置runtime-setting的日志选项【不勾选Enable logging】
     char *a;
     a = "ABC";
     lr_set_debug_message (LR_MSG_CLASS_EXTENDED_LOG |LR_MSG_CLASS_PARAMETERS,LR_SWITCH_ON);
     //打开Runtime-setting Log 的Parameter substitution设置
     lr_debug_message(LR_MSG_CLASS_PARAMETERS,"打开参数保存的系统日志");
     lr_save_string("aa",a);
     lr_debug_message(LR_MSG_CLASS_PARAMETERS,"关闭参数保存的系统日志");
     lr_set_debug_message (LR_MSG_CLASS_EXTENDED_LOG |LR_MSG_CLASS_PARAMETERS,LR_SWITCH_OFF);
     //关闭Runtime-setting Log 的Parameter substitution设置

     return 0;
    }

     

       因为设置了runtime-setting不打印任何日志,所以正常运行脚本应该没有任何日志输出;
     
      但是使用lr_set_debug_message函数打开了日志的设置(输出保存参数操作的日志)
     
      因此脚本运行到lr_save_string("aa",a)时,就输出了日志如下:
     
      打开参数保存的系统日志
     
      Action.c(7): Notify: Saving Parameter "ABC = aa".关闭参数保存的系统日志

     

    注:页面的runtime-settings更为方便,推荐使用F4


  • QTP中的步骤生成器

    xiaonan 发布于 2006-12-25 10:38:19

        在我们录制脚本过程中,可能会遇到这样一种情况.用object spy能识别到某个对象,但录制的时候脚本就是没生成下来.当然如果你对QTP的原理比较熟悉,可以直接把对象加到对象库中,再自己手工写代码.这当然是个比较好的解决方法.但碰到对QTP不是很熟,对vbscrīpt的语法比较陌生的朋友来说,可能需要花点功夫了.但事实上QTP还提供给我们一个方便操作的工具,叫做步骤生成器.在insert菜单里能够找到,当然按一下F7能直接调出这个工具.

      先来介绍一下这个工具.“步骤生成器”对话框有助于快速轻松地添加一些步骤,这些步骤使用测试对象方法、实用程序对象方法和函数调用,因此用户无需记住语法或者精通高级 VBscrīpt。既可在关键字视图中,也可在专家视图中使用步骤生成器。

      接下来用一个小例子来说明这个步骤生成器的使用.

    比如在QTP自带的fight程序里,在填好相应信息后,按下insert order会生成一个定单号.那么我们就用步骤生成器生成脚本来取这个order no.首先我们要做的是把这个对象加入到对象库中去.加入对象的方法,可以打开对象库来add 填加.也可以在Active screen 里找到这个对象来右击鼠标,选择ADD object.如下:

    在填出的窗口后,按下ok,然后下一个窗口继续按add,直到把对象真正加入到对象库中去.因为这边有些朋友以为第一次按了ok就已经填进去了,下面就直接close掉了,其实不是这样子的,这边是要注意的.对象我们已经准备好后,我们就在合适的地方生成需要的脚本.直接按一下F7.然后打开的了步骤生成器的窗口.如下:

    在第一个下拉选项Category我们选择test object.在第二个下拉选项object里选择我们要操作的对象,我们这里选择order no.也可以按旁边的图标,会显示这个脚本中的所有对象让你选择.然后在第三个下拉选项operation里选择我们要做的操作.这里提供了很多的操作.这里只是取值,所以选择了GetRoProperty.
    然后在Arguments里在value里填上我们要取的属性名.在Return value打上勾,设置返回值取好变量名.再按下ok整句代码就出来了.

    aa = Window("Flight Reservation").WinEdit("Order No:").GetROProperty("text")

    到这里整个过程就结束了.大家可以自己试试看.

  • QTP的录制回放过程

    xiaonan 发布于 2006-11-28 12:48:35

    QTP录制过程

       1.确定用于描述当前操作对象的测试对象类,并创建测试对象

       2.读取当前操作对象属性的当前值,并存储一组属性和属性值到测试对象中

       3.为测试对象创建独特的有别于其他对象的名称,通常使用一个突出属性的值

       4.记录在对象上执行的操作

    录制过程中可能出现的问题:

       1.无法识别对象

       解决方案:如果是没有相应程序的插件,而导致的对象不能识别,请填加相应的插件.如果是少量的几个控件不能识别的话,可以用合适类型的虚拟对象来代替.当然还有两个万能的办法,就是更改录制模式使用LOW-LEVEL Recording 和 Analog Recording来录制.

       2.无法生成脚本,但对象可以识别

       解决方案:把对象手工添加到对象库中去,然后手工来生成需要的脚本

     

    QTP回放过程

       1.根据对象的名称到对象存储库中查找相应的对象

       2.读取对象的描述,既对象的属性和属性值

       3.基于对象的描述,QTP在应用程序中查找相应的对象

       4.执行相关的操作

     

    回放过程中可能出现的问题:  

       1.找不到测试对象 

       解决方案:把该对象填加到对象库中去

       2.测试对象与运行时对象不匹配

      解决方案:如果是因为脚本的上下文依赖而导致的对象不能识别,请加相应的延时.如果是由于对象属性发生了变化而导致的对象不能识别,请修改相应的属性.

       3.无法执行脚本操作

       解决方案:请检查脚本程序

     

     

     

  • Web 常用的测试方法(1)

    Q_sunny520 发布于 2009-08-19 11:36:09

    1. 页面链接检查:每一个链接是否都有对应的页面,并且页面之间切换正确。
    2. 相关性检查:删除/增加一项会不会对其他项产生影响,如果产生影响,这些影响是否都正确。

    3. 检查按钮的功能是否正确:如updatecanceldeletesave等功能是否正确。

    4. 字符串长度检查:输入超出需求所说明的字符串长度的内容,看系统是否检查字符串长度,会不会出错。

    5. 字符类型检查:在应该输入指定类型的内容的地方输入其他类型的内容 (如在应该输入整型的地方输入其他字符类型) ,看系统是否检查字符类型,会否报错。

    6. 标点符号检查:输入内容包括各种标点符号,特别是空格、各种引号、回车键。看系统处理是否正确。

    7. 中文字符处理:在可以输入中文的系统输入中文,看会否出现乱码或出错。

    8. 检查带出信息的完整性:在查看信息和update信息时,查看所填写的信息是不是全部带出,带出信息和添加的是否一致。

    9. 信息重复:在一些需要命名,且名字应该唯一的信息输入重复的名字或ID,看系统有没有处理,会否报错,重名包括是否区分大小写,以及在输入内容的前后输入空格,系统是否作出正确处理。

    10. 检查删除功能:在一些可以一次删除多个信息的地方,不选择任何信息,按”delete”,看系统如何处理,会否出错;然后选择一个和多个信息,进行删除,看是否正确处理。

    11. 检查添加和修改是否一致:检查添加和修改信息的要求是否一致,例如添加要求必填的项,修改也应该必填;添加规定为整型的项,修改也必须为整型。

    12. 检查修改重名:修改时把不能重名的项改为已存在的内容,看会否处理,报错。同时,也要注意,会不会报和自己重名的错。

    13. 重复提交表单:一条已经成功提交的纪录,back后再提交,看看系统是否做了处理。

    14. 检查多次使用back键的情况:在有back的地方,back,回到原来页面,再back,重复多次,看会否出错。

    15. search检查:在有search功能的地方输入系统存在和不存在的内容,看search结果是否正确。如果可以输入多个search条件,可以同时添加合理和不合理的条件,看系统处理是否正确。

    16. 输入信息位置:注意在光标停留的地方输入信息时,光标和所输入的信息会否跳到别的地方。

    17. 上传下载文件检查:上传下载文件的功能是否实现,上传文件是否能打开。对上传文件的格式有何规定,系统是否有解释信息,并检查系统是否能够做到。

    18. 必填项检查:应该填写的项没有填写时系统是否都做了处理,对必填项是否有提示信息,如在必填项前加*  

    19. 快捷键检查:是否支持常用快捷键,如Ctrl+C Ctrl+V Backspace等,对一些不允许输入信息的字段,如选人,选日期对快捷方式是否也做了限制。

    20. 回车键检查:在输入结束后直接按回车键,看系统处理如何,会否报错。
  • 谈谈LoadRunner中Pacing的设置[转]

    zhong51test 发布于 2009-08-13 14:02:33

    在 LoadRunner 的运行场景中,有一个不大起眼的设置,可能经常会被很多人忽略,它就是 Pacing 。具体设置方式为: Run-Time settings à General à Pacing ,这个设置的功能从字面上就很容易理解,即在场景的两次迭代 (iteration) 之间,加入一个时间间隔(步进)。设置方法也很简单,这里就不赘述了,我在这里想说明的是,这个设置到底有什么作用?为什么要进行这个设置?说实话,虽然我在以前做过的一些性能测试中,偶尔会对这个步进值进行一些设置,但其实对它的真正含义和作用,我还并不十分清楚。
      前段时间,我在对X银行招聘信息系统进行性能测试的时候,发现这个值的设置对于测试的结果有着很大的影响,很遗憾当时没有深入研究这个问题,而只是简单地认为它同脚本中的 thinktime 一样只是为了更真实地模拟实际情况而已。最近在网络上看到一篇题为《调整压力测试工具》的文章,读完之后,再用之前我的测试经历加以印证,真有种豁然开朗的感觉。以下就将我的一些体会与大家分享:
      通常我们在谈到一个软件的“性能”的时候,首先想到的就是“响应时间”和“并发用户数”这两个概念。我们看到的性能需求经常都是这样定义的:
    “要求系统支持 100 个并发用户”
      看到这样的性能需求,我们往往会不假思索地就在测试场景中设置 100 个用户,让它们同时执行某一个测试脚本,然后观察其操作的响应时间,我们都是这样做的,不是吗?我在实际实施性能测试的过程中,也往往都是这样做的。可惜的是,我们中的大多数人很少去更深入地思考一下其中的奥妙,包括我自己。
      事实上,评价一个软件系统的性能,可以从两个不同的视角去看待:客户端视角和服务器视角(也有人把它叫做用户视角和系统视角),与此相对应的,又可以引出两个让初学者很容易混淆的两个概念:“并发用户数”和“每秒请求数”。“并发用户数”是从客户端视角去定义的,而“每秒请求数”则是从服务器视角去定义的。
      因此,上面所描述的做法的局限性就是,它反映的仅仅是客户端的视角。
      对于这个世界上的很多事情,变换不同的角度去看它,往往可以有助于我们得到更正确的结论。现在,我们就转换一下角度,以服务器的视角来看看性能需求应该怎么样定义: “要求系统的事务处理能力达到 100 个 / 秒” ( 这里为了理解的方便,假定在测试脚本中的一个事务仅仅包含一次请求 )
      面对以这样方式提出的性能需求,在 LoadRunner 中,我们又该如何去设置它的并发用户数呢?千万不要想当然地以为设置了 100 个并发用户数,它就会每秒向服务器提交 100 个请求,这是两个不同的概念,因为 LoadRunner 模拟客户端向服务器发出请求,必须等待服务器对这个请求做出响应,并且客户端收到这个响应之后,才会重新发出新的请求,而服务器对请求的处理是需要一个时间的。我们换个说法,对于每个虚拟用户来说,它对服务器发出请求的频率将依赖于服务器对这个请求的处理时间。而服务器对请求的处理时间是不可控的,如果我们想要在测试过程中维持一个稳定的每秒请求数( RPS ),只有一个方法,那就是通过增加并发用户数的数量来达到这个目的。这个方法看起来似乎没有什么问题,如果我们在测试场景中只执行一次迭代的话。然而有经验的朋友都会知道,实际情况并不是这样,我们通常会对场景设置一个持续运行时间(即多次迭代),通过多个事务 (transaction) 的取样平均值来保证测试结果的准确性。测试场景以迭代的方式进行,如果不设置步进值的话,那么对于每个虚拟用户来说,每一个发到服务器的请求得到响应之后,会马上发送下一次请求。同时,我们知道, LoadRunner 是以客户端的角度来定义“响应时间”的 ,当客户端请求发出去后, LoadRunner 就开始计算响应时间,一直到它收到服务器端的响应。这个时候问题就产生了:如果此时的服务器端的排队队列已满,服务器资源正处于忙碌的状态,那么该请求会驻留在服务器的线程中,换句话说,这个新产生的请求并不会对服务器端产生真正的负载,但很遗憾的是,该请求的计时器已经启动了,因此我们很容易就可以预见到,这个请求的响应时间会变得很长,甚至可能长到使得该请求由于超时而失败。等到测试结束后,我们查看一下结果,就会发现这样一个很不幸的现象:事务平均响应时间很长,最小响应时间与最大响应时间的差距很大,而这个时候的平均响应时间,其实也就失去了它应有的意义。也就是说,由于客户端发送的请求太快而导致影响了实际的测量结果。
      因此,为了解决这个问题,我们可以在每两个请求之间插入一个间隔时间,这将会降低单个用户启动请求的速度。间歇会减少请求在线程中驻留的时间,从而提供更符合现实的响应时间。这就是我在文章开头所提到的 Pacing 这个值的作用。
      最后再补充一句话:虽然性能测试通常都是从客户端活动的角度定义的,但是它们应该以服务器为中心的视角来看待。请注意这句话,理解它很重要,只有真正理解了这句话,你才会明白为什么我们一直强调做性能测试的时候要保证一个独立、干净的测试环境,以及一个稳定的网络,因为我们希望评价的是软件系统真正的性能,所以必须排除其它一切因素对系统性能造成的影响。
      花了几天的时间才完成这篇文章,如果它能够帮助大家对性能测试多一些理解或者多一些思考,那就是我的荣幸了。
  • RFT代码收藏四

    wonew1228 发布于 2008-06-17 14:00:33

    9. 使用方法 findSubitem properties)在某个特定范围查找满足条件的所有对象

    录制的脚本,使用方法document_htmlDocument()来调用页面的Document对象,使用方法text_q()来调用搜索输入框,使用方法button_search()来调用搜索按钮。这些方法是由脚本SearchLotusLink的父类SearchLotusLinkHelper定义的

            protected GuiTestObject document_htmlDocument()

            {

                    return new GuiTestObject(getMappedTestObject("document_htmlDocument"));

            }

    类:com.rational.test.ft.object.interfaces.TestObject,而它的方法findSubitem properties)正是用来在某个特定范围内查找满足条件的所有对象。改造后,回放过程中所需要用到的页面对象都是在当前浏览器中即时查找得到的。通过目标对象的类型和某个属性值来定位目标对象

            protected GuiTestObject document_htmlDocument()          {            

                      return new GuiTestObject(findTestObjectInBrowser(".class","Html.HtmlDocument",null,null));

        }

             protected TestObject findTestObjectInBrowser(String property1, String value1, String property2,

             String value2)

             {             TestObject[] foundTOs ;

                      //在当前浏览器页面中查找

                      if(null==property2)

                           foundTOs = browser_htmlBrowser().find(atDescendant(property1,value1)) ;

                      else

                           foundTOs = browser_htmlBrowser().find(atDescendant(property1,value1,property2,value2)) ;

                      //如果没有找到满足条件的TestObject

                      if(foundTOs.length<1)

                      {

                           throw new com.rational.test.ft.ObjectNotFoundException("Can NOT find TestObject with

                           "+property1+"<"+value1+">,"+property2+"<"+value2+">");

                 }                  //如果找到多个TestObject满足条件,

                      else if(foundTOs.length>1)

                      {

                           throw new AmbiguousRecognitionException("Found multi-TestObject with

                           "+property1+"<"+value1+">,"+property2+"<"+value2+">");

                 }                  //返回唯一的查找结果

                      return foundTOs[0];

             }

    10.添加等待时间

    ·            定长等待
    调用Java脚本的公共父类com.rational.test.ft.scrīpt.RationalTestscrīpt里的方法:sleep(double seconds)。这一方法可以使回放过程等待若干秒。
    这种方式直观、简单。但缺点也是明显的:固定的时间常常不能适应多变的真实环境:等待时间设置得过长,无疑会拉长测试的回放时间,降低效率;等待时间设置得过短,在某些情况下,又无法起到延时应有的效果,仍然错过了被测对象。

    ·            不定长等待
    脚本记录器记录下的这些页面对象都是从接口com.rational.test.ft.object.interfaces.TestObject继承下来的,在TestObject中有一个方法waitForExistence()可以用以实现不定长的等待。在一定的时间限度内,等待该对象的出现;一旦出现后就不再等待,程序继续往下执行。最大时间限度是在"首选项""回放"选项里设置的。不定长等待既达到灵活等待的目的,又没有浪费不必要的等待时间,是一个值得推荐的解决方案。

    11. 如何提高脚本的复用程度和兼容性

                     充分利用Rational Functional Tester的强大功能,比如scrīptAssure技术、正则表达式,数据驱动,Rational Functional Tester API等;2) 合理地编写、优化脚本。提纲挈领地对测试过程进行抽象,对关键过程进行必要的验证。

    12. ComboBox/List Control中提取参数

    import resources.GetListDataExampleHelper;

    import com.rational.test.ft.*;
    import com.rational.test.ft.object.interfaces.*;
    import com.rational.test.ft.scrīpt.*;
    import com.rational.test.ft.value.*;
    import com.rational.test.ft.vp.*;

    public class GetListDataExample extends GetListDataExampleHelper
    {
    public void testMain (Object[] args)
    {
    startApp("ClassicsJavaA");

    // Frame: ClassicsCD
    tree2Tree().click(atPath("Composers->Schubert->Location(PLUS_MINUS)"));
    tree2Tree().click(atPath("Composers->Schubert->Die schone Mullerin, Op. 25"));
    placeOrderButton2Button().click();

    //Declare variables for list
    ITestDataList nameList;
    ITestDataElementList nameListElements;
    ITestDataElement nameListElement;

    // Frame: Member Logon
    nameComboComboBox().waitForExistence();

    // Available test data types: {selected=Selected List Element, list=List Elements}
    java.util.Hashtable ht = nameComboComboBox().getTestDataTypes();
    System.out.println(ht);

    // Get all elements
    nameList = (ITestDataList)nameComboComboBox().getTestData("list");

    nameListElements = nameList.getElements();

    int listElemCount = nameList.getElementCount();

    for (int i = 0; i < listElemCount; i++)
    {
    nameListElement = nameListElements.getElement(i);
    System.out.println(nameListElement.getElement());

    // Click on each element
    nameComboComboBox().click();
    nameComboComboBox().click(atText(nameListElement.getElement().toString()));
    };

    cancelorderlogonButton().click();

    // Frame: ClassicsCD
    ClassicsJavaFrame(ANY,MAY_EXIT).close();
    }

    }

     

  • {转载}页面测试用例(参考)

    超越自我 发布于 2009-01-06 09:54:06

    列表页面显示:

    1.   确认页面的默认排序方式,字段+升降续;

    2.   含link的列,验证其有效性,即,点击后的跳转是否正确;

    3.   第一列的选择框,“全选”和“部分 选择”需有效;部分选中时,全选按钮应自动取消。

     

    顶部搜索功能:

    4.   逐个测试每个搜索条件的有效性;

    5.   做2-3个组合条件的查询,验证结果;合计共有N+3个搜索条件的测试。

    6.   有时间区间的,验证列表项的开始到结束时间 和 选择区间有交叉,则为有效,且包含所选日期的记录;

    7.   条件中,开始时间不能大于结束时间;

    8.   搜索条件,在分页显示时,需始终保持有效;

    9.   点击名为“显示全部”的按钮,需清除所有条件,并显示所有记录。

    10.   每一次新的搜索执行,都应该去除分页,显示第一页、并回到进入页面时的默认排序方式。

     

    右侧或底部的按钮(按功能分成多个用例):

    11.   单选,多选、全选的情况下,点击按钮执行某个功能,如暂停服务、恢复服务的按钮;

    12.   跨页选择,在一些 选择成员的列表中是应有效的,需进行确认。

     

    列表数据的验证:

    13.   验证从数据库中得到的列表项中每列数据的正确性,要求覆盖不同情况下的值,比如“开通”、“暂停”的服务状态;已使用空间大小和总空间大小等数字的正确性。可考虑结合其他用例来描述,但必须覆盖到。


    列表按标题的排序:

    14.   检查每个列标题,要求点击后能按其进行排序:第一次点击为正序,以后每次点击为升、降续的切换。

    15.   进入下一页、上一页,以及任意分页显示时,条件需始终保持有效。

     

    分页:

    16.   第2页/共8页  每页 10条/共 79条中的 分页数据必须正确;

    17.   第一页、 上一页、下一页、最后一页的link在当前上下文有意义时显示,否则隐藏或显示为文本标签;

    18.   填入某个数字,点击“跳转到”按钮,到正确的页数;

    另外请考虑每个文本框输入的有效性,比如日期、域名、跳转到某页的文本框的能接受的值,具体可参考需求文档。

  • 功能测试用例设计积累(六):在敏捷测试中如何设计用例

    okokokk 发布于 2009-01-08 19:54:53

    敏捷宣言:
    个体和交互比过程和工具更有价值;
    能工作的软件比全面的文档更有价值;
    顾客的协作比合同谈判更有价值;
    及时响应变更比遵循计划更有价值。

      并非每个企业都能严格按敏捷的相关开发方法进行项目管理,例如测试驱动、XP、SCRUM等。也并非都需要按这些方式管理才能实现敏捷。只要我们理解了敏捷的原则和精髓,我认为很多方法、很多地方都可以应用敏捷的思想,实现敏捷的管理。测试用例的设计是其中一项。

    1。 测试用例的粒度
      测试用例可以写得很简单,也可以写得很复杂。最简单的测试用例是测试的纲要,仅仅指出要测试的内容,如探索性测试(Exploratory Testing)中的测试设计,仅会指出需要测试产品的哪些要素、需要达到的质量目标、需要使用的测试方法等。而最复杂的测试用例就像飞机维修人员使用的工作指令卡一样,会指定输入的每项数据,期待的结果及检验的方法,具体到界面元素的操作步骤,指定测试的方法和工具等等。
      测试用例写得过于复杂或过于详细,会带来两个问题:一个是效率问题,一个是维护成本问题。另外,测试用例设计得过于详细,留给测试执行人员的思考空间就比较少,容易限制测试人员的思维。
      测试用例写得过于简单,则可能失去了测试用例的意义。过于简单的测试用例设计其实并没有进行“设计”,只是把需要测试的功能模块记录下来而已,它的作用仅仅是在测试过程中作为一个简单的测试计划,提醒测试人员测试的主要功能包括哪些而已。测试用例的设计的本质应该是在设计的过程中理解需求,检验需求,并把对软件系统的测试方法的思路记录下来,以便指导将来的测试。
      大多数测试团队编写的测试用例的粒度介于两者之间。而如何把握好粒度是测试用例设计的关键,也将影响测试用例设计的效率和效果。我们应该根据项目的实际情况、测试资源情况来决定设计出怎样粒度的测试用例。
      软件是开发人员需要去努力实现敏捷化的对象,而测试用例则是测试人员需要去努力实现敏捷化的对象。要想在测试用例的设计方面应用“能工作的软件比全面的文档更有价值”这一敏捷原则,则关键是考虑怎样使设计出来的测试用例是能有效工作的。

    2。 基于需求的测试用例设计
      基于需求的用例场景来设计测试用例是最直接有效的方法,因为它直接覆盖了需求,而需求是软件的根本,验证对需求的覆盖是软件测试的根本目的。
      要把测试用例当成“活”的文档(Effective Software Testing : 50 Specific Ways to Improve Your Testing – Elfriede Dustin),因为需求是“活”的、善变的。因此在设计测试用例方面应该把敏捷的“及时响应变更比遵循计划更有价值”这一原则。
      不要认为测试用例的设计是一个阶段,测试用例的设计也需要迭代,在软件开发的不同的阶段都要回来重新审视和完善测试用例。

    3。 测试用例的评审
      测试用例设计出来了,质量如何,如何提高测试用例设计的质量?就像软件产品需要通过各种手段来保证质量一样,测试用例的质量保证也需要综合使用各种手段和方法。
      测试用例的检查可以有多种方式,但是最敏捷的应当属临时的同行评审。我认为同行评审,尤其是临时的同行评审,应该演变成类似结对编程一样的方式。从而体现敏捷的“个体和交互比过程和工具更有价值”,要强调测试用例设计者之间的思想碰撞,通过讨论、协作来完成测试用例的设计,原因很简单,测试用例的目的是尽可能全面地覆盖需求,而测试人员总会存在某方面的思维缺陷,一个人的思维总是存在局限性。因此需要一起设计测试用例。
      除了同行评审,还应该尽量引入用户参与到测试用例的设计中来,让他们参与评审,从而体现敏捷的“顾客的协作比合同谈判更有价值”这一原则。这里顾客的含义比较广泛,关键在于你怎样定义测试,如果测试是对产品的批判,则顾客应该指最终用户或顾客代表(在内部可以是市场人员或领域专家);如果测试是指对开发提供帮助和支持,那么顾客显然就是程序员了。
      因此,参与到测试用例设计和评审中来的人除了测试人员自己和管理层外,还应该包括最终用户或顾客代表,还有开发人员。

    4。 测试用例数据生成的自动化
      在测试用例设计方面最有希望实现自动化的,要当属测试用例数据生成的自动化了。因为设计方面的自动化在可想象的将来估计都很难实现,但是数据则不同,数据的组合、数据的过滤筛选、大批量数据的生成等都是计算机擅长的工作。
      很多时候,测试用例的输入参数有不同的类型、有不同的取值范围,我们需要得到测试用例的输入参数的不同组合,以便全面地覆盖各种可能的取值情况。但是全覆盖的值域可能会不可思议地广泛,我们又需要科学地筛选出一些有代表性的数据,以便减轻测试的工作量。在这方面可利用正交表设计数据或成对组合法设计数据。
      可利用一些工具,例如TConfig、PICT等来产生这些数据。
      在性能测试、容量测试方面,除了设计好测试用例考虑如何测试外,还要准备好大量的数据。大量数据的准备可以使用多种方式:编程生成、SQL语句生成(基于数据库的数据)、利用工具生成。
      工具未必能生成所有满足要求的数据,但是却是最快速的,编程能生成所有需要的数据,但是可能是最复杂、最慢的方式。所以应该尽量考虑使用一些简单实用的工具,例如DataFactory等。
271/212>
Open Toolbar