授课进程：

>>>自动化测试的分类：
单元测试的原理（白盒类测试）
自动化功能测试的原理（黑盒类测试，基于界面的测试，Java发帖演示)
性能测试的基本原理(灰盒类测试)

>>>自动化功能测试的原理：
对象识别/检查点/参数化 (模拟键盘鼠标操作和对期望结果的判断)


>>>计算器的录制与回放
录制的代码分析，专家视图与关键字视图(123+456=579)
如何运行程序SystemUtil.Run/InvokeApplication/WScript.Shell方式
窗体的常用操作(Maxmise/Minimize/Restore/Close/CaptureBitmap...)
手写代码完成1+2=3的功能
手写代码完成1+9/2+8/5+6/7+8的功能，并理解对象库原理


>>>Object Identification
录制与回放过程
Mandatory/Assistive/Location/Index/Smart属性(Mandatory必需)
MSPaint的应用：模拟录制Analog Recording
Flash计算器的低级录制：Resize和Maxmize进行稳定精确的定位
使用QTP识别ClassicsJavaA应用程序，并讲解Object Spy, Spy++(Handle句柄)及回归测试ClassicsJavaB
讲解QTP的插件机制及使用Java插件识别ClassicsJava对象
使用QTP或SPY++识别counter.java程序，为何可以识别？	Swing(JButton)/AWT(Button)
对于不能识别的对象的处理方法：
-- 低级录制(Low Level Recording)
-- 虚拟对象(Virtual Object)
安装和破解Java插件,并用来识别ClassicsJava对象


>>>检查点
自动化测试的原理：单元测试的期望结果与断言
Reporter.ReportEvent micPass及截图
CheckProperty与GetROProperty
使用QTP对flight进行自动化测试
-- 登录失败与成功的判断(用户名为空，密码为空，密码错误)
-- 检查点的设定与超时时间(全局超时File->Settings->Run，同步点或检查点超时)
-- WaitProperty同步点
-- SQL语句获取订单编号，+1产生新订单编号
-- Active Screen插入检查点和对象
-- 正则表达式作为检查点
-- Output Value


>>>参数化
参数化对象库的属性值达到同一对象库对象识别不同运行时对象的目的
使用对象的SetTOProperty来动态修改对象属性进行查找
DataTable各类操作：添加，删除，修改，导入，导出(以及用DataTable的各类方法动态实现)
使用参数化和检查点完成Flight的登录，选择城市，选择航班，选择舱位类别等操作
环境变量：系统内置的和用户自定义的Environment.Value("MyName")


>>>Action调用，函数定义，场景恢复
RunAction "Action2", oneIteration, 111, 222, Result
Call to New Action: 新增一个Action
Call to Copy of Action: 调用一个已经存在的Action的副本（相当于复制）
Call to Existing Action: 调用一个现有的Action，只做简单调用

RunAction "Action_1", oneIteration, "这是输入参数 1_1 的值", "这是输入参数 1_2 的值"
RunAction "Action_1", allIterations, "这是输入参数 1_1 的值", "这是输入参数 1_2 的值"
RunAction "Action_1", oneIteration, "这是输入参数 1_1 的值", "这是输入参数 1_2 的值"


Action1:
returnValue = RunAction("Action2", oneIteration, 111, 222, Result)
Msgbox Result
Msgbox returnValue

Action2:
Msgbox "参数1：" & Parameter("Num1") & " ----- 参数2：" & Parameter("Num2")
Parameter("Result") = Parameter("Num1") + Parameter("Num2")
exitaction "111111111111111"


>>>其它
set arr = GetTOProperties, arr.count-1, arr(i).name/value
msgbox randomnumber(1, 1000)
msgbox environment.Value("MyName")

Set calc = Description.Create
calc("text").value = "Calculator"
Window(calc).WinButton("text:=1").Click

Set calc = Window("text:=Calculator")
calc.WinButton("text:=1").Click




