VBScript函数作为参数或类似的构造

时间:2015-06-26 16:15:43

标签: vbscript function-pointers hp-uft

我试图将测试放在HP Unified Functional Testing中 程序员的方式。 对于那些不知道的人,该工具使用VBScript作为其驱动程序。

因为我想在多个UFT操作中使用来自同一DataTable的数据 - 并且因为全局表已经有一组不同的数据 - 我想从外部文件中检索数据。 UFT很乐意支持这个功能。

我目前的计划是,根据我正在进行的测试, 我将遍历该表中的一系列行。

这是我提出的脚本:

' targets the local sheet, but 
' not the same value as dtLocalSheet
Const sheetNum = 2 

dim sheetRowCount
DataTable.ImportSheet "PersonFile.xlsx", 1, sheetNum
sheetRowCount = DataTable.GetSheet(sheetNum).GetRowCount

dim firstRow, lastRow
firstRow = Parameter("FirstPersonIndex")
lastRow = Parameter("LastPersonIndex")
If sheetRowCount < lastRow Then
    lastRow = sheetRowCount
End If

If sheetRowCount >= firstRow Then
    Dim i
    For i = firstRow To lastRow
        DataTable.SetCurrentRow i

        ' begin payload
        MsgBox(DataTable.Value("LastName", dtLocalSheet))
        ' end payload

    Next
End if

我不想重复所有这些样板 每次我想使用这种模式。 我真的很喜欢这样的东西:

在函数库中:

sub LoopThroughSheetAnd(sheetFile, doThis)
    ' targets the local sheet, but 
    ' not the same value as dtLocalSheet
    Const sheetNum = 2 

    dim sheetRowCount
    DataTable.ImportSheet sheetFile, 1, sheetNum
    sheetRowCount = DataTable.GetSheet(sheetNum).GetRowCount

    dim firstRow, lastRow
    firstRow = Parameter("FirstRow")
    lastRow = Parameter("LastRow")
    If sheetRowCount < lastRow Then
        lastRow = sheetRowCount
    End If

    If sheetRowCount >= firstRow Then
        Dim i
        For i = firstRow To lastRow
            DataTable.SetCurrentRow i

            call doThis()
        Next
    End if
end sub

在最初的行动......

sub Payload1()
    MsgBox(DataTable.Value("LastName", dtLocalSheet))
end sub
LoopThroughSheetAnd "PersonFile.xlsx", Payload1

在单独的行动中,3或4步之后......

sub Payload2()
    ' compare the data against another data source
end sub
LoopThroughSheetAnd "PersonFile.xlsx", Payload2

上述代码在VBScript中不起作用。 抛出类型不匹配错误 一旦我们尝试将Payload1作为参数传递。

如何才能在VBScript中合理地解决这个问题? 如果答案也适用于UFT,则奖励积分。

4 个答案:

答案 0 :(得分:5)

可以使用GetRef()函数将函数作为参数传递。这是一个实用程序map函数,就像您在JavaScript中找到接受数组并为数组的每个元素调用函数一样:

Sub Map(a, f)
    Dim i
    For i = 0 To UBound(a)
        ' Call a function on each element and replace its value with the function return value
        a(i) = f(a(i))      
    Next
End Sub

Map MyArray, GetRef("SomeFunc")

现在您可以编写SomeFunc以便它对值进行操作并返回更新的值:

Function SomeFunc(i)
    SomeFunc = i + 1
End Function

这很好用。 map使用函数&#34;指针&#34;调用SomeFunc我们过去了。

您可以使用LoopThroughStreetAnd函数执行类似操作:

LoopThroughStreetAnd "PersonFile.xlsx", GetRef("Payload2")

答案 1 :(得分:2)

VBScript中的标准回调方式使用GetRef,与this demo中一样。

答案 2 :(得分:0)

使用对象时,可以将对方法的调用包装在对象中,然后可以传递该对象。 (这大约已经是其他语言所发生的事情,您只需在VBScript中手动进行操作即可。)

唯一的问题是调用此方法的任何方法都必须是Public

我将使用诸如“ Func1”,“ Func2”,“ Action1”,“ Action2”等之类的命名方案,具体取决于函数的可用性以及它们是否返回值。

