发布新日志

  • 使用Loadrunner分别测量服务器响应时间及页面加载时间

    2013-08-06 10:10:16

      最近想对一网站进行性能测试,我们的初衷是把Server reponse时间和页面渲染时间区分看,这样我们就能判断是server这端的问题,还是网页前端HTML、CSS、JS等解析问题。
      因为性能测试还需要同时测试最大并发用户数及服务器资源使用情况,所以测试工具选择了Loadrunner,但此工具只是能统计服务器响应时间,无法测试页面渲染及加载时间。
      在网上搜索了一些,有一篇帖子是讲如何使用QTP写VBS脚本,然后使用QTP中Tools--Options--Run的"Alow other Mercury products to run tests and components"功能来执行性能测试。这种方法不好的地方在于我们得在机器上同时装QTP 和 Loadrunner, 那么有没有一种办法可以直接使用Loadrunner来写VBS脚本然后直接用Loadrunner跑VBS的脚本呢?
      查看了Loadrunner支持的协议,其中有一项是关于"VB Script. Vuser",使用该协议可以实现相应语言的脚本的编写,那不正好可以满足我的要求么?于是参考帖子“使用QTP统计页面加载时间”开始在Loadrunner中编写VBS脚本。
      以下在原帖子中的代码在Loadrunner中的应用:
    在Action模块中编写如下脚本:

    Public Function timeCount(url)

      Set dom = CreateObject("InternetExplorer.Application") 'Create an IE object

      Set lr = CreateObject("LoadRunner.LrApi") 'Create LoadRunner object

      dom.Navigate(url) 'Open the specific URL

      time_start = Now() 'To obtain statistics at the beginneing of time

      timer_start = timer() 'Get the current time in milliseconds

      dom.visible = True ' Set IE can be seen

      While dom.busy or (dom.readyState<>4) 'dom.readyState -- Got the IE status; when IE busy or is loading the readyState<>4, got the time duration

       wscript.sleep 1 'Time interval 1 ms, if the relatively long time interval, then is likely to take less than a state value

       Select Case dom.readyState 'To determine the value of dom.readyState

        Case 0  'IE is not initialized

          time0 = Now()

          timer0 = timer()

        Case 1 'Is sending Request

          time1 = Now()

          timer1 = timer()

        Case 2 'Request has been sent to complete

          time2 = Now()

          timer2 = timer()

        Case 3 'Can receive the part of response data

          time_3 = Now() 

          timer_3 = timer()

        Case 4 'Page is loaded

          time4 = Now()

          timer4 = timer()

        End select

       wend

       timeCount = "Statistics Start Time:"&start_time&vbcrlf&"time0:"&time0&vbcrlf&"time1:"&time1&vbcrlf&"time2:"&time2&vbcrlf&"time3():"&time3&vbcrlf&"time4:"&time4&vbcrlf&"To complete the initializtion of IE and send request:"&(timer1-timer_start)&"seconds"&vbcrlf&"To send the completion and acceptance of server-side part of the response data:"&(timer2-timer1)&"seconds"&vbcrlf&"100% to receive and complete the HTML content parsing:"&(timer4-timer2)&"seconds"&vbcrlf& "Total spent:"&(timer4-timer_start)&"seconds"

    End Function


    Public Function Action()

      SITEURL = "http://www.yourwebsite.com"

      result = timeCount(SITEURL) 'Returns running result

      MsgBox result 'Output to run As a result, the line can be commented out loadrunner ' For debugging, you can comment it out

    End Function 


    通过执行上述脚本发现如下几个问题:
    1. wscript.sleep 1 运行时提示缺少wscript对象,在网上查了一下,原因如下:
    wscript对象是windows宿主脚本对象,而且是windows系统默认提供的脚本操作对象,即无须重新创建就可以使用。所以你在vbs,js中可以直接使用wscript(或者wsh)的方法和属性,但这只是说你可以直接使用wscript,不代表wscript属于vbs。
    尽管QTP引入了vbs,但由于wscript不属于vbs,所以QTP未引入wscript,使用时自然报错。

    很多人提供了解决办法,有的说是没有创建对象的缘故,按要求加了Set WshShell = CreateObject("WScript.Shell") 也是不可以的,后来网上有人重新写了WScript供Loadrunner调用:
    在 Action 函数前放置 Sleep 过程 Sub Sleep(MSecs) ' loadrunner can't use wscript.sleep directly, the following code is trying to create Wscript. object Set fso = CreateObject("Scripting.FileSystemObject") If Fso.FileExists("sleeper.vbs")=False Then Set bjOutputFile = fso.CreateTextFile("sleeper.vbs", True) objOutputFile.Write "wscript.sleep WScript.Arguments(0)" objOutputFile.Close End If CreateObject("WScript.Shell").Run "sleeper.vbs " & MSecs,1 , True End Sub
    将Loadrunner中的 wscript.sleep 1 改为调用 Sleep(1)

    2.不支持其它的浏览器,因为页面渲染时间跟浏览器是息息相关的,用vbscript写的脚本目前只支持IE,因为创建只能创建IE对象。

    3.上述脚本中只能把时间以Message box的形式显示出来,如果使用Loadrunner测试的话,为了分析结果,我们需要把时间存成事务,更新后的脚本如下:

    Sub Sleep(MSecs) ' loadrunner can't use wscript.sleep directly, the following code is trying to create Wscript. object

        Set fso = CreateObject("Scripting.FileSystemObject")

        If Fso.FileExists("sleeper.vbs")=False Then

           Set bjOutputFile = fso.CreateTextFile("sleeper.vbs", True)

           objOutputFile.Write "wscript.sleep WScript.Arguments(0)"

           objOutputFile.Close

        End If

        CreateObject("WScript.Shell").Run "sleeper.vbs " & MSecs,1 , True

    End Sub

    Public Function timeCount(url)

      Set dom = CreateObject("InternetExplorer.Application") 'Create an IE object

      Set lr = CreateObject("LoadRunner.LrApi") 'Create LoadRunner object

      dom.Navigate(url) 'Open the specific URL

      time_start = Now() 'To obtain statistics at the beginneing of time

      timer_start = timer() 'Get the current time in milliseconds

      dom.visible = True ' Set IE can be seen

      While dom.busy or (dom.readyState<>4) 'dom.readyState -- Got the IE status; when IE busy or is loading the readyState<>4, got the time duration

       Sleep(1) 'Time interval 1 ms, if the relatively long time interval, then is likely to take less than a state value

       Select Case dom.readyState 'To determine the value of dom.readyState

        Case 0  'IE is not initialized

          time0 = Now()

          timer0 = timer()

        Case 1 'Is sending Request

          time1 = Now()

          timer1 = timer()

        Case 2 'Request has been sent to complete

          time2 = Now()

          timer2 = timer()

        Case 3 'Can receive the part of response data

          time_3 = Now() 

          timer_3 = timer()

        Case 4 'Page is loaded

          time4 = Now()

          timer4 = timer()

        End select

       wend

       server_response_transaction_timer = timer2 - timer1 ' Get the server

       page_render_transaction_timer = timer4-timer_2

       total_timer = timer4 - timer_start

       lr.log_message "The server response time is " + lr.eval_string(server_response_transaction_timer)

       lr.log_message "The page render time is " + lr.eval_string(page_render_transaction_timer)

       lr.log_message "Total page load time is " + lr.eval_string(total_timer)

       lr.set_transaction "server_response_time", server_response_transaction_timer, lr.PASS

       lr.set_transaction "page_render_time", page_render_transaction_timer, lr.PASS

       lr.set_transaction "total_page_load_time", total_timer, lr.PASS

     

    Public Function Action()

      SITEURL = "http://www.yourwebsite.com"

      result = timeCount(SITEURL) 'Returns running result

      'MsgBox result 'Output to run As a result, the line can be commented out loadrunner 

    End Function


    4.测试更新后脚本发现dom.readystate=2总是捕获不到,导致不能计算出事务时间,经过Debug发现,dom.readystate=2确实没有捕获到,但dom.readystate=3到是有很多次的时间捕获,后来想到当dom.readystate状态从2变化到3时,也可以认为服务器已经返回了响应,直接把readystate变成3的第一个时间值当做服务器返回响应的最后时间就可以,再次更新代码
    Sub Sleep(MSecs) ' loadrunner can't use wscript.sleep directly, the following code is trying to create Wscript. object

        Set fso = CreateObject("Scripting.FileSystemObject")

        If Fso.FileExists("sleeper.vbs")=False Then

           Set bjOutputFile = fso.CreateTextFile("sleeper.vbs", True)

           objOutputFile.Write "wscript.sleep WScript.Arguments(0)"

           objOutputFile.Close

        End If

        CreateObject("WScript.Shell").Run "sleeper.vbs " & MSecs,1 , True

    End Sub

     

    Public Function timeCount(url)

      Dim i

      i = 0

      Dim time_3(100)

      Dim timer_3(100)

      Set dom = CreateObject("InternetExplorer.Application") 'Create an IE object

      Set lr = CreateObject("LoadRunner.LrApi") 'Create LoadRunner object

      dom.Navigate(url) 'Open the specific URL

      time_start = Now() 'To obtain statistics at the beginneing of time

      timer_start = timer() 'Get the current time in milliseconds

      dom.visible = True ' Set IE can be seen

      While dom.busy or (dom.readyState<>4) 'dom.readyState -- Got the IE status; when IE busy or is loading the readyState<>4, got the time duration

       Sleep(1) 'Time interval 1 ms, if the relatively long time interval, then is likely to take less than a state value

       lr.log_message "The readyState is " + lr.eval_string(dom.readyState) ' For debugging, you can comment it out before running

       Select Case dom.readyState 'To determine the value of dom.readyState

        Case 0  'IE is not initialized

          time0 = Now()

          timer0 = timer()

        Case 1 'Is sending Request

          time1 = Now()

          timer1 = timer()

        Case 2 'Request has been sent to complete

          time2 = Now()

          timer2 = timer()

        Case 3 'Can receive the part of response data

          time_3(i) = Now() ' When dom.readystate is changed from 2 to 3, it means server has returned the response data, so the first value of Now() and Timer() stands for the server response time.

          timer_3(i) = timer()

          lr.log_message "when dom.readystate = 3 "& cstr(i) + " " + lr.eval_string(time_3(i)) ' For debugging, you can comment it out before running

          i = i+1 ' Because dom.reaystate = 3 may keep in a while

        Case 4 'Page is loaded

          time4 = Now()

          timer4 = timer()

          lr.log_message "4 start at " + lr.eval_string(time4) ' For debugging, you can comment it out before running

        End select

       server_response_transaction_timer = timer_3(0) - timer1 ' Get the server

       page_render_transaction_timer = timer4-timer_3(0)

       total_timer = timer4 - timer_start

       lr.log_message "The server response time is " + lr.eval_string(server_response_transaction_timer)

       lr.log_message "The page render time is " + lr.eval_string(page_render_transaction_timer)

       lr.log_message "Total page load time is " + lr.eval_string(total_timer)

       lr.set_transaction "server_response_time", server_response_transaction_timer, lr.PASS

       lr.set_transaction "page_render_time", page_render_transaction_timer, lr.PASS

       lr.set_transaction "total_page_load_time", total_timer, lr.PASS

    End Function


    Public Function Action()

      SITEURL = "http://www.yourwebsite.com"

      result = timeCount(SITEURL) 'Returns running result

      'MsgBox result 'Output to run As a result, the line can be commented out loadrunner 

    End Function


    5.还有一个问题就是当脚本执行完毕后,发现IE无法关闭,虽然表面上看似已经关闭了,其实进程还在运行,当批量进行执行脚本时,导致机子运行缓慢,解决方法是在vusr_end中将IE进程关闭
    Public Function Terminate() 

       Set ws=CreateObject("wscript.shell")

       ws.run "cmd /c taskkill /f /im iexplore.exe",0 

    End Function


    6.刚才测试的时候发现一个问题,如果在vusr_end中结束IE进程,在controller中跑的时候,有可能会导致正在运行中的其它并发用户正在使用的浏览器关闭,所以我们还不能使用上述的方法,暂时想到的办法是使用dom.quit 放置在timeCount函数最后。
      然后写一个批处理程序来运行controller,等所有的脚本运行完成后关闭ie进程,目前只是一个想法,后续实践后再分享。
    哈哈,至此使用Loadrunner测试页面加载时间的目的已经达到
Open Toolbar