正则表达式：
Function RegExpTest(patm,strng)
  Dim regEx,retVal
  Set regEX = New RegExp
  regEx.Pattern=patm
  regEx.IgnoreCase=False
  retVal = regEx.Test(strng)
  If retVal Then
     RegExpTest = "匹配成功."
  Else
     RegExpTest = "匹配失败."
  End If
End Function

MsgBox RegExpTest("(xo)+","dxoxoxoxo")



描述性编程：不使用对象库，而是直接使用纯代码来进行对象识别和自动化测试。
优点：在被测程序还未实现时就已经可以开始进行自动化测试代码的开发
      代码的维护和移植更加灵活
缺点：对象识别较慢，有时会出现无法正常识别的情况



综合应用：
使用QTP结合自动化测试框架的知识来对论坛程序PHPWind进行测试，测试点如下：
注册功能
登录功能
发帖功能
回帖功能
注销退出


自动化测试框架设计思路：

分析设计：
1. 分析被测系统的各类特性，分析开展自动化测试的可行性，找出可以/不可以被自动化的部分。
2. 设计自动化测试用例（方法与手工测试用例类似，如果条件允许，也尽量考虑自动化实现方面的问题）。
3. 熟悉被测系统的基本操作，构想和设计相应的自动化测试思路和框架。

初级框架：
1. 开发自动化测试脚本（录制，描述性编程均可），将基本测试步骤流程自动化。
2. 调试，确保基本测试步骤及流程可用。
3. 分模块进行，将注册，登录，发帖等模块放到单独的Action中，使用主调Action进行调用。
4. 为单独的Action设计数据表实现参数化，并实现检查点。
5. 运行/维护自动化测试

中级框架：
1. 导出对象库，一个产品始终确保只维护少数的几个对象库，并将对象库中多余的对象删除。
2. 数据表的内容来源于Excel或XML或数据库等外部数据源。
3. 将测试用例封装到



框架的特性：
1. 减少对QTP本身的依赖
2. 测试步骤可重用
3. 测试资产可重用
4. 测试脚本维护更容易
5. 无人干预执行
6. 代码可移植性高




知识点：

自动化测试的作用
自动化测试的原理
工具无关性
Record and Run Settings选项
自动化测试之计算器演示
关键字视图与专家视图
检查点
插入测试步骤:Insert Step>Step Generator
专家视图中编辑脚本
对象层次关系
对象识别原理
Object Spy
对象库管理
Object Identification
添加测试对象到对象库
导出对象库文件
添加新的Action,Recourse > Associate Repositories关联已有的对象库
调用别的Action
创建自定义函数Insert > Function Definition Generator(不用这种方式能否创建公用函数？)
脚本调试
运行测试脚本
	Tools>Options>Run 禁用结果查看器
	Tools>Options>Run Mode: Normal可设时间间隔，Fast最快运行
选中某个测试步骤，右键Run From Step
Run Current Action
批量运行：
	Tools>Options>Run下：勾选Allow other HP prodcut ....
	开始菜单中：Tools>Test Batch Runner运行批量
测试结果截图：Tools>Options>Run: Save movie to results
Active Screen的级别设置：Tools>Options>Active Screen
利用Active Screen添加测试对象
利用Active Screen来输出属性值 Insert Output Value

参数化：datatable("column", dtGlobalSheet)
File>Settings>Run>Data Table Iterations设置迭代方式
添加Action的输入参数
添加Action的输出参数
调用其它Action: RunAction "MyAction", oneIteration, "param1", "param2"
使用环境变量：File>Settings>Environment

pathFinder
extern加载dll
systemutil.run运行程序
systemutil.blockinput屏蔽鼠标和键盘
systemutil.unblockinput
systemutil.closedescendentProcesses, closeProcessbyhwnd, closeprocessbyid, closeprocessbyname, closeprocessbywndtitle
reporter.reportevent micDone, "", ""写入测试结果
environment.value("OSVersion")取得环境变量
print显示信息
wait 3 等待3秒
executefile "mycode.vbs"执行VBS代码

虚拟对象管理(Virtual Object),不能识别的对象
QTP支持把对象虚拟成object, button, list, checkbox, table, radiobutton6种

