发布新日志

  • 腾迅也有BUG哦

    2008-07-25 08:55:01

    腾迅也有BUG哦
  • QuickTest Plus帮助文档中EXCEL相关函数

    2008-03-25 09:25:35

    QuickTest Plus帮助文档中EXCEL相关函数

    打开QTP,test--settings--resources,将附件文件添加进去就可以使用相关函数了

    ?
    Dim ExcelApp    'As Excel.Application
    Dim excelSheet  'As Excel.worksheet
    Dim excelBook   'As Excel.workbook
    Dim fso         'As scrīpting.FileSystemObject

    ' *********************************************************************************************
    ' 函数说明:创建一个Excel应用程序ExcelApp,并创建一个新的工作薄Workbook;
    ' 参数说明:无
    ' 调用方法:
    '           CreateExcel()
    ' *********************************************************************************************

    Function CreateExcel()
        Dim excelSheet
        Set ExcelApp = CreateObject("Excel.Application")
        ExcelApp.Workbooks.Add  
        ExcelApp.Visible = True
        Set CreateExcel = ExcelApp
    End Function

    ' *********************************************************************************************
    ' 函数说明:关闭Excel应用程序;
    ' 参数说明:
    '          (1)ExcelApp:Excel应用程序名称;
    ' 调用方法:
    '           CloseExcel(ExcelApp)
    ' *********************************************************************************************
    Sub CloseExcel(ExcelApp)
        Set excelSheet = ExcelApp.ActiveSheet
        Set excelBook = ExcelApp.ActiveWorkbook
        Set fso = CreateObject("scrīpting.FileSystemObject")
        On Error Resume Next
        fso.CreateFolder "C:\Temp"
        fso.DeleteFile "C:\Temp\ExcelExamples.xls"
        excelBook.SaveAs "C:\Temp\ExcelExamples.xls"
        ExcelApp.Quit
        Set ExcelApp = Nothing
        Set fso = Nothing
        Err = 0
        On Error GoTo 0
    End Sub

    ' *********************************************************************************************
    ' 函数说明:保存工作薄;
    ' 参数说明:
    '          (1)ExcelApp:Excel应用程序名称;
    '          (2)workbookIdentifier:属于ExcelApp的工作薄名称;
    '          (3)path:保存的路径;
    ' 返回结果:
    '          (1)保存成功,返回字符串:OK
    '          (2)保存失败,返回字符串:Bad Worksheet Identifier
    ' 调用方法:
    '           ret = SaveWorkbook(ExcelApp, "Book1", "D:\Example1.xls")
    ' *********************************************************************************************
    ' 函数说明:保存工作薄;
    ' 参数说明:
    '          (1)ExcelApp:Excel应用程序名称;
    '          (2)workbookIdentifier:属于ExcelApp的工作薄名称;
    '          (3)path:保存的路径;
    ' 返回结果:
    '          (1)保存成功,返回字符串:OK
    '          (2)保存失败,返回字符串:Bad Worksheet Identifier
    ' 调用方法:
    '           ret = SaveWorkbook(ExcelApp, "Book1", "D:\Example1.xls")
    ' *********************************************************************************************
    Function SaveWorkbook(ExcelApp, workbookIdentifier, path) 'As String
        Dim workbook
        On Error Resume Next  '启用错误处理程序
        Set workbook = ExcelApp.Workbooks(workbookIdentifier)
        On Error GoTo 0   '禁用错误处理程序
        If Not workbook Is Nothing Then
            If path = "" Or path = workbook.FullName Or path = workbook.Name Then
                workbook.Save
            Else
                Set fso = CreateObject("scrīpting.FileSystemObject")
                '判断路径中是否已添加扩展名.xls
                If InStr(path, ".") = 0 Then
                    path = path & ".xls"
                End If
                '删除路径下现有同名的文件
                On Error Resume Next
                fso.DeleteFile path
                Set fso = Nothing
                Err = 0
                On Error GoTo 0
               
                workbook.SaveAs path
            End If
            SaveWorkbook = "OK"
        Else
            SaveWorkbook = "Bad Workbook Identifier"
        End If
    End Function
    ' *********************************************************************************************
    ' 函数说明:设置工作表excelSheet单元格的值
    ' 参数说明:
    '          (1)excelSheet:工作表名称;
    '          (2)row:列的序号,第一列为1;
    '          (3)column:行的序号,第一行为1;
    '          (4)value:单元格要设置的值;
    ' 返回结果:
    '          无返回值
    ' 调用方法:
    '           SetCellValue excelSheet1, 1, 2, "test\"
    ' *********************************************************************************************
    Sub SetCellValue(excelSheet, row, column, value)
        On Error Resume Next
        excelSheet.Cells(row, column) = value
        On Error GoTo 0
    End Sub
    'The GetCellValue returns the cell's value according to its row column and sheet
    'excelSheet - the Excel Sheet in which the cell exists
    'row - the cell's row
    'column - the cell's column
    'return 0 if the cell could not be found
    ' *********************************************************************************************
    ' 函数说明:获取工作表excelSheet单元格的值
    ' 参数说明:
    '          (1)excelSheet:工作表名称;
    '          (2)row:列的序号;
    '          (3)column:行的序号;
    ' 返回结果:
    '          (1)单元格存在,返回单元格值;
    '          (2)单元格不存在,返回0;
    ' 调用方法:
    '           set CellValue = GetCellValue(excelSheet, 1, 2)
    ' *********************************************************************************************
    Function GetCellValue(excelSheet, row, column)
        value = 0
        Err = 0
        On Error Resume Next
        tempValue = excelSheet.Cells(row, column)
        If Err = 0 Then
            value = tempValue
            Err = 0
        End If
        On Error GoTo 0
        GetCellValue = value
    End Function
    ' *********************************************************************************************
    ' 函数说明:获取并返回工作表对象
    ' 参数说明:
    '          (1)ExcelApp:Excel应用程序名称;
    '          (2)sheetIdentifier:属于ExcelApp的工作表名称;
    ' 返回结果:
    '          (1)成功:工作表对象Excel.worksheet
    '          (1)失败:Nothing
    ' 调用方法:
    '           Set excelSheet1 = GetSheet(ExcelApp, "Sheet Name")
    ' *********************************************************************************************
    Function GetSheet(ExcelApp, sheetIdentifier)
        On Error Resume Next
        Set GetSheet = ExcelApp.Worksheets.Item(sheetIdentifier)
        On Error GoTo 0
    End Function
    ' *********************************************************************************************
    ' 函数说明:添加一张新的工作表
    ' 参数说明:
    '          (1)ExcelApp:Excel应用程序名称;
    '          (2)workbookIdentifier:属于ExcelApp的工作薄名称;
    '          (2)sheetName:要插入的工作表名称;
    ' 返回结果:
    '          (1)成功:工作表对象worksheet
    '          (1)失败:Nothing
    ' 调用方法:
    '           InsertNewWorksheet(ExcelApp, workbookIdentifier, "new sheet")
    ' *********************************************************************************************

    Function InsertNewWorksheet(ExcelApp, workbookIdentifier, sheetName)
        Dim workbook 'As Excel.workbook
        Dim worksheet 'As Excel.worksheet

        '如果指定的工作薄不存在,将在当前激活状态的工作表中添加工作表
        If workbookIdentifier = "" Then
            Set workbook = ExcelApp.ActiveWorkbook
        Else
            On Error Resume Next
            Err = 0
            Set workbook = ExcelApp.Workbooks(workbookIdentifier)
            If Err <> 0 Then
                Set InsertNewWorksheet = Nothing
                Err = 0
                Exit Function
            End If
            On Error GoTo 0
        End If

        sheetCount = workbook.Sheets.Count  '获取工作薄中工作表的数量
        workbook.Sheets.Add , sheetCount '添加工作表
        Set worksheet = workbook.Sheets(sheetCount + 1)  '初始化worksheet为新添加的工作表对象

        '设置新添加的工作表名称
        If sheetName <> "" Then
            worksheet.Name = sheetName
        End If

        Set InsertNewWorksheet = worksheet
    End Function

    ' *********************************************************************************************
    ' 函数说明:修改工作表的名称;
    ' 参数说明:
    '          (1)ExcelApp:Excel应用程序名称;
    '          (2)workbookIdentifier:属于ExcelApp的工作薄名称;
    '          (3)worksheetIdentifier:属于workbookIdentifier工作薄的工作表名称;
    '          (4)sheetName:修改后的工作表名称;
    ' 返回结果:
    '          (1)修改成功,返回字符串:OK
    '          (2)修改失败,返回字符串:Bad Worksheet Identifier
    ' 调用方法:
    '           set ret = RenameWorksheet(ExcelApp, "Book1", "Sheet1", "Sheet Name")
    ' *********************************************************************************************

    Function RenameWorksheet(ExcelApp, workbookIdentifier, worksheetIdentifier, sheetName)
        Dim workbook
        Dim worksheet
        On Error Resume Next
        Err = 0
        Set workbook = ExcelApp.Workbooks(workbookIdentifier)
        If Err <> 0 Then
            RenameWorksheet = "Bad Workbook Identifier"
            Err = 0
            Exit Function
        End If
        Set worksheet = workbook.Sheets(worksheetIdentifier)
        If Err <> 0 Then
            RenameWorksheet = "Bad Worksheet Identifier"
            Err = 0
            Exit Function
        End If
        worksheet.Name = sheetName
        RenameWorksheet = "OK"
    End Function

    ' *********************************************************************************************
    ' 函数说明:删除工作表;
    ' 参数说明:
    '          (1)ExcelApp:Excel应用程序名称;
    '          (2)workbookIdentifier:属于ExcelApp的工作薄名称;
    '          (3)worksheetIdentifier:属于workbookIdentifier工作薄的工作表名称;
    ' 返回结果:
    '          (1)删除成功,返回字符串:OK
    '          (2)删除失败,返回字符串:Bad Worksheet Identifier
    ' 调用方法:
    '           set ret = RemoveWorksheet(ExcelApp, "Book1", "Sheet1")
    ' *********************************************************************************************

    Function RemoveWorksheet(ExcelApp, workbookIdentifier, worksheetIdentifier)
        Dim workbook 'As Excel.workbook
        Dim worksheet 'As Excel.worksheet
        On Error Resume Next
        Err = 0
        Set workbook = ExcelApp.Workbooks(workbookIdentifier)
        If Err <> 0 Then
            RemoveWorksheet = "Bad Workbook Identifier"
            Exit Function
        End If
        Set worksheet = workbook.Sheets(worksheetIdentifier)
        If Err <> 0 Then
            RemoveWorksheet = "Bad Worksheet Identifier"
            Exit Function
        End If
        worksheet.Delete
        RemoveWorksheet = "OK"
    End Function

    ' *********************************************************************************************
    ' 函数说明:添加新的工作薄
    ' 参数说明:
    '          (1)ExcelApp:Excel应用程序名称;
    ' 返回结果:
    '          (1)成功:工作表对象NewWorkbook
    '          (1)失败:Nothing
    ' 调用方法:
    '          set NewWorkbook = CreateNewWorkbook(ExcelApp)
    ' *********************************************************************************************

    Function CreateNewWorkbook(ExcelApp)
        Set NewWorkbook = ExcelApp.Workbooks.Add()
        Set CreateNewWorkbook = NewWorkbook
    End Function

    ' *********************************************************************************************
    ' 函数说明:打开工作薄
    ' 参数说明:
    '          (1)ExcelApp:Excel应用程序名称;
    '          (2)path:要打开的工作薄路径;
    ' 返回结果:
    '          (1)成功:工作表对象NewWorkbook
    '          (1)失败:Nothing
    ' 调用方法:
    '          set NewWorkbook = CreateNewWorkbook(ExcelApp)
    ' *********************************************************************************************

    Function OpenWorkbook(ExcelApp, path)
        On Error Resume Next
        Set NewWorkbook = ExcelApp.Workbooks.Open(path)
        Set ōpenWorkbook = NewWorkbook
        On Error GoTo 0
    End Function

    ' *********************************************************************************************
    ' 函数说明:将工作薄设置为当前工作状态
    ' 参数说明:
    '          (1)ExcelApp:Excel应用程序名称;
    '          (2)workbookIdentifier:要设置为当前工作状态的工作薄名称;
    ' 返回结果:无返回值;
    ' 调用方法:
    '          ActivateWorkbook(ExcelApp, workbook1)
    ' *********************************************************************************************

    Sub ActivateWorkbook(ExcelApp, workbookIdentifier)
        On Error Resume Next
        ExcelApp.Workbooks(workbookIdentifier).Activate
        On Error GoTo 0
    End Sub

    ' *********************************************************************************************
    ' 函数说明:关闭Excel工作薄;
    ' 参数说明:
    '          (1)ExcelApp:Excel应用程序名称;
    '          (2)workbookIdentifier:
    ' 调用方法:
    '           CloseWorkbook(ExcelApp, workbookIdentifier)
    ' *********************************************************************************************

    Sub CloseWorkbook(ExcelApp, workbookIdentifier)
        On Error Resume Next
        ExcelApp.Workbooks(workbookIdentifier).Close
        On Error GoTo 0
    End Sub

    ' *********************************************************************************************
    ' 函数说明:判断两个工作表对应单元格内容是否相等
    ' 参数说明:
    '          (1)sheet1:工作表1的名称;
    '          (2)sheet2:工作表2的名称;
    '          (3)startColumn:开始比较的行序号;
    '          (4)numberOfColumns:要比较的行数;
    '          (5)startRow:开始比较的列序号;
    '          (6)numberOfRows:要比较的列数;
    '          (7)trimed:是否先除去字符串开始的空格和尾部空格后再进行比较,true或flase;
    ' 返回结果:
    '          (1)两工作表对应单元格内容相等:true
    '          (2)两工作表对应单元格内容不相等:flase         
    ' 调用方法:
    '           ret = CompareSheets(excelSheet1, excelSheet2, 1, 10, 1, 10, False)
    ' *********************************************************************************************

    Function CompareSheets(sheet1, sheet2, startColumn, numberOfColumns, startRow, numberOfRows, trimed)
        Dim returnVal 'As Boolean
        returnVal = True

        '判断两个工作表是否都存在,任何一个不存在停止判断,返回flase
        If sheet1 Is Nothing Or sheet2 Is Nothing Then
            CompareSheets = False
            Exit Function
        End If

        '循环判断两个工作表单元格的值是否相等
        For r = startRow to (startRow + (numberOfRows - 1))
            For c = startColumn to (startColumn + (numberOfColumns - 1))
                Value1 = sheet1.Cells(r, c)
                Value2 = sheet2.Cells(r, c)

                '如果trimed为true,去除单元格内容前面和尾部空格
                If trimed Then
                    Value1 = Trim(Value1)
                    Value2 = Trim(Value2)
                End If

                '如果单元格内容不一致,函数返回flase
                If Value1 <> Value2 Then
                    Dim cell 'As Excel.Range
                    '修改sheet2工作表中对应单元格值
                    sheet2.Cells(r, c) = "Compare conflict - Value was '" & Value2 & "', Expected value is '" & Value1 & "'."  
                    '初始化cell为sheet2中r:c单元格对象
                    Set cell = sheet2.Cells(r, c) '
                    '将sheet2工作表中对应单元格的颜色设置为红色
                    cell.Font.Color = vbRed  
                    returnVal = False
                End If
            Next
        Next
        CompareSheets = returnVal
    End Function
  • VBScript编码约定

    2008-02-13 11:30:28

    VBscrīpt编码约定

    编码约定是帮助您使用 Microsoft Visual Basic scrīpting Edition 编写代码的一些建议。编码约定包含以下内容:

    • 对象、变量和过程的命名约定
    • 注释约定
    • 文本格式和缩进指南

    使用一致的编码约定的主要原因是使脚本或脚本集的结构和编码样式标准化,这样代码易于阅读和理解。使用好的编码约定可以使源代码明白、易读、准确,更加直观且与其他语言约定保持一致。

    常数命名约定

    VBscrīpt 的早期版本不允许创建用户自定义常数。如果要使用常数,则常数以变量的方式实现,且全部字母大写以和其他变量区分。常数名中的多个单词用下划线 (_) 分隔。例如:

     USER_LIST_MAX
    NEW_LINE

    这种标识常数的方法依旧可行,但您还可以选择其他方案,用 Const 语句创建真正的常数。这个约定使用大小写混合的格式,并以“con”作为常数名的前缀。例如:

     conYourOwnConstant

    变量命名约定

    为提高易读和一致性,请在 VBscrīpt 代码中使用以下变量命名约定:

    子类型 前缀 示例
    Boolean bln blnFound
    Byte byt bytRasterData
    Date (Time) dtm dtmStart
    Double dbl dblTolerance
    Error err errOrderNum
    Integer int intQuantity
    Long lng lngDistance
    Object obj objCurrent
    Single sng sngAverage
    String str strFirstName

    变量作用域

    变量应定义在尽量小的作用域中。VBscrīpt 变量的作用域如下所示:

    作用域 声明变量处 可见性
    过程级 事件、函数或子过程。 在声明变量的过程中可见。
    scrīpt 级 HTML 页面的 HEAD 部分,任何过程之外。 在脚本的所有过程中可见。

    变量作用域前缀

    随着脚本代码长度的增加,有必要快速区分变量的作用域。在类型前缀前面添加一个单字符前缀可以实现这一点,而不致使变量名过长。

    作用域 前缀 示例
    过程级 dblVelocity
    scrīpt 级 s sblnCalcInProgress

    描述性变量名和过程名

    变量名或过程名的主体应使用大小写混合格式,并且尽量完整地描述其目的。另外,过程名应以动词开始,例如 InitNameArray 或 CloseDialog。

    对于经常使用的或较长的名称,推荐使用标准缩写以使名称保持在适当的长度内。通常多于 32 个字符的变量名会变得难以阅读。使用缩写时,应确保在整个脚本中保持一致。例如,在一个脚本或脚本集中随意切换 Cnt 和 Count 将造成混乱。

    对象命名约定

    下表列出了 VBscrīpt 中可能用到的对象命名约定(推荐):

    对象类型 前缀 示例
    3D 面板 pnl pnlGroup
    动画按钮 ani aniMailBox
    复选框 chk chkReadOnly
    组合框、下拉列表框 cbo cboEnglish
    命令按钮 cmd cmdExit
    公共对话框 dlg dlgFileOpen
    框架 fra fraLanguage
    水平滚动条 hsb hsbVolume
    图像 img imgIcon
    标签 lbl lblHelpMessage
    直线 lin linVertical
    列表框 lst lstPolicyCodes
    旋钮 spn spnPages
    文本框 txt txtLastName
    垂直滚动条 vsb vsbRate
    滑块 sld sldScale

    代码注释约定

    所有过程的开始部分都应有描述其功能的简要注释。这些注释并不描述细节信息(如何实现功能),这是因为细节有时要频繁更改。这样就可以避免不必要的注释维护工作以及错误的注释。细节信息由代码本身及必要的内部注释来描述。

    当传递给过程的参数的用途不明显,或过程对参数的取值范围有要求时,应加以说明。如果过程改变了函数和变量的返回值(特别是通过参数引用来改变),也应在过程的开始部分描述该返回值。

    过程开始部分的注释应包含以下区段标题。相关样例,请参阅后面的“格式化代码”部分。

    区段标题 注释内容
    目的 过程的功能(不是实现功能的方法)。
    假设 其状态影响此过程的外部变量、控件或其他元素的列表。
    效果 过程对每个外部变量、控件或其他元素的影响效果的列表。
    输入 每个目的不明显的参数的解释。每个参数都应占据单独一行并有其内部注释。
    返回 返回值的解释。

    请记住以下几点:

    • 每个重要的变量声明都应有内部注释,描述变量的用途。
    • 应清楚地命名变量、控件和过程,仅在说明复杂细节时需要内部注释。
    • 应在脚本的开始部分包含描述该脚本的概述,列举对象、过程、运算法则、对话框和其他系统从属物。有时一段描述运算法则的假码是很有用的。

    格式化代码

    应尽可能多地保留屏幕空间,但仍允许用代码格式反映逻辑结构和嵌套。以下为几点提示:

    • 标准嵌套块应缩进 4 个空格。
    • 过程的概述注释应缩进 1 个空格。
    • 概述注释后的最高层语句应缩进 4 个空格,每一层嵌套块再缩进 4 个空格。例如:
    '*********************************************************
    ' Purpose: Locates the first occurrence of a specified user
    '          in the UserList array.
    ' Inputs: strUserList(): the list of users to be searched.
    '         strTargetUser: the name of the user to search for.
    ' Returns: The index of the first occurrence of the strTargetUser
    '          in the strUserList array.
    '          If the target user is not found, return -1.
    '*********************************************************
    Function intFindUser (strUserList(), strTargetUser)
       Dim i   ' Loop counter.
       Dim blnFound   ' Target found flag
       intFindUser = -1
       i = 0   ' Initialize loop counter
       Do While i <= Ubound(strUserList) and Not blnFound
          If strUserList(i) = strTargetUser Then
             blnFound = True   ' Set flag to True
             intFindUser = i   ' Set return value to loop count
          End If
          i = i + 1   ' Increment loop counter
       Loop
    End Function
  • qtp 多种函数使用方法

    2008-01-30 13:56:03

    --转载

    1 生产随机数列
    第一种方法
    randomize'更新反回的数据
    funcation rand(k,n)
    n="int((k-1)*rnd+1) rand=n
    end funcation
    第二种方法
    n="randomnumber.value(1,255)

     2  当运行到表中的某一行,自动导出表中的所有数据
    row=datatable.getcurrentrow
    if row="5" then
      datatable.export("d:\data.xml")
    end if

    3 参数化密码
    webedit("txtpass").setsecure"sdsdf...."
    如果参数化密码,可以直接在数据表中写入未加密的密码,它会自动识别,即不用把setsecure改为set

    4 如果弹出对话框就获取上面提示信息并与表中的信息对比,不统一证明弹出的提示出错,主要用来验证
    if browser("web_name").dialog("dialog_name").exist(1) then'如果不出现="false     error_message=browser("web_name").dialog("diaglog_name").static("用户密码错误!".getRoproperty("text")
       if error_message<>(datatable.value("error_info"))then
             msgbox(error_message)
          end if
         browser("web_name").dialog("diaglog_name").close
      end if
    这里我总结了两点技巧:
       一是:对于dialog中,虽然提示信息对象名称是"用户密码错误",但如果信息对象名称是“该用户不存在”,不用更改会自动识别,我想主要是录制第一 遍时,“用户密码错误”只是让运行时能找到这个控制,而不管它是什么内容,因为在对象仓库中,text不是决定该对象的属性
         二是:如果对于提示信息比较长的,可以用mid(error_message,n,m)取一部份特征提示信息进行验证,这样我想可以节省处理时间,又可以避免长度以及空格等字符的处理

    5  datatable.value("num")只在global形式下的一种省略形式;完整形式是:
    datatable.value("num",dtlocalsheet)
    -----向某一列的单元格赋值:
    datatable.value("column_name",dtlocalsheet)="nanjing"
    -----取得某一行具体值:
    datatable.setcurrentrow(n)
    msgbox(datatable.getsheet("global").getparameter("column_name").Rawvalue)
    或者kk=datatable.Rawvalue("column_name","action1")
    ----在run-time时,动态添加表格与数据
    kk=datatable.addsheet("sheet_name").addparameter("column_name","value").name;

    7   wintreeview一些操作
    选择一个条目:wintreeview.select(item)'根是0
    根的名称:wintreeview.getitem(0)

    8   数据库检查点模块:
    sub database_check
    set con="createobject(""adodb.connection")
    con.open "Descrīption="IBM_ODBC;DRIVER=SQL" Server;SERVER="IBM;UID=sa;""&_
                     "PWD="123456;APP=Quick" Test Pro;WSID="IBM;DATABASE=IBM_table""
    'access方式:con.open "DRIVER="{Microsoft" Access Driver (*.mdb)};DBQ="d:\test.mdb""
    'Orocle方式:con.open "DRIVER="{Oracle" in OraHome92};SERVER="CESHI;UID=CND_TEST;PWD=CND;DBQ=CESHI;DBA=W;APA=T;

    EXC=F;XSM=Default;FEN=T;QTO=T;FRC=10;FDL=10;LOB=T;RST=T;GDE=F;FRL=Lo;BA

    M=IfAllSuccessful;MTS=F;MDI=Me;CSR=F;FWC=F;PFC=10;TLO=O;""
    set record="createobject(""adodb.recordset")
    sql="select*from ibm_one_table"
    record.open sql,con
    DO
    if(record("ibm_table_column")="kai")then'//查找表格中有多少kai
    num=num+1;
    end if
    record.movenext
    loop until record.eof="true record.close
    set record="nothing con.close
    set con="nothing end sub

    9   换行符
    vbcr----chr(13)回车符// vblf----chr(10)换行符
        vbcrlf----chr(13)+chr(10)结合//type(chr(13)就相当于按了一上键盘上的enter

    10  Run from step有两种方式:
    在Keyword View模式会从本步骤运行到所有action结束
    在expert view模式仅会将本action运行结束

    11  由于对象属性原因,无法识别对象
    -----对于对象属性是变化的,可以参数化/或者用正则表达式
    -----报匹配多个对象错误,可以spy查看对象,添加一个该对象另一个唯一标识属性
    -----有时可以删除对象的变化的属性来解决识别问题
    ------对于多个完全相同的对象,可以采用添加index,location,createtime等特殊属性来识别
      (index:按照程序源码,绘制对象的先后标识对象,所以与其它相同对象是相互依赖,当其它对象发生
      变化后,原先的所有对象index属性要发生变化,开始是0;如index:="0;         location:根据对象的位置进行确定,从上到下,从左到右;
      CreateTime:按照对象被浏览器打开的先后标识对象)
    ------另外换一种思维方式,采取等效的方法;比如用键盘代替鼠标或用操作系统本身特性去解决问题

    12  对系统文件的操作
    -------从系统的文件中获取信息及删除文件
      get_file_infor("c:\she.mpg")
       function get_file_infor(url)
        dim fso,f
        set fso="createobject(""scrīpting.filesystemobject")
        set f="fso.getfile(url)"
        f.name:f.size:f.type:f.datacreated'///获取文件信息
        fso.deletefile(url)'/////删除文件
       end function
    --------获取文件夹里所有文件信息
    get_folder_infor("c:\kai")
    function get_folder_infor(folder)
    dim fso,f,f1,n
    set fso="createobject(""scrīpting,filesystemobject")
    set f="fso.getfolder(folder) set fc="f.files for each f1 in fc
    select case f1.name
    case"kai.mpg","she.mpg","dd.mp3"'//检查文件夹里是否含有这些文件
    end select
    next
    end function

     

    13   等待某个对象出现方法
    y="......waitproperty(""visible",true,10000)

     

    14   防程序中断方法
    On error resume next
    On error goto handle

     

    15  数组的应用:
    name="array(1,2,""aa","bb")
    name(2)="aa"

     

    16  正则表达式应用模板
    进行日期YYYY-MM-DD的格式检查 :
    Function RegExpTest(patrn, strng)
      Dim regEx, Match, Matches      ' Create variable.
      Set regEx = New RegExp         ' Create a regular expression.
      regEx.Pattern = patrn         ' Set pattern.
      regEx.IgnoreCase = True         ' Set case insensitivity.
      regEx.Global = True         ' Set global applicability.
      Set Matches = regEx.Execute(strng)   ' Execute search.
      For Each Match in Matches      ' Iterate Matches collection.
        RetStr = RetStr & "Match found at position "
        RetStr = RetStr & Match.FirstIndex & ". Match Value is '"
        RetStr = RetStr & Match.Value & "'." & vbCRLF
      Next
      RegExpTest = RetStr
    End Function
    date_pattern="^((((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((01,3-9])|(1[0-2]))-(29|30)))))$"
    result_message=RegExpTest(date_pattern, inputbox("请你输入要检查的时间:"))'用其它正则表达式更改此处
    Select case result_message
    Case ""
             msgbox("你输入的日期格式与标准不匹配")
    case else  MsgBox(result_message)
    end select

     

    17   返回一个字符串在另一字符串中的位置
    instr(string1,string2)

     

    18   有时回放出现找不到对象时,可能不是由于你的代码问题,而是由于你的操作系统等设置问题;
    举例说明1:
    比如:你录制一个选择磁盘中的文件动作
    会录制为:
    .winlistview("  ").drap 46,99
    .winlistview("  ").draponitem "she.mp3"
    下次录制的时候,如果你的系统文件改为不显示扩展名,下次执行的时候,QTP就找不到she.mp3,只能找到she;
    举例说明2:
    有时由于不同操作系统以及不同的ie,导致有些窗口不能识别,比如在2000下弹出的网页对话框的标题是:
    “web对话框",而在2003上是”网页对话框"

     

    19  "is+*"类型function
    isarray'是否是数组
    isconnected'判断QTP是否连接到TD
    isdate'是否是合法的日期类型
    isempty'判断是否初始化
    isNull'判断是否为空值
    isNumeric'判断是否是数字型
    isobject'判断是否一个功能对象
    isready'判断设备是否准备就绪
    isRootFolder'是否是根目录

     

    20 Action之间的参数传递
    例如:在Action1中,有如下代码:
    out_str="This is out_string"
    RunAction "Action2",oneIteration,out_str
    在Acton2中,在其step->Action Properties中的,input参数栏,加入out_str后,
    msgbox(parameter("out_str")),就能正确显示参数了 

     

    21 Wscrīpt.Shell的一些应用
    set WshShell ="CreateObject(""Wscrīpt.Shell")
    WshShell.SendKeys "{ENTER}"     '模拟键盘进行操作
    WshShell.AppActivate "Calculator"             '启动应用程序

     

    22 获取对象属性名称用法:
    GetRoProperty----从应用程序界面上获取对象属性(即,是脚本运行时,获取的对象动态属性值)例如:获取对象库中index属性值,似乎只能用GetToProperty,因为应用程序界面上对象没有该属性,只是QTP为识别该对象创立的描述属性;
    GetToproperty----从对象库中描述对象的属性,静态值
    GetToProperties----获取用于标识对象的属性集;对于这个集合,有count等属性方法

     

    23 FireEvent的使用可以对一个对象进行更复杂的操作
    如:FireEvent("onfocus")   '使一个控件获取焦点
         FireEvent("ondblclick")  '实现双击/也可以在事件设定中针对该对象事件响应  

     

    24 模板的应用
    -----新建一个文本,输入一些新建Action时常包含的信息,然后保存为ActionTemplate.MST文件,
     并复制到QTP/dat目录下;这样每次新建action都会包含固定的信息了;
    例如:
    '-------------------脚本说明---------------
    '产品版本:      __Build(  )
    '测试员:
    '编写日期:
    '测试功能:
    '脚本类型:
    '被测试对象初始状态:
    '进展程度:
    '基本思路:
    '主要功能函数:
    '历史修改:
    '没解决的问题:
    '--------------------脚本内容-------------

     

    25 在对象库中,两个对象有时不能通过更改属性或命名来达到两个对象完全一致的替换;
    在web-mod项目中,我在对象库里添加了一个自动含有index标识属性的对象,然后每次通过SetToproperty来改变
    index值,对对象进行数据驱动,使其操作另一个对象,但脚本始终操作原先index属性值的对象;后来,把该对象
    删除掉,重新添加一个不自动含有index标识属性的该类对象,然后,手工添加,index标识属性,后来脚本能正常工作了,可见两次的对象属性完全一致,但形成方式不一样,导致的结果往往也不一样;

     

    26 childobject的应用
    childobject可以返回界面上满足条件的对象集合,而且与对象库里是否有这些对象无关,这就可以简化对象库;
    返回的对象集合的count方法可以返回对象个数,这就可以通过下标对单个对象进行操作;在出现index标识对象时
    可以进行运用
    如:Set m_WinCheck="Descrīption.Create()       m_WinCheck("nativeclass").Value="Button"
          set All_WinCheck="Window(""").Dialog("").Childobject(m_WinCheck)
          n="All_WinCheck.Count()      for i="0" to n-1
          All_WinCheck(i).Set "ON"
         next

  • qtp数据表的添加、数据导入、数据导出

    2008-01-21 15:56:45

    • 数据表的添加、数据导入、数据导出

      2007-03-29 15:54:26

      测试文件名:datasheet   路径为E:\TestInstance\qtp\ForexampleTest\
      要导入的数据保存在C:\NameTickets.xls 内容为
      name tickets
      aa         1
      bb        2
      cc         3
      在导入数据前E:\TestInstance\qtp\ForexampleTest\datasheet\Default.xls有两个缺省的Sheet 分别为Global Action1均无数据
      运行如下程序:

      DataTable.AddSheet("MySheet")  '在缺省的Default.xls添加一个标单MySheet      
      DataTable.ImportSheet "C:\NameTickets.xls", 1, "MySheet"                                               ' 第二行
      DataTable.ExportSheet "E:\TestInstance\qtp\ForexampleTest\datasheet\Default.xls", 3        ' 第三行
        
      '其中第二行中的1参数 是指从文件“"C:\NameTickets.xls"的第一列开始导入数据到新建的MySheet 中
      '其中第二行中的3参数 是指讲运行过程的数据导出到文件"E:\TestInstance\qtp\ForexampleTest\datasheet\Default.xls"第三个Sheet即新建的MySheet中。
      运行完毕,则在下次打开该测试时就能看见添加了表单MySheet,并且数据已经导入。
      也可以手工打开文件 E:\TestInstance\qtp\ForexampleTest\datasheet\Default.xls来查看。
    • 关于文件的操作

      2007-03-29 11:48:05

      创建文件
      dim fso, f
      set fso = server.CreateObject("scrīpting.FileSystemObject")
      set f = fso.CreateTextFile("C:\test.txt", true) '第二个参数表示目标文件存在时是否覆盖
      f.Write("写入内容")
      f.WriteLine("写入内容并换行")
      f.WriteBlankLines(3) '写入三个空白行(相当于在文本编辑器中按三次回车)
      f.Close()
      set f = nothing
      set fso = nothing

      打开并读文件
      dim fso, f
      set fso = server.CreateObject("scrīpting.FileSystemObject")
      set f = fso.OpenTextFile("C:\test.txt", 1, false) '第二个参数 1 表示只读打开,第三个参数表示目标文件不存在时是否创建
      f.Skip(3) '将当前位置向后移三个字符
      f.SkipLine() '将当前位置移动到下一行的第一个字符,注意:无参数
      response.Write f.Read(3) '从当前位置向后读取三个字符,并将当前位置向后移三个字符
      response.Write f.ReadLine() '从当前位置向后读取直到遇到换行符(不读取换行符),并将当前位置移动到下一行的第一个字符,注意:无参数
      response.Write f.ReadAll() '从当前位置向后读取,直到文件结束,并将当前位置移动到文件的最后
      if f.atEndOfLine then
          response.Write("一行的结尾!")
      end if
      if f.atEndOfStream then
          response.Write("文件的结尾!")
      end if
      f.Close()
      set f = nothing
      set fso = nothing

      打开并写文件
      dim fso, f
      set fso = server.CreateObject("scrīpting.FileSystemObject")
      set f = fso.OpenTextFile("C:\test.txt", 2, false) '第二个参数 2 表示重写,如果是 8 表示追加
      f.Write("写入内容")
      f.WriteLine("写入内容并换行")
      f.WriteBlankLines(3) '写入三个空白行(相当于在文本编辑器中按三次回车)
      f.Close()
      set f = nothing
      set fso = nothing

      判断文件是否存在
      dim fso
      set fso = server.CreateObject("scrīpting.FileSystemObject")
      if fso.FileExists("C:\test.txt") then
          response.Write("目标文件存在")
      else
          response.Write("目标文件不存在")
      end if
      set fso = nothing

      移动文件
      dim fso
      set fso = server.CreateObject("scrīpting.FileSystemObject")
      call fso.MoveFile("C:\test.txt", "D:\test111.txt") '两个参数的文件名部分可以不同
      set fso = nothing

      复制文件
      dim fso
      set fso = server.CreateObject("scrīpting.FileSystemObject")
      call fso.CopyFile("C:\test.txt", "D:\test111.txt") '两个参数的文件名部分可以不同
      set fso = nothing

      删除文件
      dim fso
      set fso = server.CreateObject("scrīpting.FileSystemObject")
      fso.DeleteFile("C:\test.txt")
      set fso = nothing

      创建文件夹
      dim fso
      set fso = server.CreateObject("scrīpting.FileSystemObject")
      fso.CreateFolder("C:\test") '目标文件夹的父文件夹必须存在
      set fso = nothing

      判断文件夹是否存在
      dim fso
      set fso = server.CreateObject("scrīpting.FileSystemObject")
      if fso.FolderExists("C:\Windows") then
          response.Write("目标文件夹存在")
      else
          response.Write("目标文件夹不存在")
      end if
      set fso = nothing

      删除文件夹
      dim fso
      set fso = server.CreateObject("scrīpting.FileSystemObject")
      fso.DeleteFolder("C:\test") '文件夹不必为空
      set fso = nothing
    • 模板的应用

      2007-03-27 15:05:31

      新建一个文本,输入一些新建Action时常包含的信息,然后保存为ActionTemplate.MST文件,
       并复制到QTP/dat目录下;这样每次新建action都会包含固定的信息了;
      例如:
      '-------------------脚本说明---------------
      '产品版本:      __Build(  )
      '测试员:
      '编写日期:
      '测试功能:
      '脚本类型:
      '被测试对象初始状态:
      '进展程度:
      '基本思路:
      '主要功能函数:
      '历史修改:
      '没解决的问题:
      '--------------------脚本内容-------------

      当然了,脚本的说明内容可以随意修改,但必须保存到dat目录下,并且文件的名字为:ActionTemplate.MST

    • Action之间参数传递

      2007-03-27 15:02:45

      Action之间的参数传递
      例如:在Action1中,有如下代码:
      out_str="This is out_string"
      RunAction "Action2",oneIteration,out_str
      在Acton2中,在其step->Action Properties中的,input参数栏,加入out_str后,
      msgbox(parameter("out_str")),就能正确显示参数了 

      按照该方法如下:

      1.加入Action1后,输入:out_str="This is out_string"
      RunAction "Action2",oneIteration,out_str

      2.然后再加入Action2,注意:Action1和Action2是并列关系,

      在其step->Action Properties中的,input参数栏,加入out_str后,

      这是在Action2中输入:msgbox(parameter("out_str"))

      当运行的时候会出现两个msgbox,其中第一个显示内容为:"This is out_string" ;第二个msgbox显示内容为:空;

      当把和Action1并列的那个Action2去掉后就可以出现一个msgbox,其中显示内容为:"This is out_string",

      结论: Action1和Action2为父子关系时,才会出现传递的参数内容。

    • QTP识别和操作对象的原理

      2007-03-26 11:36:49

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


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

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

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

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

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


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

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

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

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

      2007-03-26 11:30:40

      应该说TO是仓库文件里定义的仓库对象,RO是被测试软件的实际对象
      QTP要求先在仓库文件里定义仓库对象,里面存有实际对象的特征属性的值,
      运行的时候,QTP会根据仓库对象的特征属性描述,寻找到实际对象,然后操作实际对象。

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

      相关的几个函数有:

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

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


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

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

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

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


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

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

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

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

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


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

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

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

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

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

      JavaWindow("Test").JavaButton("label:=New").Click
      JavaWindow("Test").JavaButton("label:=Modify").Click
      JavaWindow("Test").JavaButton("label:=Delete").Click
      JavaWindow("Test").JavaButton("label:=Check").Click
  • qtp 检查点

    2008-01-02 17:50:21

    1) 理解检查点

    QuickTest enables you to add checks to your test or component.

    检查点比较指定属性的当前值与期望值,以判断当前的程序(或站点)功能是否正常。

    当你增加了一个检查点以后,在KeyWord模式下会增加一个CheckPoint,在Expert模式下会增加一条CheckPoint语句。在运行测试时,QTP比较CheckPoint的期望值与当前值,如果结果不匹配,则检查点失败,你可以在TestResults窗口中查看到检查点的结果。

    如果你想获取 checkpoint的返回值(一个布尔值,表示检查成功或失败),你必须在专家模式下将checkpoint 参数两端加上括号。如

    a = browser("MyBrowser").page("MyPage").check (checkPoint("MyProperty"))

     

    2) 向测试脚本中添加检查点

    可以在录制脚本的过程中添加,也可以在修改脚本的过程中添加。

    途径:菜单 Insertcheckpoint、或按钮;在Keywork视图中选择一个STEP,然后选右键菜单Insert Standard Checkpoint;在Active Screan中选择任意一个object,然后选右键菜单Insert Standard Checkpoint

     

    3) checkpoint的种类:

    可以在站点或应用程序中插入不同种类的checkpoint

    l         Standard Checkpoint (标准检查点)

    检查程序或网页object的属性值,检查对象如buttons, radio buttons, combo boxes, lists, 等等。

    标准检查点支持所有的add-in 环境 (see Supported Checkpoints).

    l         Image Checkpoint (图像检查点)

    检查程序或网页中图像的值,如你可以检查图像 的源文件是否正确。

    注:你也可以给图片object插入一个标准检查点,这个标准检查点也是图像检查点。

    l         Bitmap Checkpoint(图片检查点)

    将程序或网页的某个区域作为一个图片,建立检查点。如,某个站点可以展示一个城市的地图,这个地图有控制地图缩放的按钮,你点击1次“zoom in”按钮后,录制下放大了的地图快照。通过建立bitmap 检查点,可以检查“zoom in”功能是否正确。

    l         Table Checkpoint(表检查点)

    检查一个表中的信息。例如,假设被测的程序或网站包括一个table,本table中包含了所有的从New YorkSan Fransisco的有效航班。你可以通过Table检查点来检查第1个航班的时间是否正确。

    注意:你也可以通过为表Object插入标准检查点的方法创建表检查点。

    l         Text Checkpoint(文本检查点)

    检查位于程序或网站某个位置的字符串。例如,假设程序或网站显示“Flight departing from New York to San Francisco”的语句,你可以创建一个文本检查点检查"New York" 是否显示于"Flight departing from" "to San Francisco"之间。

    所有的add-in环境都支持文本检查点。

    l         Text Area Checkpoint

    l         Accessibility Checkpoint

    l         Page Checkpoint

    l         Database Checkpoint

    检查database的内容。例如,可以使用数据库检查点来检查包含航班信息的数据库的内容。

    所有环境都支持数据库检查点。

    l         XML Checkpoint

    l         下表是QTP中在不同环境下对各类检查点的支持情况。

     

    Web

    Std

    VB

    ActiveX

    Other Object

    Standard

    S

    S

    S

    S

    NA

    Image

    S

    NS

    NS

    NS

    NA

    Table

    S

    NS

    NS

    S

    NA

    Text

    S

    S

    S

    S

    NA

    Text Area

    NS

    S

    S

    S

    NA

    Bitmap

    S

    S

    S

    S

    NA

    Accessibility

    S

    NS

    NS

    NS

    NA

    XML

    S

    NS

    NS

    NS

    S (File)

    Page

    S

    NA

    NA

    NA

    NA

    Database

    NA

    NA

    NA

    NA

    S (DbTable)

    S—Supported

    NS—Not Supported

    NA—Not Applicable

     

    4) 检查object的属性值

    通过向测试脚本中添加标准检查点,可以检查不同版本的程序(或站点)的object的属性的异同。

     

    在录制过程中添加检查点时,点击检查点按钮,鼠标变成手状,点击object即可。这时如果按钮CTRL键,可以将鼠标变成正常状态,进行正常操作,松开CTRL后,仍然变成手状。

     

    5)检查TableDatabase

    通过检查Table,可以检查程序中Table的内容;

    通过检查DabaBase,可以检查DataBase的内容。两种检查方法相似。

    通过Table检查点,你可以检查某个指定的值是否存在于应用程序的当前表格中。

    DataBase检查点:针对Database定义一个查询,然后创建一个检查点,用检查点来检查查询结果。

     

    创建Database检查点:

    首先基于数据库表查询的结果建立检查点。检查点可以是检查查询结果的全部或部分。QTP从数据库中获取当前数据并将它保存为期望的数据。在专家模式下,数据库检查点的脚本表达为“DbTable.Check CheckPoint”。

    当运行测试脚本时,DAtabase检查点将当前数据与录制时产生的期望数据相比较,如果数据不匹配,则表示失败。
  • 学会了在lr中运用关联

    2007-12-20 09:25:16

    在http properties中手动添加关联,录制时让机器自动建立correlation,比在录制后寻找web_reg_save_param()的位置快多了,也准确多了.  充分利用本身所带的功能      呵呵,找了3天,逐步的改善,终于实现我想要的.探索真的很美    .      
  • 以武装革命反对武装的反革命

    2007-12-18 18:07:59

    以武装革命反对武装的反革命,坚决给予反击.        
  • lr函数集

    2007-12-18 18:02:03

    1.         Intweb_reg_save_param("参数名","LB=左边界","RB=右边界",LAST);/注册函数,在参数值出现的前面使用,注册成功时返回值为0,注册失败时返回值为1。左右边界需根据TreeView里相关步骤的SeverResponse代码来确定。用以上函数能获取第一个符合条件的数值。

    2.         web_reg_save_param("参数名”,"LB=左边界”,"RB=右边界","Ord=All",LAST);/当参数有多个值时,加上"Ord=All”后可获取所有的数值。注册成功后,{参数名_count}表示取得的数值个数,{参数名_1}为第一个数值,{参数名_2}为第二个数值。

    3.         lr_save_string(“字符串变量”,"参数名")/将字符变量里的值传递给指定参数。通过该函数来改变DataFile类型参数的数值。

    4.         lr_eval_string("{参数名}")/取得参数的数值。可取得已注册参数或DataFile类型参数的数值。eval就是evaluation(估价, 评价, 赋值)的缩写。

    5.         int sprintf(char * string , const char*format_string[,args]);/字符串赋值函数

    Action()

    {

    int index=56;

    charfilename[64],*suffix="txt";

    sprintf(filename,"log_%d.%s",index,suffix);

    lr_output_message("Thenewfilenameis%s",filename);

    return 0;

    }

    OutputThenewfilenameislog_56.txt

    6.         char*strcat(char*to,constchar*from);/将一字符串追加到另一字符串后面

    7.         web_find("find_time","What=2006-03-0118:21:16.882",LAST);/增加检查点,检查“2006-03-0118:21:16.882”这个字符串是否出现在当前页面上。find_time为自己任意输入的检查点名称。

    8.       事务函数

    lr_end_sub_transaction/标记子事务的结束以便进行性能分析

    lr_end_transaction/标记LoadRunner事务的结束

    lr_end_transaction_instance/标记事务实例的结束以便进行性能分析

    lr_fail_trans_with_error/将打开事务的状态设置为LR_FAIL并发送错误消息

    lr_get_trans_instance_duration/获取事务实例的持续时间(由它的句柄指定)

    lr_get_trans_instance_wasted_time/获取事务实例浪费的时间(由它的句柄指定)

    lr_get_transaction_duration/获取事务的持续时间(按事务的名称)

    lr_get_transaction_think_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_start_sub_transaction/标记子事务的开始

    lr_start_transaction/标记事务的开始

    lr_start_transaction_instance/启动嵌套事务(由它的父事务的句柄指定)

    lr_stop_transaction/停止事务数据的收集

    lr_stop_transaction_instance/停止事务(由它的句柄指定)数据的收集

    lr_wasted_time/消除所有打开事务浪费的时间

    lr_end_sub_transaction/标记子事务的结束以便进行性能分析

    r_end_transaction/标记LoadRunner事务的结束

    lr_end_transaction_instance/标记事务实例的结束以便进行性能分析

    lr_fail_trans_with_error/将打开事务的状态设置为LR_FAIL并

     

    9.      命令行分析函数

    lr_get_attrib_double/检索脚本命令行中使用的double类型变量

    lr_get_attrib_long/检索脚本命令行中使用的long类型变量

    lr_get_attrib_string/检索脚本命令行中使用的字符串

    10.  信息性函数

    lr_user_data_point/记录用户定义的数据示例

    lr_whoami/将有关Vuser脚本的信息返回给Vuser脚本

    lr_get_host_name/返回执行Vuser脚本的主机名

    lr_get_master_host_name/返回运行LoadRunnerController的计算机名

    11.  字符串函数

    lr_eval_string/用参数的当前值替换参数

    lr_save_string/将以NULL结尾的字符串保存到参数中

    lr_save_var/将变长字符串保存到参数中

    lr_save_datetime/将当前日期和时间保存到参数中

    lr_advance_param/前进到下一个可用参数

    lr_decrypt/解密已编码的字符串

    lr_eval_string_ext/检索指向包含参数数据的缓冲区的指针

    lr_eval_string_ext_free/释放由lr_eval_string_ext分配的指针

    lr_save_searched_string/在缓冲区中搜索字符串实例,并相对于该字符串实例,该缓冲区的一部分保存到参数中

    12.  消息函数

    lr_debug_message/将调试消息发送到输出窗口

    lr_error_message/将错误消息发送到输出窗口

    lr_get_debug_message/检索当前的消息类

    lr_log_message/将输出消息直接发送到output.txt文件,此文件位于Vuser脚本目录中。该函数有助于防止输出消息干扰TCP/IP通信。

    lr_output_message/将消息发送到输出窗口

    lr_set_debug_message/为输出消息设置消息类

    lr_vuser_status_message/生成格式化输出并将其打印到ControllerVuser状态区域。

    lr_message/将消息发送到Vuser日志和输出窗口

    13.  操作函数

    web_custom_request允许您使用HTTP支持的任何方法来创建自定义HTTP请求
    web_image
    在定义的图像上模拟鼠标单击
    web_link
    在定义的文本链接上模拟鼠标单击
    web_submit_data
    执行无条件无上下文的表单
    web_submit_form
    模拟表单的提交
    web_url
    加载由“URL”属性指定的URL

    14.  身份验证函数

    身份验证函数web_set_certificate使Vuser使用在InternetExplorer注册表中列出的特定证书
    身份验证函数web_set_certificate_ex指定证书和密钥文件的位置和格式信息
    身份验证函数web_set_user指定Web服务器的登录字符串和密码,用于Web服务器上已验证用户身份的区域

    15.  缓存函数

    缓存函数web_cache_cleanup清除缓存模拟程序的内容

    16.  检查函数

    检查函数web_findHTML页内搜索指定的文本字符串
    检查函数web_global_verification在所有后面的HTTP请求中搜索文本字符串
    检查函数web_image_check验证指定的图像是否存在于HTML页内
    检查函数web_reg_find在后面的HTTP请求中注册对HTML源或原始缓冲区中文本字符串的搜索

    17.  连接定义函数

    连接定义函数web_disable_keep_alive禁用Keep-AliveHTTP连接
    连接定义函数web_enable_keep_alive启用Keep-AliveHTTP连接
    连接定义函数web_set_connections_limit设置Vuser在运行脚本时可以同时打开连接的最大数目

    18.  并发组

    web_concurrent_end标记并发组的结束
    web_concurrent_start
    标记并发组的开始

    19.  cook函数

    web_add_cookie添加新的Cookie或修改现有的Cookie
    web_cleanup_cookies
    删除当前由Vuser存储的所有
    Cookie
    web_remove_cookie
    删除指定的Cookie

    20.  关联函数

    web_create_html_paramHTML页上的动态信息保存到参数中。(LR6.5及更低版本)
    web_create_html_param_ex
    基于包含在HTML页内的动态信息创建参数(使用嵌入边界)(LR6.5及更低版本)。
    关联函数

  • 如何在 Load Runner 腳本中做关联 (Correlation)

    2007-12-14 15:01:30

    Part1
    当录制脚本时,VuGen会拦截client端(浏览器)与server端(网站服务器)之间的对话,并且通通记录下来,产生脚本。在VuGenRecording Log中,您可以找到浏览器与服务器之间所有的对话,包含通讯内容、日期、时间、浏览器的请求、服务器的响应内容等等。脚本和Recording Log最大的差别在于,脚本只记录了client端要对server端所说的话,而Recording Log则是完整纪录二者的对话。
    <!--[if !vml]--> <!--[endif]-->
    图像-0015.png
    当执行脚本时,您可以把VuGen想象成是一个演员,它伪装成浏览器,然后根据脚本,把当初真的浏览器所说过的话,再对网站伺服器重新说一遍,VuGen企图骗过服务器,让服务器以为它就是当初的浏览器,然后把网站内容传送给VuGen

    所以纪录在脚本中要跟服务器所说的话,完全与当初录制时所说的一样,是写死的(hard-coded)。这样的作法在遇到有些比较聪明的服务器时,还是会失效。这时就需要透过「关联(correlation)」的做法来让VuGen可以再次成功地骗过服务器。

    何谓关联(correlation)?

    所谓的关联(correlation)就是把脚本中某些写死的(hard-coded)数据,转变成是撷取自服务器所送的、动态的、每次都不一样的数据。

    举一个常见的例子,刚刚提到有些比较聪明的服务器,这些服务器在每个浏览器第一次跟它要数据时,都会在数据中夹带一个唯一的辨识码,接下来就会利用这个辨识码来辨识跟它要数据的是不是同一个浏览器。一般称这个辨识码为Session ID。对于每个新的交易,服务器都会产生新的Session ID给浏览器。这也就是为什么执行脚本会失败的原因,因为VuGen还是用旧的Session ID向服务器要数据,服务器会发现这个Session ID是失效的或是它根本不认识这个Session ID,当然就不会传送正确的网页数据给VuGen了。

    下面的图示说明了这样的情形:

    当录制脚本时,浏览器送出网页A的请求,服务器将网页A的内容传送给浏览器,并且夹带了一个ID=123的数据,当浏览器再送出网页B的请求时,这时就要用到ID=123的数据,服务器才会认为这是合法的请求,并且把网页B的内容送回给浏览器。

    在执行脚本时会发生什么状况?浏览器再送出网页B的请求时,用的还是当初录制的ID=123的数据,而不是用服务器新给的ID=456,整个脚本的执行就会失败。
    图像-0016.png
    要对付这种服务器,我们必须想办法找出这个Session ID到底是什么、位于何处,然后把它撷取下来,放到某个参数中,并且取代掉脚本中有用到Session ID的部份,这样就可以成功骗过服务器,正确地完成整个交易了。

    哪些错误代表着我应该做关联(correlation)?

    假如脚本需要关联( correlation ),在还没做之前是不会执行通过的,也就是说会有错误讯息发生。不过,很不幸地,并没有任何特定的错误讯息是和关联( correlation )有关系的。会出现什么错误讯息,与系统实做的错误处理机制有关。错误讯息有可能会提醒您要重新登入,但是也有可能直接就显示 HTTP 404 的错误讯息。

    要如何做关联(correlation)?

    关联(correlation)函数

    关联(correlation)会用到下列的函数:

    • web_reg_save_param :这是最新版,也是最常用来做关联(correlation)的函数。
      语法:
      web_reg_save_param ( “Parameter Name” , < list of Attributes >, LAST );
    • web_create_html_param web_create_html_param_ex:这二个函数主要是保留作为向前兼容的目的的。建议使用 web_reg_save_param 函数。
    详细用法请参考使用手册。在VuGen中点选【Help>Function reference>Contexts>Web and Wireless Vuser Functions>Correlation Functions】。

    如何找出要关联(correlation)数据

    简单的说,每一次执行时都会变动的值,就有可能需要做关联(correlation)。

    VuGen 提供二种方式帮助您找出需要做关联(correlation)的值:

    <!--[if !supportLists]-->

    <!--[if !supportLists]--> 1.      <!--[endif]--> 自动关联

         2.  手动关联

    自动关联

    VuGen 内建自动关联引擎(auto-correlation engine),可以自动找出需要关联的值,并且自动使用关联函数建立关联。

    自动关联提供下列二种机制:

    • Rules Correlation :在录制过程中VuGen会根据订定的规则,实时自动找出要关联的值。规则来源有两种:
      • 内建(Built-in Correlation
        VuGen
        已经针对常用的一些应用系统,如AribaBuyerBlueMartiniBroadVisionInterStagemySAPNetDynamicsOraclePeopleSoftSiebelSilverJRunner等,内建关联规则,这些应用系统可能会有一种以上的关联规则。您可以在【Recording Options>Internet Protocol>Correlation】中启用关联规则,则当录制这些应用系统的脚本时,VuGen会在脚本中自动建立关联。
        您也可以在【Recording Options>Internet Protocol>Correlation】检视每个关联规则的定义。
      • 使用者自订(User-defined Rules Correlation
        除了内建的关联规则之外,使用者也可以自订关联规则。您可以在【Recording Options>Internet Protocol>Correlation】建立新的关联规则。
    • Correlation Studio :有别于Rules CorrelationCorrelation Studio则是在执行脚本后才会建立关联,也就是说当录制完脚本后,脚本至少须被执行过一次,Correlation Studio才会作用。Correlation Studio会尝试找出录制时与执行时,服务器响应内容的差异部分,藉以找出需要关联的数据,并建立关联。

    Rule Correlation

    请依照以下步骤使用Rule Correlation

    <!--[if !supportLists]--> 1.      <!--[endif]--> 启用auto-correlation

    <!--[if !supportLists]--> 1.      <!--[endif]--> 点选VuGen的【Tools>Recording Options】,开启【Recording Options】对话窗口,选取【Internet Protocol>Correlation】,勾选【Enable correlation during recording】,以启用自动关联。

    <!--[if !supportLists]--> 2.      <!--[endif]--> 假如录制的应用系统属于内建关联规则的系统,如AribaBuyerBlueMartiniBroadVisionInterStagemySAPNetDynamicsOraclePeopleSoftSiebelSilverJRunner等,请勾选相对应的应用系统。

    <!--[if !supportLists]--> 3.      <!--[endif]--> 或者也可以针对录制的应用系统加入新的关联规则,此即为使用者自订的关联规则。

    <!--[if !supportLists]--> 4.      <!--[endif]--> 设定当VuGen侦测到符合关联规则的数据时,要如何处理:

    <!--[if !supportLists]-->           <!--[endif]--> Issue a pop-up message and let me decide online】:跳出一个讯息对话窗口,询问您是否要建立关联。

                      Perform correlation in sceipt】:直接自动建立关联
        2.  录制脚本
               
    开始录制脚本,在录制过程中,当VuGen侦测到符合关联规则的数据时,会依照设定建立关联,您会在脚本中看到类似以下的脚            本,此为BroadVision应用系统建立关联的例子,在脚本批注部分可以看到关联前的数据为何。
    图像-0017.png

          3.  执行脚本验证关联是OK的。

    Correlation Studio

    当录制的应用系统不属于VuGen预设支持的应用系统时,Rule Correlation可能既无法发挥作用,这时可以利用Correlation Studio来做关联。

    Correlation Studio会尝试找出录制时与执行时,服务器响应内容的差异部分,藉以找出需要关联的数据,并建立关联。

    使用Correlation Studio的步骤如下:

    <!--[if !supportLists]-->1.      <!--[endif]-->录制脚本并执行

       2.  执行完毕后,VuGen会跳出下面的【Scan Action for Correlation】窗口,询问您是否要扫描脚本并建立关联,按下【Yes】按钮。

    图像-0018.png

       3.  扫描完后,可以在脚本下方的【Correlation Results】中看到扫描的结果。

    Part2

    手动关联

    手动关联的执行过程大致如下:

    <!--[if !supportLists]-->1.      <!--[endif]-->使用相同的业务流程与数据,录制二份脚本

    <!--[if !supportLists]-->2.      <!--[endif]-->使用WinDiff工具协助找出需要关联的数据

    <!--[if !supportLists]-->3.      <!--[endif]-->使用web_reg_save_param函数手动建立关联

    <!--[if !supportLists]-->4.      <!--[endif]-->将脚本中有用到关联的数据,以参数取代

    接下来将详细的说明如何执行每个步骤

    使用相同的业务流程与数据,录制二份脚本

    <!--[if !supportLists]-->1.      <!--[endif]-->先录制一份脚本并存档。

    <!--[if !supportLists]-->   2.      <!--[endif]-->依照相同的操作步骤与数据录制第二份脚本并存盘。注意,所有的步骤和输入的数据一定都要一样,这样才能找出由服务器端产生的动态数据。

    有时候会遇到真的无法使用相同的输入数据,那您也要记住您使用的输入数据,到时才能判断是您输入的数据,还是变动的数据。 

    使用WinDiff工具协助找出需要关联的数据

    <!--[if !supportLists]-->1.      <!--[endif]-->在第二份脚本中,点选VuGen的【Tools>Compare with Vuser…】,并选择第一份脚本。

    <!--[if !supportLists]-->2.      <!--[endif]-->接着WinDiff会开启,同时显示二份脚本,并显示有差异的地方。WinDiff会以一整行黄色标示有差异的脚本,并且以红色的字体显示真正差异的文字。(假如没看到红色字体,请点选【Options>View>Show Inline Differences】)。

          3.  逐一检视二份脚本中差异的部份,每一个差异都可能是需要做关联的地方。选取差异的脚本,然后复制。在复制时,有时并不需要取整行脚本,可能只会选取脚本中的一部分。
    注意:请忽略lr_thik_time的差异部份,因为lr_thik_time是用来模拟每个步骤之间使用者思考延迟的时间。
    图像-0020.png

       4.  接着要在Recording Log(单一protocol)或是Generation Log(多重protocol)中找这个值。将鼠标光标点到Recording Log的第一行开头,按下Ctrl+F,开启【Find】窗口,贴上刚刚复制的脚本,找出在Recording Log第一次出现的位置。
    图像-0021.png

    <!--[if !supportLists]--><!--[endif]-->结果会有二种:

    <!--[if !supportLists]-->1      <!--[endif]-->Recording Log中找不到要找的数据,这时请先确认您找对了脚本,毕竟现在开启了二个几乎一样的脚本,很容易弄错。

               2  在Recording Log中找到了要找的数据,这时要确认数据是从服务器端传送过来的。首先可以先检查数据的标头,从标头的Receiving response可以知道数据是从服务器端传送到client端的。假如此数据第一次出现是在Sending request中,则表示此数据是由client端产生,不需要做关联,但是有可能需要做参数化(parameterized)。
    您要找的标头格式如下:
    *** [tid=b9 Action1 2] Receiving response from host astra.merc-int.com:80 ( 25/11/2002 12:04:00 )
    图像-0022.png

      5.  现在您已经找到录制二次都不一样,而且是由服务器所产生的动态数据了,而此数据极有可能需要做关联。

    使用web_reg_save_param函数手动建立关联

    在找到是由服务器所产生的动态数据之后,接下来要做的就是找出适当的位置,使用web_reg_save_param函数,将这个动态数据撷取到某个参数中。

    1.要在哪里使用web_reg_save_param函数?
    在之前的步骤,我们已经在Execution Log找到可能需要关联的动态数据。在Execution Log中选取动态数据前的文字然后复制,我们将会利用这段文字,来帮助我们找出要关联的动态数据。
    图像-0023.png

    不过在这之前我们要先找出使用web_reg_save_param函数的正确位置,所以我们要再重新执行一遍脚本,而且这次会开启所有的Log

    <!--[if !supportLists]-->1.      <!--[endif]-->VuGen中点选【Vuser>Run-Time Settings】。

    <!--[if !supportLists]-->2.      <!--[endif]-->点选【General>Log】。

    <!--[if !supportLists]-->3.      <!--[endif]-->勾选【Enable logging】、【Always sends messages】、【Extended log】,以及【Extended log】下的所有选项。

    <!--[if !supportLists]-->4.      <!--[endif]-->按下【OK】就可以执行脚本了。

    执行完脚本之后,在Execution Log中搜寻刚刚复制的字符串。找到字符串后,在字符串前面会有A.tion1.c(7),这个7就是到时候要插入web_reg_save_param函数的位置,也就是要插入到脚本的第7行。
    在脚本的第7行前插入一行空白行,然后输入
    web_reg_save_param(“UserSession”,
    “UserSession”
    这个 “UserSession” 就是到时要使用的参数名称,建议给个有意义的名字。
    注意:到这里整个web_reg_save_param函数还没完成。
    图像-0024.png

    2.找出web_reg_save_param中要用到的边界
    web_reg_save_param
    函数主要是透过动态数据的前面和后面的固定字符串,来辨识要撷取的动态数据的,所以我们还需要找出动态数据的边界字符串。

    找出左边界字符串

    再回到Execution Log中,选取动态数据前的字符串并且复制它。
    这时会有个问题,到底要选取多少字符串才足以唯一识别要找的动态数据呢?建议是越多越好,但是尽量不要包含到特殊字符。

    在这边我们选取「input type=hidden name=userSession value=」字符串。选好之后,还要再确认一次这段字符串真的是可以唯一识别的,所以我们在Execution Log中透过Ctrl+F的搜寻,找找看这段字符串是否可以找到要找的动态数据。假如找不到,web_reg_save_param函数还有个ORD参数可以使用,ORD参数可以设定出现在第几次的字符串才是要找的字符串。

    将这个边界字符串加到未完成的web_reg_save_param函数中:
    web_reg_save_param(“UserSession”, “LB= input type=hidden name=userSession value=”,

    找出右边界字符串

    接下来要找出动态数据的右边界字符串,这个字符串就比较好找了,从动态数据的最后一个字符开始,通常就是我们要找的右边界字符串了。

    以这个例子来看,就是「>」,所以再把右边界字符串加入,web_reg_save_param函数中,这时web_reg_save_param函数已经快完成了。最后再加上「LAST);」就完成整个web_reg_save_param函数了。

    web_reg_save_param(“UserSession”, “LB= input type=hidden name=userSession value=”, “RB=>”, LAST);
    图像-0025.png

    将脚本中有用到关联的数据,以参数取代

    当使用web_reg_save_param建立参数后,接下来就是用“UserSession”参数去取代脚本中写死的(hard-coded)资料。

    范例:

    “Name=userSession”, “Value=75893.0884568651DQADHfApHDHfcDtccpfAttcf”, ENDITEM,

    换成
    “Name=userSession”, “Value={UserSession}”, ENDITEM,
    图像-0026.png

    到这里您已经完成了一个关联了,接下来就是执行脚本,是否能成功运行,假如还是有问题,就要检查看看是否还需要再做另一个关联。

    关于 web_reg_save_param 函数

    对于关联(correlation)来说,web_reg_save_param是最重要的一个函数,其功能是在下载的网页内容中,透过设定的边界字符串,找出特定的数据并将其储存在一个参数中,以供后续脚本使用。

    接下来将针对web_reg_save_param做比较详细的说明。

    Service and registration type function

    web_reg_save_param是一个Service functionservice function主要是用来完成一些特殊的工作的,如关联、设定proxy、提供认证信息等,当其作用时,不会对网页的内容做任何的修改。

    web_reg_save_param同时也是一个registration type function (只要函数名称中包含_reg_的字眼,表示其为registration type function)registration type function意味着其真正作用的时机是在下一个action function完成时执行的。举例来说,当某个web_url执行时所接收到的网页内容中包含了要做关联的动态数据,则必须将web_reg_save_param放在此web_url之前,则web_reg_save_param会在web_url执行完毕后,也就是网页内容都下载完后,再执行web_reg_save_param找寻要做关联的动态数据并建立参数。

    所以要记住一点,要使用registration type function时,要注意其放置的位置必须在要作用的action function之前。

    语法

    int web_reg_save_param(const char *ParamName, <list of Attributes>, LAST);

    参数说明

    ParamName:存放动态数据的参数名称

    list of Attributes:其它属性,包含 Notfound, LB, RB, RelFrameID, Search, ORD, SaveOffset, Convert, 以及 SaveLen。属性值不分大小写,例如 Search=all。以下将详细说明每个属性值的意义:

    • Notfound:指定当找不到要找的动态数据时该怎么处置。
      • Notfound=error:当找不到动态数据时,发出一个错误讯息。假如没设定此属性,此为LoadRunner的默认值。
      • Notfound=warning:当找不到动态数据时,不发出错误讯息,只发出警告,脚本也会继续执行下去不会中断。在对角本除错时,可以使用此属性值。
    • LB:动态数据的左边界字符串。此属性质是必须要有的,而且区分大小写。
    • RB:动态数据的右边界字符串。此属性质是必须要有的,而且区分大小写。
    • RelFrameID:相对于URL而言,欲搜寻的网页的Frame。此属性质可以是All或是数字,而且可有可无。
    • Search:搜寻的范围。可以是Headers(只搜寻headers)Body(只搜寻body部分,不搜寻header)Noresource(只搜寻body部分,不搜寻headerresource)或是All(搜寻全部范围,此为默认值)。此属性质可有可无。
    • ORD:指明从第几次出现的左边界开始才是要撷取的数据。此属性质可有可无,默认值是1。假如值为All,则所有找到符合的数据会储存在数组中。
    • SaveOffset:当找到符合的动态数据时,从第几个字符开始才开始储存到参数中。此属性质不可为负数,其默认值为0
    • Convert:可能的值有二种:
      • HTML_TO_URL: HTML-encoded数据转成URL-encoded数据格式
      • HTML_TO_TEXT:HTML-encoded数据转成纯文字数据格式
    SaveLen:offect开始算起,到指定的长度内的字符串,才储存到参数中。此参数可有可无,默认值是-1,表示储存到结尾整个字符串。

    范例

    web_reg_save_param("A", "LB/ic=<a href=", "RB='>", "Ord=All", LAST);nner会搜寻网页中所有以<a href=开头,且以’>」结束,当中包含的字符串,并且储存在「A」参数中。

    Tips and Tricks

    以下提供一些关联的常见问题:

    • 如何打印出参数值?
      lr_output_message
      这二个函数来做到。例如:

    lr_output_message(“Value Captured = %s”, lr_eval_string(“{ParameterName}”));

    lr_eval_stringlr_output_message函数的使用说明请参考LoadRunner Online Function Reference

    • 在脚本的data目录下找不到路制时的快照(snapshot
      造成在脚本的data目录下找不到路制时的快照(snapshot)的可能原因如下:
      • 脚本是由VuGen 6.02或更早的版本所录制的
      • 汇入的Action不会包含快照(snapshot)的档案
      • 脚本是储存在只读的目录下,早成VuGen无法储存执行时撷取的快照(snapshot
      • 某些步骤并不会产生快照(snapshot),如浏览某个资源
      • 快照(snapshot)功能被取消
        Tools>General options>Correlationtab >Save correlation information during replay
    • 开启WinDiff时出现「File no longer available」的错误讯息
      WinDiff
      这个工具有些限制,无法开启包含空格符的目录或是脚本,所以建议命名时不要使用空格符,并且尽可能将名称取短一点。
    录制时突然跳出【Correlation warning】对话窗口
    当你有勾选自动关联的【Issue a popup message and let me decide online】选项,当VuGen发现有可能要做关联的数据时,就会跳出【Correlation warning】的窗口,询问你要做关联(Correlation in scrīpt)还是要忽略(Ignore)。
    另外你也可以勾选【Perform correlation in scrīpt】,让VuGen自动作关联,不会再跳出询问窗口。
    或是勾选【Disable correlation engine】,关闭自动关联的功能。
    图像-0027.png

    如何手动启动「Scan action for correlation」的功能
    要手动启动「Scan action for correlation」的功能,请先执行脚本一次后,点选【Vuser>Scan Action for Correlation】。
    图像-0028.png


    执行完脚本后并未出现【Scan Action for Correlation】窗口
    要启用【Scan Action for Correlation】功能,请点选【Tools>General options>Correlationtab,勾选【Show Scan for correlation popup after replay of Vuser】选项。
    图像-0029.png
  • 性能测试指标

    2007-12-12 15:38:08

    测试所需指标:
    1、 获取各WEB服务的性能指标,包括 WEB SERVER的性能(包括线程数(为了给执行队列决定一个理想的线程数,当队列中所有应用程序都运行在最大负荷的情况下,监视队列的吞吐量。增加线程数, 重复负载测试,直到达到最佳的吞吐量。(在某些情况下,增加线程数将产生足够多的上下文转换程序,使得队列中的吞吐量开始减少。))、最大并发数、最优并 发数、TPS);
    --最佳线程数(调整并满足既定的配置数,详见2.2硬件环境描述)
    --最佳吞吐量 for server (tomcat/sip/oracle)
    --响应时间 for case(OSAP/PXYWEB/xxxCOMP/WEB SERVICES)
    --最大同时并发用户数 for osap
    --最佳同时并发用户数 for osap
    --最佳用户数下的TPS for case(OSAP/PXYWEB/xxxCOMP/WEB SERVICES)
    2、 能力组件性能
    --最大并发用户数下的CPS for case(xxxCOMP)
    --最佳线程数(调整并满足既定的配置数,详见2.2硬件环境描述)
    --最佳吞吐量 for server (tomcat)
    --响应时间 for case(xxxCOMP)
    --最大同时并发用户数 for case(xxxCOMP)
    --最佳同时并发用户数 for case(xxxCOMP)
    3、 应用服务(SIPSVR)的性能指标:
    ---最佳线程数
    ---最佳吞吐量 for case5
    ---CPS for case2/case5
    4、 后置指标:
    ---各服务器的CPU占用百分比(基准测试/容量规划测试/渗入测试)
    ---各服务器的Memory平均占用比例 (基准测试/容量规划测试/渗入测试)
    (例如,如果想知道增加JVM内存是否会影响应用程序的性能,就逐次递增JVM内存(例如,从1024 MB增至1224 MB,然后是1524 MB,最后是2024 MB),在每个阶段收集结果和环境数据,记录信息,然后到下一阶段。)

    容量规划
    前提(测试结果有效的先决条件):
    1、 web/sip/oracle/第三方后台服务器配置满足建设方案标准配置或以上;

    2、 系统正常工作时,用户访问系统的基本性能需求如下:
    1) 软终端用户登录时间<= 3秒
    2) WEB终端用户页面初始化操作<= 3秒
    3) WEB接入的系统响应时间:在带宽足够的情况下,用户点击访问页面时间不超过3秒,请求提交响应时间最大不超过5秒;
    4) 系统一般性操作最长时间<= 2秒
    5) 用户操作界面友好,交互性强,在出现错误时,应能显示错误提示信息,并且错误信息能够被用户取消,并恢复界面正常显示。

    3、 根据项目一期设计,系统建设要求满足3万用户需求,业务话务模型如下:
    1) 点击拨号
    按最大CAPS为60计算,普通用户的通话时长为60秒,媒体服务器为主叫放音时长为30秒。
    2) 网络传真
    按最大CAPS为3计算,每个呼叫时长为120秒,媒体服务器话音提示时长为15秒。
    3) Web会议
    按最大CAPS为0.2计算,每次会议保持时长为120秒,会议方数为5方,40%用户存在数据协同会议需求。
    4) 短信
    短信按每秒100条计算。
    5) 电话总机
    按最大CAPS为0.5计算,每个呼叫时长为90秒。

    4、 九的个数和时间之间的对应关系。
    可接受的运行时间百分比 每天的停机时间 每月的停机时间 每年的停机时间
    95 72.00 分钟 36 小时 18.26 天
    99 14.40 分钟 7 小时 3.65 天
    99.9 86.40 秒钟 43 分钟 8.77 小时
    99.99 8.64 秒钟 4 分钟 52.60 分钟
    99.999 0.86 秒钟 26 秒钟 5.26 分钟

    5、业务比例选取:
     “xx”平台用户主要针对中小企业用户,按照约有3万企业用户,xx商业客户分类如下:
    客户类型 客户员工规模 客户数量 比率
    1-2线客户 约3-10人 135万 86%
    3-10线客户 约10-100人 19.5万 12%
    10线以上客户 约20-500人 2.2万 2%
     按以上比例,3万用户中,2.58万为1-2线用户,3600为3-10线用户,600为10线以上用户。

    6、在线使用概况
    峰值乘数用于计算与平均负载有关的系统的最大容量。 如果每秒钟的平均请求数量是 50 ,如果您的峰值乘数是 3 的话那么预期峰值将会是每秒钟 150 次请求。 为了对实施进行容量规划,您应当为系统的峰值容量做规划。
    描述 值
    会话的平均时间 7 分钟(420 秒)
    峰值乘数 3x 平均值
    每个用户每次访问的请求数 10

    7、事务比例选取
    对于行业应用,测试数据的准备中最重要的就是事务的选取,以上从业务比例中抽取每个客户类型的事务比例:
    比例的分布:
    操作 分布权重 发送比例 标准化 每个操作的请求数 每个会话的请求数 
    定购(ws)/请求使用 0.10  10*0.1=1 2 1 Ws:canuse
    登录 0.10  10*0.1=1 1 2 Login->logout
    发送传真 0.20  10*0.2=2 1 3 Osap->pxy->comp->sip
    已发/接收传真 0.03  10*0.03=0.3 2 2 Osap->pxy->comp->
    发送短信 0.20  10*0.2=2 1 3 Osap->pxy->comp->
    已发/接收短信 0.05  10*0.05=0.5 2 2 Osap->pxy->comp->
    点击拨号 0.20  10*0.2=2 1 3 Osap->pxy->comp->ctd
    发起会议 0.09  10*0.09=0.9 1 3 Osap->pxy->comp->ipunity
    定制语音流程 0.03  10*0.03=0.3 1 3 Osap->pxy->comp->->sip
    总计 1  10   

    其中 分布权重 一栏给出某类操作占总请求数的百分比。
    其中 标准化 一栏表示分布权重乘以前表给出的每用户每次访问请求数得到的结果。 注意这一栏合计达10。
    其中 每个操作的请求数 一栏给出了执行某一操作所用的用户请求数量。 由于回帖或服务器重定向等原因,有些操作会产生多个请求。
    其中 每个会话的请求数 一栏给出了用户在每次会话中发起的对某一操作的请求数量。

    8、测试强度估算:
    测试强度估算时采用如下假设前提:
    *全年的业务量集中在10个月完成,每个月20个工作日,每个工作日8个小时;
    *采用80—20原理,每个工作日中80%的业务在20%的时间内完成,即每天80%的业务在1.6小时内完成;
    测试压力的估算结果:
    按照3万用户每用户每次访问的10请求数,每7分钟一次会话计算,可处理业务约30万笔,每小时处理超过100次请求。其中,假设早上9点及下午15点为高峰期,按照2个小时段的业务处理量估计如下:
    10%的业务处理每笔订购业务需对应用服务器提交1(标准化)*10=10次请求;
    10%的业务处理每笔登录业务需对应用服务器提交1(标准化)*10=10次请求;
    20%的业务处理每笔传真业务需对应用服务器提交2(标准化)*10=20次请求;
    20%的业务处理每笔短信业务需对应用服务器提交2(标准化)*10=20次请求;
    20%的业务处理每笔呼叫业务需对应用服务器提交2(标准化)*10=20次请求;
    9%的业务处理每笔呼叫业务需对应用服务器提交9(标准化)*10=9次请求;
    其余11%的业务每笔业务向应用服务器提交1.1(标准化)*10=11次请求。

    根据以往统计结果,每年的业务增量为15%,考虑到今后三年业务发展的需要,测试需按现有业务量的2倍进行。
    每年总的请求数量为: (30*10%*10*2+30*10%*10*2+30*20%*20*2+30*20%*20*2+30*20%*20*2+30*9%*9*2+30*11% *11*2)*2=60+60+240+240+240+48.6+72.6=961.2万次/年。
    每天的请求数量为:961.2/200=4.806万次/天。
    每秒的请求数量为:(48060*80%)/(8*20%*3600)=38448/5760=6.675次/秒。
    正常情况下,应用服务器处理请求的能力至少应达到:6.675次/秒。
    某种程度上,可认为请求数量约等于交易数量:
    如果再考虑未来几年的交易量的增加(每年增长15%),则可以归纳为:
    第一年(万) 第二年(万) 第三年(万) 第四年(万) 合计(万)
    30 34.5 39.675 45.627 149.802

  • 环境回顾

    2007-12-10 15:09:33

         跟周围人生活志向不同,处事也不同,真的很看不惯叽叽喳喳的人.当然,自己也一字不吐. 测试感慨,好像凡事都只学一半,没有一项精. 记得以前做压力测试,只懂原班照抄,被问时哑口无言,只会自己讲解.    重拾以前的零散,先了解loadrunner 的 分析器 用法
  • 测试心情

    2007-10-16 13:07:26

    新环境,一而再,再而衰,三而绝.有时特失落,连话都不想讲.周围人文跟以前差太多,对目前待遇也很不满,何去何从,一味的故我??为我爱的人而改变

332/2<12
Open Toolbar