Dim s : Set s = New Something : s.Run

Class Something
   Public Sub HowToPassMe(pValue)
      WScript.Echo pValue
   End Sub

   Public Sub Run
      Dim action : Set action = New Action1Wrapper
      Set action.Target = Me
      Dim se : Set se = New SomethingElse
      se.DoSomethingElse action
   End Sub
End Class

Class SomethingElse
   Public Sub DoSomethingElse(pAction1)
      pAction1.Action1("something")
   End Sub
End Class

Class Action1Wrapper
   Private mTarget
   Public Property Set Target(value) : Set mTarget = value : End Property

   Public Sub Action1(p1)
      mTarget.HowToPassMe(p1)
   End Sub
End Class

使用ExecuteAction1Wrapper也可以像下面这样写。您还可以编写工厂类以方便使用。

Class Action1Wrapper
   Private mTarget
   Public Property Set Target(value) : Set mTarget = value : End Property

   Private mName
   Public Property Let Name(value) : mName = value : End Property

   Public Sub Action1(p1)
      Execute "mTarget." & mName & "(p1)"
   End Sub
End Class

Class Action1Factory_
   Public Function Create(pTarget, pName)
      Dim a1 : Set a1 = New Action1Wrapper
      Set a1.Target = pTarget
      a1.Name = pName
      Set Create = a1
   End Function
End Class
Dim Action1Factory : Set Action1Factory = New Action1Factory_

用作:

Dim action : Set action = Action1Factory.Create(Me, "HowToPassMe")
Dim se : Set se = New SomethingElse
se.DoSomethingElse action

答案 3 :(得分:-1)

当我写这个问题时,我的记忆变得不合时宜, 我开始研究我曾经发现的“特征”。

这在HP UFT的上下文中无效, 但如果您正在运行cscript,或使用Classic ASP, 你可以延迟声明一个函数,或者替换以前的声明, 改变它的运作方式。

VBScript允许您声明相同的函数或子例程 在程序中多次。 它将最后一个声明视为正确声明。

你可以通过物理分离在cscript和ASP中解决这个问题 不同版本的功能, 这样一个人就不会被另一个人摧毁。 你必须要小心,不要把两者放在彼此附近, 或者你(继任者)可能有动脉瘤试图调试结果。

老实说,你可能会更好地以其他方式重构你的代码。

现在,在免责声明的情况下, 以下示例适用于cscript或wscript。

代码

因为无论如何这都不适用于UFT,我会从头开始写。

WrapperSub.vbs

' Sub WrapperSub_Payload doesn't exist in this file.
' It must be declared by the calling file or the program will crash.
Sub WrapperSub()
    wscript.echo("This begins the wrapper.")
    WrapperSub_Payload
    wscript.echo("This ends the wrapper.")
End Sub

WrapperSubUseA.vbs

With CreateObject("Scripting.FileSystemObject")
    call ExecuteGlobal(.openTextFile("WrapperSub.vbs").readAll())
End With

Sub WrapperSub_Payload
    wscript.echo("This is payload A.")
End Sub

WrapperSub

WrapperSubUseB.vbs

With CreateObject("Scripting.FileSystemObject")
    call ExecuteGlobal(.openTextFile("WrapperSub.vbs").readAll())
End With

Sub WrapperSub_Payload
    wscript.echo("This is payload B.")
End Sub

WrapperSub

输出

>cscript wrappersubusea.vbs
Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation. All rights reserved.

This begins the wrapper.
This is payload A.
This ends the wrapper.

>cscript wrappersubuseb.vbs
Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation. All rights reserved.

This begins the wrapper.
This is payload B.
This ends the wrapper.

请注意,如果是WrapperSub_Payload的占位符 在源文件中声明, 该占位符将始终执行而不是预期的子例程。 这可能是由于ExecuteGlobal 在解析当前文件后执行, 导致占位符在本地声明后加载。

当您在UFT中尝试此操作时 - 将WrapperSub.vbs的内容放在函数库中 - 函数库正确地忽略了调用者的作用域。 然后它将失败,因为范围中不存在WrapperSub_Payload