在运行时设置选项：
setting("DefaultTimeout") = 30000 (判断一个对象是否存在的最大超时时间)

QTP中访问.NET的类库：
set x = DotNetFactory.createInstance("System.Windows.Forms.Form")
x.show
wait 5
x.close
可使用QTP调用.NET的ADO方法访问数据库

场景恢复的使用
描述性编程(某一层次使用了描述性编程，则层次结构下的后续测试对象都要使用描述性编程)
使用Description对象
set mydesc = description.create()
formname = "myform.*"
mydesc("name").value = formName
mydesc("text").value = "hello"
window(mydesc).button("text:=on").click
简化描述性编程

GetROProperty来取得对象的属性值
childObject()方法来取得某一对象的所有子对象

desktop对象的capturebitmap,childobjects,runanalog方法
clipboard对象的使用
使用exists判断控件是否存在
使用checkproperty检查控件属性


与QC的连接，放在框架中讲解


环境变量：
USER：
_JAVA_OPTIONS: -Xrunjvmhook -Xbootclasspath/a:C:\PROGRA~1\HP\QUICKT~1\bin\JAVA_S~1\classes;C:\PROGRA~1\HP\QUICKT~1\bin\JAVA_S~1\classes\jasmine.jar
IBM_JAVA_OPTIONS: -Xrunjvmhook -Xbootclasspath/a:C:\PROGRA~1\HP\QUICKT~1\bin\JAVA_S~1\classes;C:\PROGRA~1\HP\QUICKT~1\bin\JAVA_S~1\classes\jasmine.jar

SYSTEM:
_JAVA_OPTIONS: -Xrunjvmhook -Xbootclasspath/a:C:\PROGRA~1\HP\QUICKT~1\bin\JAVA_S~1\classes;C:\PROGRA~1\HP\QUICKT~1\bin\JAVA_S~1\classes\jasmine.jar

IBM_JAVA_OPTIONS: -Xrunjvmhook -Xbootclasspath/a:C:\PROGRA~1\HP\QUICKT~1\bin\JAVA_S~1\classes;C:\PROGRA~1\HP\QUICKT~1\bin\JAVA_S~1\classes\jasmine.jar
JAVA_TOOL_OPTIONS: -agentlib:jvmhook






终于被我破了，要诀就是：欲练神功，挥刀自宫。
先装QTP10装完执行破解（mgn-mqt82.exe），破解成功后备份lservrc文件，卸载QTP10。
装QTP11，可以考虑选择java等插件，装完后修改系统时间让它失效，然后参照附件破解所有插件。
破解完，再运行破解程序，再把刚才备份的lservrc里的第一行贴到QTP11的对应的lservrc文件里：
LWWD4IYBG8K3989JFZS9BLE844Y3FJ783JNJ3GFQCWR9OSY5VDCHRQNUOIVF5KQDAGNI5BX3SX# "QuickTestPro" version "6.0", no expiration date, exclusive
余下的不要动，就保留原来的。改回系统时间。破解完毕。
我已经完全破解成功。此法请大家暂时保密，哈哈！


RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\Java\","QTCoreAddin","REG_SZ"
RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\Java\ProgID","Mercury.AddinBaseObj","REG_SZ"
RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\Delphi\","QTCoreAddin","REG_SZ"
RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\Delphi\ProgID","Mercury.AddinBaseObj","REG_SZ"
RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\WebServices\","QTCoreAddin","REG_SZ"
RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\WebServices\ProgID","Mercury.AddinBaseObj","REG_SZ"
RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\WinForms\","QTCoreAddin","REG_SZ"
RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\WinForms\ProgID","Mercury.AddinBaseObj","REG_SZ"
RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\WPF\","QTCoreAddin","REG_SZ"
RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\WPF\ProgID","Mercury.AddinBaseObj","REG_SZ"
MsgBox "破解成功！"

Function RegWrite(ByVal rName,ByVal rValue,ByVal rType)
         Dim wsh,str
         Set wsh = CreateObject("Wscript.Shell")
         'str =wsh.RegRead ("HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\Java\")
         'str =wsh.RegRead ("HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\Java\ProgID")
         wsh.RegWrite rName,rValue,rType
         Set wsh = Nothing
