要想使用QTP进行自动化测试,必须了解VBScript这门语言,对于使用过ASP或VB开发的人来说,VBScript已经再熟悉不过了,但是没有接触过VBScript的同学也不要灰心,因为这门语言简单易学。
1. VBScript利器
2. Hello World
3. 数据类型
4. 变量
5. 常数
6. 运算符
子曰:工欲善其事,必先利其器。学习一门语言自然是离不开工具及文档,有好的工具及文档在手,学习起来也会得心应手。在此,我推荐大家一个很不错的编辑工具——VbsEdit,该工具既能编辑代码,又可调试代码,有不错的智能提示,还有很多示例代码。可惜不是免费使用,不过网上已经有绿色版,您可以搜索下载。若你已经安装了QTP,那么使用QTP工具也是一个不错的选择。参考文档可以使用在线版《Microsoft Windows脚本技术》,也可以从网上搜索下载CHM文件。
每种语言的入门都是一样,从简单的Hello World开始,我们也不例外。如何使用VBScript来弹出一个对话框显示Hello World问候语呢?很简单,代码如下:
MsgBox("Hello world!")
MsgBox "Hello world!"
result = MsgBox("Hello World!", vbOKOnly, "Greeting")
MsgBox "Hello World!", vbOKOnly, "Greeting"
既然在此出现的第一个函数是MsgBox,那么就简单介绍一下该函数,其签名如下:
MsgBox(prompt[, buttons][, title][, helpfile, context])
主要参数:
MsgBox函数也有返回值,当你点击确定或取消按钮时,其返回的值是不一样的。其他详细内容,大家可以去查阅参考文档,这里就不逐一说明。
VBScript只有一种数据类型——Variant,它是根据上下文来判断是数字还是字符串。因为Variant是VBScript中唯一的数据类型,所以它也是VBScript中所有函数的返回值的数据类型。为了进一步区分数据类型,它包含如下数据子类型:
子类型 | 描述 |
---|---|
Empty | 未初始化的Variant。对于数值变量,值为0;对于字符串变量,值为零长度字符串 ("")。 |
Null | 不包含任何有效数据的Variant。 |
Boolean | 包含True或False。 |
Byte | 包含0到255之间的整数。 |
Integer | 包含-32,768到32,767之间的整数。 |
Currency | -922,337,203,685,477.5808到922,337,203,685,477.5807。 |
Long | 包含-2,147,483,648到2,147,483,647之间的整数。 |
Single | 包含单精度浮点数,负数范围从-3.402823E38到-1.401298E-45,正数范围从1.401298E-45到3.402823E38。 |
Double | 包含双精度浮点数,负数范围从-1.79769313486232E308到-4.94065645841247E-324,正数范围从4.94065645841247E-324到1.79769313486232E308。 |
Date (Time) | 包含表示日期的数字,日期范围从公元100年1月1日到公元9999年12月31日。 |
String | 包含变长字符串,最大长度可为20亿个字符。 |
Object | 包含对象。 |
Error | 包含错误号。 |
您可以使用转换函数(CInt,CStr等等)来转换数据的子类型。另外,可使用VarType函数返回数据的Variant子类型。
变量声明有两种方式——显式与隐式,显式使用Dim、Public、Private语句进行声明,隐式直接使用变量名。使用隐式声明方式的习惯不好,因为这样有时会由于变量名拼错而导致程序运行出现意外,因此,最好在每个脚本开始第一行使用Option Explicit语句强制显式声明所有变量。声明示例如下:
Option Explicit
Dim i, conn '声明多个变量时用逗号隔开
Public UserName, Password
Private m_id
注意:在VBScript中,变量名是不区分大小写,即userName与UserName是指同一个变量。
VBScript中变量命名是有其规则标准的,变量命名必须遵循:
变量的作用域由声明它的位置所决定。如果在过程中声明的,则只有该过程可以使用,即过程级变量;如果在过程之外声明的,则该变量可以被脚本中所有过程所使用,即Script级变量。
变量所存在的时间为存活期。Script级变量的存活期为从被声明开始,直到脚本运行结束为止;过程级变量的存活期仅是过程被调用执行开始到结束的时间。不同的过程可以使用相同的变量名,因为局部变量只有声明它的过程才能识别。
给变量赋值很简单,使用等号进行赋值,等号左边为变量名,右边为变量值。若该变量是对象引用级别的,则需使用Set语句。示例代码如下:
Dim i, conn, ui
i = 0
Set conn = CreateObject("ADODB.Connection")
Set ui = New UserInfo
只包含一个值的变量成为标量变量;有时候为了方便将一组相关值赋给一个变量,则成为数组变量。区别标量与数组的唯一方式是声明时数组变量名后面带有括号()。变量声明就不说了,前面已经提到,这里我们看看怎样声明一维数组及多维数组(最大60维——:)只要您能够理解)。
Dim a(9), table(2, 3)
a(0) = 1
...
a(9) = 11
MsgBox(a(1)) '输出数组变量值
table(0, 0) = 1
...
table(2, 3) = 10
我们也可以声明动态数组(在运行脚本时大小发生变化的数组),使用Dim或ReDim语句,但括号中不包含任何数字。要使用动态数组,必须随后使用ReDim确定维数和每一维的大小。若同时使用Preserve关键字,则在重新调整大小时保留数组的内容。
Dim count, a()
count = 9
ReDim a(count)
ReDim Preserve a(10)
常数在VBScript中是表示不变的值,用于代替数字或字符串。其内部定义了许多常数,都是以vb开头,例如在Hello World程序中涉及到的MsgBox常数“vbOKOnly”。除了MsgBox常数外,还有颜色常数、比较常数、日期和时间常数等等,详见参考文档。
内部自带常数,我们可以直接使用。当自带常数不能满足我们的需求时,我们也可以自定义常数,在VBScript中是使用Const语句来定义常数,该语句的签名如下:
[Public | Private] Const constname = expression
主要参数:
常数默认是Public级别,您也可以指定为Private级别,在同一行中声明多个常数需要用逗号分割,常数声明中不能使用变量、自定义函数及内部函数。下面是常数的一些示例代码:
Const PI = 3.14 '常数默认为公有。
Private Const STEP_APPLY = "Apply" '定义私有常数。
Const STEP_APPLY = "Apply", PI = 3.14 '在一行上定义多个常数。
VBScript有一套完整的运算符,包括算术运算符、比较运算符、连接运算符和逻辑运算符。当表达式中含有多个运算符时,它们的运算优先级是:算术运算符 > 比较运算符 > 逻辑运算符。所有比较运算符的优先级相同,算术运算符和逻辑运算符的优先级如下所示:
描述 | 符号 |
---|---|
求幂 | ^ |
负号 | - |
乘 | * |
除 | / |
整除 | \ |
求余 | Mod |
加 | + |
减 | - |
字符串连接 | & |
字符串连接 (&) 运算符不是算术运算符,但是在优先级顺序中,它排在所有算术运算符之后和所有比较运算符之前。
描述 | 符号 |
---|---|
逻辑非 | Not |
逻辑与 | And |
逻辑或 | Or |
逻辑异或 | Xor |
逻辑等价 | Eqv |
逻辑隐含 | Imp |
描述 | 符号 |
---|---|
等于 | = |
不等于 | <> |
小于 | < |
大于 | > |
小于等于 | <= |
大于等于 | >= |
对象引用比较 | Is |
Is 运算符是对象引用比较运算符。它并不比较对象或对象的值,而只是进行检查,判断两个对象引用是否引用同一个对象。
VBScript中可以使用以下条件语句:
If…Then…Else语句结构如下:
If condition Then statements [Else elsestatements]
或者使用块形式
If condition Then
[statements]
[ElseIf condition-n Then
[elseifstatements]] . . .
[Else
[elsestatements]]
End If
主要参数:
对于短小简单的测试,可以使用单行形式(第一种语法),但块形式(第二种语法)提供了比单行形式更强的结构化与适应性,比较容易阅读、维护及调试。
'1. 条件为True时
'单行形式
Dim myDate
myDate = #2011-9-8# '日期时间字符串需用#括起来
If myDate < Now Then myDate = Now
'块形式
If i = 100 Then
c = True
i = 0
End If
'2. 条件为True和False时
If user.UserName = "admin" Then
showAdminPage = True
Else
showAdminPage = False
End If
'3. 对多个条件判断
If value = 0 Then
MsgBox(0)
ElseIf value = 1 Then
MsgBox(9999)
Else
MsgBox("输入不合法!")
End If
语法结构如下:
Select Case testexpression
[Case expressionlist-n
[statements-n]] . . .
[Case Else expressionlist-n
[elsestatements-n]]
End Select
主要参数:
Select Case结构提供了If...Then...ElseIf结构的另一个变通形式,功能与If...Then...ElseIf类似,但可以使代码更加简练易读,它与Case语句关联使用。
Dim value : value = 5 '多条语句在一行,需用冒号分开
Select Case value
Case 0:
MsgBox(0)
Case 1:
MsgBox(9999)
Case Else
MsgBox("输入不合法!")
End Select
VBScript中可以使用以下循环语句:
当(或直到)条件为True时循环,语法结构如下:
当条件为True时重复执行某语句块。
Do [{While | Until} condition]
[statements]
[Exit Do]
[statements]
Loop
当条件变为True之前重复执行某语句块。
Do
[statements]
[Exit Do]
[statements]
Loop [{While | Until} condition]
主要参数:
Exit Do可以退出循环体,循环可以嵌套使用。
Do Until response = vbNo
myNum = Int(6 * Rnd + 1) '产生1到6之间的随机数
response = MsgBox(myNum & "想要另一个数吗?", vbYesNo)
Loop
Dim check, counter
check = True : counter = 0
Do
Do While count < 20
counter = counter + 1 '增加计数器
If counter = 10 Then
check = false
Exit Do '终止内循环
End If
Loop
Loop Until Not check
当条件为True时循环,语法结构如下:
While condition
[statements]
Wend
主要参数:
While…Wend没有Exit语句,从头一直循环到尾,若要在中途退出,则需用Do…Loop语句。
指定循环次数,使用计数器重复运行语句,语法结构如下:
For counter = start To end [Step step]
[statements]
[Exit For]
[statements]
Next
主要参数:
对于集合中的每项或数组中的每个元素,重复执行一组语句,语法结构如下:
For Each element In group
[statements]
[Exit For]
[statements]
Next [element]
主要参数:
在VBScript中,过程被分为两类:Sub过程和Function过程。
语法结构如下:
[Public [Default] | Private] Sub name [(arglist)]
[statements]
[Exit Sub]
[statements]
End Sub
主要参数:
如没有显式地指定使用Public或Private,则Sub过程默认为Public。调用Sub过程时,只需输入过程名及所有参数值,参数值之间使用逗号分隔。不需使用Call语句,但如果使用了此语句,则必须将所有参数包含在括号之中。调用Sub过程的两种方式。一种使用Call语句;另一种则不使用。两种方式效果相同,如:Call MySub(a, b)或MySub a, b。
语法结构如下:
[Public [Default]| Private] Function name [(arglist)]
[statements]
[name = expression]
[Exit Function]
[statements]
[name = expression]
End Function
主要参数:
如没有显式地指定使用Public或Private,则Function过程默认为Public。调用Function过程时,函数名必须用在变量赋值语句的右端或表达式中,如:b = MyFunction(a)。要从函数返回一个值,只需将值赋给函数名。在过程的任意位置都可以出现任意个这样的赋值。
VBScript作为脚本语言不仅能够编写简单的脚本,而且还能够创建及使用对象编写复杂的脚本,如Class对象,数据字典,操作文件夹及文件,错误处理,正则表达式等等。
1. Class对象
2. Dictionary对象
3. FileSystemObject对象
4. Err对象
5. RegExp对象
使用Class语句可以创建一个对象,可以为它编写字段、属性及方法,它只有两个对象事件——Initialize与Terminate。首先来看一个简单的Class示例:
Class User
'私有字段,也可以使用Public语句定义公有字段
Private m_UserName
Private m_Profile
'Initialize事件相当于构造函数
Private Sub Class_Initialize
m_UserName = Empty '设置UserName初始值为空字符串
End Sub
'Terminate事件相当于析构函数
Private Sub Class_Terminate
Set m_Profile = Nothing '将对象设置为Nothing,销毁对象
End Sub
'Property Get语句,获取属性值或对象引用,Default只与Public一起使用,表示该属性为类的默认属性
Public Default Property Get UserName
UserName = m_UserName
End Property
'Property Let语句,设置属性值
Public Property Let UserName(newUserName)
m_UserName = newUserName
End Property
Public Property Get Profile
Set Profile = m_Profile
End Property
'Property Set语句,设置属性对象引用
Public Property Set Profile(newProfile)
Set m_Profile = newProfile
End Property
'ToString方法
Public Function ToString()
ToString = "Hello! " & Me.UserName 'Me相当于C#中的this关键字
End Function
End Class
用VBScript创建的对象并不是真正的面向对象,它不能继承和实现多态,但是在QTP对象模型Utility中,提供了一个RegisterUserFunc方法可以覆写对象的方法,但这也不是真正意义上的面向对象。Class及其成员如何创建,上面已经简单介绍过,若要对其中的一些语句进一步了解,还需要去仔细阅读一些参考文档。下面我们来看看如何调用对象,在《VBScript基础上》变量赋值中也已经提到过。
Dim u '定义对象变量名,注意变量名不能与类名相同,即使是大小写不同
Set u = New User '创建对象用New语句
u.UserName = "known" '给属性赋值
MsgBox u.ToString() '调用方法
Dictionary是存储数据键和项目对的对象,其主要属性有Count、Item、Key,主要方法有Add、Exists、Items、Keys、Remove、RemoveAll。下面是该对象的一个综合示例:
'定义并创建Dictionary对象,使用CreateObject创建并返回自动化对象的引用
Dim d
Set d = CreateObject("Scripting.Dictionary")
'向Dictionary对象中添加键值对
d.Add "a", "Known" 'Add方法第一个参数是Key值,第二个是Item值
d.Add "b", "Christina"
d.Add "c", "test"
d.Add "d", "fuck"
Call ShowDictionary(d)
'遍历Dictionary对象,更改Item值
For i = 0 To d.Count - 1 'Count返回Dictionary对象中的项目数
If d.Exists("c") Then 'Exists判断Dictionary对象中是否存在指定关键字
d.Item("c") = "Test" 'Item返回Dictionary对象中指定Key的Item值
End If
Next
d.Remove("d") 'Remove从Dictionary对象中删除一个关键字,项目对。
Call ShowDictionary(d)
'输出Dictionary对象所有键值
Sub ShowDictionary(dic)
Dim str, a
a = dic.Items 'Items返回一个包含所有Item值的数组
For i = 0 To dic.Count - 1
str = str & a(i) & vbCrlf
Next
MsgBox(str)
End Sub
FileSystemObject对象可以操作驱动器、文件夹及文件,其对象模型包含下面的对象和集合。
对象/集合 | 描述 |
---|---|
FileSystemObject | 主对象。包含用来创建、删除和获得有关信息,以及通常用来操作驱动器、文件夹和文件的方法和属性。和该对象相关联的许多方法,与其他 FSO 对象中的方法完全相似;它们是为了方便才被提供的。 |
Drive | 对象。包含用来收集信息的方法和属性,这些信息是关于连接在系统上的驱动器的,如驱动器的共享名和它有多少可用空间。请注意,"drive" 并非必须是硬盘,也可以是 CD-ROM 驱动器,RAM 磁盘等等。并非必须把驱动器实物地连接到系统上;它也可以通过网络在逻辑上被连接起来。 |
Drives | 集合。提供驱动器的列表,这些驱动器实物地或在逻辑上与系统相连接。Drives 集合包括所有驱动器,与类型无关。要可移动的媒体驱动器在该集合中显现,不必把媒体插入到驱动器中。 |
File | 对象。包含用来创建、删除或移动文件的方法和属性。也用来向系统询问文件名、路径和多种其他属性。 |
Files | 集合。提供包含在文件夹内的所有文件的列表。 |
Folder | 对象。包含用来创建、删除或移动文件夹的方法和属性。也用来向系统询问文件夹名、路径和多种其他属性。 |
Folders | 集合。提供在 Folder 内的所有文件夹的列表。 |
TextStream | 对象。用来读写文本文件。 |
FileSystemObject对象所有属性、方法及对象和集合的详细说明,您可以查阅参考文档,因为内容比较多,我们就看一个简单的示例,直观地来了解一下该对象的使用,该示例是将一个文件复制到指定文件夹下。
'定义并创建对象
Dim fso, filePath, folderPath
Set fso = CreateObject("Scripting.FileSystemObject")
filePath = "C:\\Test.txt"
folderPath = "D:\\Test"
Call MoveFile(filePath, folderPath)
'将文件移动到指定文件夹
Sub MoveFile(sourceFile, targetFolder)
Dim file, fileName
'获取文件对象
Set file = fso.GetFile(sourceFile)
'判断目标文件夹是否存在
If Not fso.FolderExists(targetFolder) Then
fso.CreateFolder(targetFolder)
End If
'将文件移动到目标位置
file.Move(targetFolder & "\\" & file.Name)
End Sub
Err对象是一个具有全局范围的内部对象,不必在代码中创建它的实例,含有关于运行时错误的信息。主要属性有Description、HelpContext、HelpFile、Number、Source,主要方法有Clear、Raise,其属性及方法的详细说明详见参考文档。下面的示例说明了Err对象的用法:
'示例1:
On Error Resume Next
Err.Raise 6 '产生溢出错误
MsgBox("Error #" & CStr(Err.Number) & " " & Err.Description)
Err.Clear
'示例2:
'定义数据库连接
Dim conn
Set conn = CreateObject("ADODB.Connection")
conn.BeginTrans '开始事务
...
'提交数据库事务错误处理
On Error Resume Next
If conn.Errors.Count > 0 Then
conn.RollbackTrans '回滚事务
Else
conn.CommitTrans '提交事务
End If
Err.Clear
RegExp是正则表达式对象,提供简单的正则表达式支持功能。主要属性有Global、IgnoreCase、Pattern,主要方法有Execute、Replace、Test,其属性及方法的详细说明详见参考文档。下面的示例说明了RegExp对象的用法:
Function RegExpTest(patrn, strng)
Dim regEx, match, matches '建立变量。
Set regEx = New RegExp '建立正则表达式。
regEx.Pattern = patrn '设置模式。
regEx.IgnoreCase = True '设置是否区分字符大小写。
regEx.Global = True '设置全局可用性。
Set matches = regEx.Execute(strng) '执行搜索。
For Each match in matches '遍历匹配集合。
retStr = retStr & "Match found at position "
retStr = retStr & match.FirstIndex & ". Match Value is '"
retStr = retStr & match.Value & "'." & vbCRLF
Next
RegExpTest = retStr
End Function
MsgBox(RegExpTest("is.", "IS1 is2 IS3 is4"))
每当使用C#中的Array.ForEach时,感觉很爽。最近在做QTP自动化测试时,偶然在QTP自带示例中看到一段代码可以动态调用方法,于是先喜若狂,着手改编了一下,写了一个VBScript版的Array.ForEach功能,使用起来确实不错。其实关键的一个地方就在于使用了VBScript中的Eval函数。首先我们来看看Eval函数的作用。
Eval函数主要是计算一个表达式的值并返回结果。其签名如下:
[result = ]Eval(expression)
参数如下:
在VBScript中,x = y可以有两种解释。第一种方式是赋值语句,将y的值赋予x。第二种解释是测试x和y是否相等。如果相等,result为True;否则result为False。Eval方法总是采用第二种解释,而Execute语句总是采用第一种。下面是Eval函数的简单示例:
Dim a, b
a = 1
b = 2
MsgBox Eval("a + b")
执行一个或多个指定的语句。其签名如下:
Execute statements
所需要的statements参数是一个字符串表达式,其中包含一个或多个要执行的语句。如果要在statements参数中包含多条语句,应使用冒号或嵌入的分行将其分隔开。下面是Execute语句的简单示例:
Dim a, b, c, d
a = 1
b = 2
Execute "c = a + b : d = a + c"
MsgBox c
MsgBox d
ForEach函数有两个参数,一个是数组变量,一个是遍历方法名称。其实现代码如下:
Sub ForEach(source, method)
Dim i, current
For i = 0 To UBound(source)
If IsObject(source(i)) Then '判断数组元素是否为对象
Set current = source(i)
Else
current = source(i)
End If
Eval(method & "(current)") '调用遍历方法
Next
End Sub
遍历一个整数数组的示例:
'显示数组元素方法
Function ShowValue(val)
MsgBox val
End Function
Dim i, arr(10)
'给数组元素赋值
For i = 0 To 10
arr(i) = i
Next
'调用ForEach遍历
Call ForEach(arr, "ShowValue")
遍历一个对象数组的示例:
'用户类
Class User
'用户属性
Public UserName, Email
'ToString方法
Function ToString()
ToString = Me.UserName & " : " & Me.Email
End Function
End Class
'显示用户信息方法
Function ShowUser(usr)
MsgBox usr.ToString()
End Function
Dim arr(5), u
'给数组元素赋值
For i = 0 To 5
Set u = New User
u.UserName = "user" & CStr(i)
u.Email = "user" & CStr(i) & "@xxx.com"
Set arr(i) = u
Next
'调用ForEach遍历
Call ForEach(arr, "ShowUser")
看代码很简洁,不是嘛,原来VBScript也可以像C#一样使用ForEach。VBScript应该还能够实现C#中的其他很多特性,以后在编写测试代码过程中,要不断去总结。