End Function





成都周末班：
1. 自动化测试原理
2. 自动化测试脚本
3. 自动化测试框架


测试本质（期望结果）：
1. 运行被测对象
2. 定义期望结果
3. 对比实际结果

自动化测试：
1. 白盒测试：Code-Based，基于代码
2. 功能测试：GUI-Based， 基于界面
3. 性能测试：Protocol-Based，基于协议

功能测试自动化：
1. 对象识别
2. 检查点（验证点）
3. 参数化（数据池）

性能测试自动化：
1. 基于协议
2. 多线程
3. 模拟真实场景

按键精灵：

对象识别：
1. 对象的关键特征
2. 对象的长相特征
3. 对象的相对坐标

句柄(Handle)：

自动化测试工具：
商用：QTP, RFT, TestComplete .......
开源：Abbot, Selenium/WatiR/WatiJ/WatiN/, Autoit ....
平台：MS UIAutomation, CodeUI, Adobe Flash/Flex ....

工具不是唯一的，不要依赖于某一个工具，没有工具照样自动化。

针对不同的应用平台，对象识别的原理是不一样的：
1. 针对Windows应用程序，使用Win32 API: FindWindow, FindWindowEx。
2. 针对Web应用程序，使用DOM技术进行识别 (Document Object Model)。
3. 针对.NET/Java应用程序，使用反射机制进行识别。

需求提取/测试设计/用例实现/用例执行/缺陷报告.....

QTP：
1. 准备被测程序
2. 点击录制按钮
3. Record and Run Settings
4. 正常操作被测程序，确保QTP可以录制
5. 在必要时设置检查点
6. 结束录制

7. 整理代码，清除无效代码
8. 对代码进行调试，确保可以正常运行


对象识别：
1. Java: Awt, Swing
2. .NET: 非托管，托管


对象识别及属性管理：
句柄(Handle)：000F0374
识别属性：首先看Mandatory, 再看Assistive，然后Ordinal(Index, Location, Creation Time)，最后智能识别（Base, Optional)

CBT: Component-Based Testing 基于组件的测试
自动化测试框架：
a) 独立于测试工具: 只使用工具最核心的功能。
b) 测试步骤可重用: 测试用例由多个测试步骤组成。
c) 测试资产可重用：测试集(Test Suite)由多个测试用例组成。
d) 测试数据易定制：DataTable, 外部数据源。
e) 异常处理机制：  前置条件的重用，保留测试现场。
f) 测试脚本易开发：最好写测试脚本跟写手工测试用例的操作步骤一样。
g) 测试脚本易维护：数据分离，组件化设计
h) 无人干预执行：  全自动
i) 代码可移植性高：不能Hard-Code，如路径，环境变量，参数化....
j) 适宜于团队开发：规范，接口，版本控制
重用性高，自动化程度高，简单易开发易维护


第一步：创建目录
1. Start.vbs：入口程序
2. Driver：保存QTP自动化测试项目：使用QTP
3. TestScript：保存测试脚本：测试步骤，测试用例....
4. Repository：保存对象库
5. Parameter：保存测试数据源，用于参数化，确保数据和步骤分离
6. Report：保存运行结果
7. Function：保存一些企业级或项目级函数库

第二步：组件设计
1. 被测的功能模块: 注册，登录，发帖
2. 每个功能模块的测试用例
3. 考虑每个测试前置后置条件，和基本操作
4. 对象库的简化：每种对象类型只需要一个对象

第三步：实现CBT
1. Action(Operation)->Test Case->Test Suite->Test Solution
2. 对异常的处理：Prepare()和CheckXXXX()这种Action需要特别关注。
3. 通常对Action，以DoXXXX()作为命名前缀, 对Test Case，以TestXXXX()命名
4. 保留测试现场
.........

第四步：无人干预
1. 自动检测新版本，并自动完成后续安装配置。或者通过任务计划定时运行。
2. 自动启动QTP驱动脚本，驱动测试用例执行。
3. 自动将测试报告发送给相关责任人。




























' 获取文本框对象
Function GetEditByName(NameValue)
	Browser("IE").WebEdit("MyEdit").SetTOProperty "name", NameValue
	Set GetEditByName = Browser("IE").WebEdit("MyEdit")
End Function

Function GetEditById(IdValue)
	Browser("IE").WebEdit("MyEdit").SetTOProperty "html id", IdValue
	Set GetEditById = Browser("IE").WebEdit("MyEdit")
End Function

Function GetEditByIndex(NameValue, IndexValue)
	Browser("IE").WebEdit("MyEdit").SetTOProperty "name", NameValue
	Browser("IE").WebEdit("MyEdit").SetTOProperty "html id", ""
	Browser("IE").WebEdit("MyEdit").SetTOProperty "index", IndexValue
	Set GetEditByIndex = Browser("IE").WebEdit("MyEdit")
End Function

Function GetEdit(NameValue, IdValue)
	Browser("IE").WebEdit("MyEdit").SetTOProperty "name", NameValue
	Browser("IE").WebEdit("MyEdit").SetTOProperty "html id", IdValue
	Set GetEdit = Browser("IE").WebEdit("MyEdit")
End Function

Function GetEditByIndex(NameValue, IdValue, IndexValue)
	GetEdit(NameValue, IdValue).SetTOProperty "index", IndexValue
	Set GetEditByIndex = Browser("IE").WebEdit("MyEdit")
End Function

' 获取文本区域对象
Function GetTextArea(NameValue, IndexValue)
	Browser("IE").WebEdit("MyTextArea").SetTOProperty "name", NameValue
	Browser("IE").WebEdit("MyTextArea").SetTOProperty "index", IndexValue
	Set GetTextArea = Browser("IE").WebEdit("MyTextArea")
End Function

' 获取按钮对象
Function GetButton(NameValue, IndexValue)
	Browser("IE").WebButton("MyButton").SetTOProperty "name", NameValue
	Browser("IE").WebButton("MyButton").SetTOProperty "index", IndexValue
	Set GetButton = Browser("IE").WebButton("MyButton")
End Function

' 获取超链接对象
Function GetLink(TextValue, IndexValue)
	Browser("IE").Link("MyLink").SetTOProperty "text", TextValue
	Browser("IE").Link("MyLink").SetTOProperty "index", IndexValue
	Set GetLink = Browser("IE").Link("MyLink")
End Function

' 获取图像对象
Function GetImage(FileNameValue, IndexValue)
	Browser("IE").Image("MyImage").SetTOProperty "file name", FileNameValue
	Browser("IE").Image("MyImage").SetTOProperty "index", IndexValue
	Set GetImage = Browser("IE").Image("MyImage")
End Function

' 通过Html Id获取WebElement类元素
Function GetElementById(HtmlIDValue, IndexValue)
	Browser("IE").WebElement("MyElement").SetTOProperty "html id", HtmlIDValue
	Browser("IE").WebElement("MyElement").SetTOProperty "index", IndexValue
	Set GetElementById = Browser("IE").WebElement("MyElement")
End Function

' 通过innertext获取WebElement类元素
Function GetElementByText(TextValue, IndexValue)
	Browser("IE").WebElement("MyElement").SetTOProperty "html id", ""
	Browser("IE").WebElement("MyElement").SetTOProperty "innertext", TextValue
	Browser("IE").WebElement("MyElement").SetTOProperty "index", IndexValue
	Set GetElementByText = Browser("IE").WebElement("MyElement")
End Function


'GetLink("注册", "0").click
'GetEdit("username", "0").set "qtpuser999"
'GetEdit("password", "0").set "123456"
'GetEdit("password2", "0").set "123456"
'GetEdit("email", "0").set "qtpuser999@51testing.com"
'GetButton("创建用户", "0").click

'GetLink("注册", "0").click
'GetEditByIndex("username", "", "0").set "qtp888"
GetEdit("username", ".*").set "qtp10001"
'GetEditByIndex("username", "0").set "qtp100"
'GetEditById("username").set "qtpuser999"