发布新日志

  • VBS里Err对象的使用

    2008-12-04 23:58:57

    Err对象作为VBS里的一个固有内置全局对象,在使用时无需先创建一个对象实例。它有其属性和方法:

     

    1. 属性

    a) Number 默认属性

    b) Source

    c) HelpFile

           用法:object.HelpFile [= contextID]

    d) Descrīption:当没有用户自定义Descrīption值时,该值为Number属性值

           用法:object.Descrīption [= stringexpression]

    e) HelpContext

           用法:object.HelpContext [= contextID]

           If both HelpFile and HelpContext are empty, the value of the Number property is checked.

     

    2. 方法

    Clear:重置Err对象

    Raise:产生运行错误

     

    当遇到On Error Resume Nex后,Err对象的属性被重置为0或者是长度为0的字符串。

     

    典型的Err对象用法:

     

    On Error Resume Next

    Dim Msg

    Err.Clear

    Err.Raise 6   ' Generate "Overflow" error.

    Err.Helpfile = "yourHelp.hlp"

    Err.HelpContext = yourContextID

    If Err.Number <> 0 Then

       Msg = "Press F1 or Help to see " & Err.Helpfile & " topic for" & _

       " the following HelpContext: " & Err.HelpContext

       MsgBox Msg, , "error: " & Err.Descrīption, Err.Helpfile, Err.HelpContext

    End If

  • 第一次使用描述性编程

    2008-12-04 23:56:49

    过去一直认为描述性编程对于QTP的意义不是很大,所以一直都使用对象库进行脚本编写和维护。最近却遇到一个难题,使用对象库无法解决:一个WebEdit在一个表格里被一个WebElement覆盖,点击该WebElementWebEdit才可见,Focus移走,它立马就不可见了,可以通过Spy来查看该WebEdit的属性,但是当加入到对象库时,由于对象已经不可见,可以最初抓到它,但是加入到对象库却没办法成功。

     

    这样已经无法通过对象库加入到脚本语句里了,于是再粗略的翻看了一下用户手册,才想起来描述性编程可能可以解决这个问题,于是试验了一下,果然能行。因为先Click这个单元格里的WebElement,然后WebEdit可见,直接用描述性编程就可对其进行操作:

    Browser(“browser”).Page(“page”).WebTable(“tablename”).ChildItem(2, 2, “WebElement”, 0).Click

    Browser(“browser”).Page(“page”).WebTable(“tablename”).WebEdit(“name:=textbox”).Set “test”

     

    不知道有没有人清楚还有其他哪些情况必须使用“描述性编程”才能解决问题的例子,希望可以一起交流一下。

  • vbs调用QTP

    2008-11-13 14:19:40

    Dim qtApp 'As QuickTest.Application ' Declare the Application object variable
    Dim qtTest 'As QuickTest.Test ' Declare a Test object variable
    Dim qtResultsOpt 'As QuickTest.RunResultsOptions
    ' Declare a Run Results Options object variable
    Set qtApp = CreateObject("QuickTest.Application") ' Create the Application object
    qtApp.Launch ' Start QuickTest
    qtApp.Visible = True ' Make the QuickTest application visible

    ' Set QuickTest run options
    qtApp.Options.Run.ImageCaptureForTestResults = "OnError"
    qtApp.Options.Run.RunMode = "Fast"
    qtApp.Open "C:\ Your Test Path Here", True ' Open the test in read-only mode

    ' set run settings for the test
    Set qtTest = qtApp.Test
    qtTest.Settings.Run.OnError = "NextStep" ' Instruct QuickTest to perform next step when error occurs
    Set qtResultsOpt = CreateObject("QuickTest.RunResultsOptions") ' Create the Run Results Options object
    qtResultsOpt.ResultsLocation = "C:\Your Results Path Here" ' Set the results location

    qtTest.Run ' Run the test

    'qtTest.Close ' Close the test
    Set qtResultsOpt = Nothing ' Release the Run Results Options object
    Set qtTest = Nothing ' Release the Test object
    Set qtApp = Nothing ' Release the Application object

  • Close redundant browser

    2008-11-13 12:06:40

    1. Through descrīption object

    Dim WinIe,Ie,k,m
    Set WinIe=descrīption.Create()
    WinIe("micclass").value="Browser"  'The property regexpwndtitle of all pages is " Microsoft Internet Explorer"
    Set Ie=desktop.ChildObjects(WinIe)
    m=Ie.count
    If  m>1 Then
            For k=0 to m-1
            Ie(k).close        

            Next
    End If
    Set ie = nothing

    2. Through close process

    SystemUtil.CloseProcessByName "iexplore.exe"

  • (转)使用 XML 文件记录操作日志

    2008-11-07 18:20:12

    记录应用程序的操作日志可以使用数据库、文本文件、XML文件等。我这里介绍的是使用 XML 文件记录操作日志。
    我觉得使用 XML 记录操作日志有如下几点好处:
    1. 不占用数据库的空间,可以任意的删除历史操作日志。
    2. DataTable 可以方面的读入 XML 文件,DataTable 也可以方便的保存为 XML 文件。
    3. 查看日志方便,可以直接打开 XML 文件查看,也可以读入 DataTable,然后通过程序查看。

    在 VS2005 中使用 XML 文件记录操作日志方法如下:
    1. 建立数据集:JobLogDataSet.xsd
        这里包括:TraceLevel(日志类型)、User(用户)、DateTime(操作时间)、Module(模块)、Function(功能)、Message(消息) 6 个字段。
        不够自己再加吧, 其中 TraceLevel(日志类型) 是指 Info,Warning,Error,Trance,Off。

       

    2. 建立日志类型     /// <summary>
        /// 日志类型
        /// </summary>
        public enum LogType
        {
            /// <summary>
            /// 信息
            /// </summary>
            Info,
            /// <summary>
            /// 警告
            /// </summary>
            Warning,
            /// <summary>
            /// 错误
            /// </summary>
            Error,
            /// <summary>
            /// 跟踪
            /// </summary>
            Trace,
            /// <summary>
            /// 不记录日志
            /// </summary>
            Off
        }
    2. 写日志的方法
        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="traceLevel">日志类型(Info,Warning,Error,Trance,Off)</param>
        /// <param name="user">用户</param>
        /// <param name="module">模块</param>
        /// <param name="function">功能</param>
        /// <param name="message">消息</param>
        public static void WriteLog(LogType logType,string user, string module, string function, string message)
        {
            try
            {
                // 类型为 LogType.Off 的 不记录日志
                if (logType == LogType.Off)
                    return;

                JobLogDataSet.JobLogDataTable t = new JobLogDataSet.JobLogDataTable();

                // 每天一个日志文件(.XML 文件),日志的文件名称为:JobLog yyyy-MM-dd.xml
                string jobLogFile = AppDomain.CurrentDomain.BaseDirectory + "JobLog " +
                    DateTime.Today.ToString("yyyy-MM-dd") + ".xml";
                if (!File.Exists(jobLogFile))
                    t.WriteXml(jobLogFile);

                // 从 .XML 文件中读取日志
                t.ReadXml(jobLogFile);

                // 添加一条日志
                JobLogDataSet.JobLogRow r = t.NewJobLogRow();
                r.TraceLevel = logType.ToString();
                r.User = user;
                r.Datetime = DateTime.Now;
                r.Module = module;
                r.Function = function;
                r.Message = message;
                t.AddJobLogRow(r);

                // 保存到日志到 XML 文件
                t.WriteXml(jobLogFile);
            }
            catch (Exception)
            {}
        }
    3. 读日志的方法
        /// <summary>
        /// 读日志
        /// </summary>
        /// <returns>返回读取日志的 DataTable</returns>
        public static JobLogDataSet.JobLogDataTable ReadLog()
        {
            JobLogDataSet.JobLogDataTable jobLogDataTable = new JobLogDataSet.JobLogDataTable();
            try
            {
                // 从应用程序文件夹中,获得所有日志文件 JobLog*.xml
                string[] jobLogFiles = Directory.GetFiles(
                    AppDomain.CurrentDomain.BaseDirectory, "JobLog*.xml", SearchOption.TopDirectoryOnly);

                // 把每个日志记录读取到日志 DataTable 中
                foreach (string jobLogFile in jobLogFiles)
                {
                    if (File.Exists(jobLogFile))
                    {
                        // 读取所有日志文件到临时 DataTable
                        JobLogDataSet.JobLogDataTable t = new JobLogDataSet.JobLogDataTable();
                        t.ReadXml(jobLogFile);
                        // 导入日志记录到主日志 DataTable
                        foreach (JobLogDataSet.JobLogRow r in t)
                            jobLogDataTable.ImportRow(r);
                    }
                }
                // 返回读取的日志 DataTable
                return jobLogDataTable;
            }
            catch (Exception)
            {
                return jobLogDataTable;
            }
        }
    4. 在需要写日志的地方,直接调用 WriteLog 方法即可。

  • loadrunner中运行java代码

    2008-10-15 10:17:23

    概要步骤:

    1.在eclipse建立java工程,编译要使用的java方法;

    2.打开loadrunner,新建立脚本选择java脚本模式;

    3.找到脚本存放的文件夹,把步骤1中整个的编译后的目录(class文件所在的整个目录)放如脚本文件夹中,

      loadrunner就可以使用该java方法;

     Java脚本开发基础

    要想掌握Java虚拟用户的使用,测试脚本开发人员至少需要两方面的技能:一是具有Java语言方面的技能,并熟练使用至少一种Java集成开发工具,例如Eclipse;二是掌握LoadRunner的Java API,Java API是访问Vuser函数的基础,通过LoadRunner的Java API可以在脚本中很容易地创建事务与并发点、获取用户信息等功能。

    不难看出,Java虚拟用户要求测试脚本开发人员具有良好的开发基础,否则Java Vuser很难发挥应有的作用。限于篇幅,本节在Java测试开发基础部分,仅对Java语言方面的知识做概要介绍,读者可以通过Java方面的书籍进行学习;在LoadRunner的Java API部分,将会介绍一些相对重要的方法。

    Java虚拟用户开发基础

    Java语言基础

    Java语言博大精深,即使资深的Java开发工程师也未必敢自称精通,测试人员就更不容易成为“高手”了。但是如果仅仅为了满足测试开发,还是很容易快速入门的。表7-1列出了一些进行Java虚拟用户开发的知识点,读者可以自行学习。

    表7-1  Java语言基础知识

    知识点

    详细内容

    Java背景知识

    ²  Java历史及发展、语言特点

    ²  Java开发环境、程序工作原理

    续表

    知识点

    详细内容

    Java语言基础

    ²  Java数据类型

    ²  Java运算符与表达式、控制语句

    ²  Java类定义规范

    ²  Java数组

    ²  Java的包

    Java与面向对象技术

    ²  面向对象的概念

    ²  Java中的类、方法和变量

    ²  Java名字空间及访问规则

    ²  Java中的抽象类、接口和程序包

    ²  对象的构造方法

    Java中的数据结构

    ²  Java数组

    ²  向量

    ²  字符串

    输入/输出处理 

    ²  I/O流概述

    ²  字节流

    ²  字符流

    例外处理(Exception)

    ²  例外的概念

    ²  例外的分类

    ²  捕获例外

    ²  声明例外

    ²  抛出例外

    多线程

    ²  多线程基本概念

    ²  创建线程的方式

    ²  线程的生命周期及控制

    ²  线程的调度

    ²  多线程的互斥与同步

    ²  线程组

    Java基本网络编程

    ²  Java与Internet

    ²  使用InetAddress

    ²  使用URL

    ²  Socket通信、数据报通信

    JDBC

    ²  JDBC基础、JDBC驱动程序

    ²  JDBC编程

    续表

    知识点

    详细内容

    Java Servlet

    ²  Servlet基本概念

    ²  Servlet API

    ²  Servlet执行过程与生命周期

    ²  容器、部署与运行

    Java Server Page(JSP)

    ²  JSP基础、JSP语法

    测试人员在掌握了上面这些技能后,基本可以进行Java虚拟用户的开发了。同时,本着学无止境的原则,测试人员仍要以积极的态度来学习Java开发知识。

    Java集成开发工具Eclipse

    Eclipse是一个与NetBeans、Sun ONE Studio和Borland Jbuilder类似的,一种基于Java的整合型可扩展开发平台,也是目前最著名的开源项目之一。IBM一直在大力支持该项目的发展,并在2001年 11月宣布投入4千万美元到该项目的研发,这也是Eclipse项目发展较快的原因之一。

    Eclipse专注于为高度集成的工具开发提供一个全功能的、具有商业品质的工业平台。它主要由Eclipse项目、Eclipse工具项目和Eclipse技术项目组成,具体包括四个组成部分:Eclipse Platform、JDT、CDT和PDE。JDT支持Java开发、CDT支持C开发、PDE用来支持插件开发,Eclipse Platform则是一个开放的可扩展IDE,提供了一个通用的开发平台。

    Eclipse SDK(软件开发包)是Eclipse Platform、JDT和PDE所生产的组件合并,它们可以从eclipse.org网站(http://www.eclipse.org /downloads)上下载。这些组件提供了一个具有丰富特性的开发环境,允许开发者有效地建造可以无缝集成到Eclipse Platform中的工具。Eclipse SDK由Eclipse项目生产的工具和来自其他开放源代码的第三方软件组合而成。

    在接下来的内容里,将介绍用Eclipse创建与编译Java类文件的过程以及如何在Java虚拟用户中调用编译好的类文件。关于Eclipse更深入的内容请读者参考其相关书籍。

    l  创建Java项目

    启动Eclipse后,依次选择菜单的“文件”→“新建”→“项目”,进入图7-7所示的界面。

    图7-7  新建项目

    在图7-7中选择Java项目,单击“下一步”,进入图7-8所示的界面。

    图7-8  配置项目

    在图7-8的“项目名称”输入“LoadRunnerDev”,“位置”下选择“在外部位置创建项目”,目录下选择“D:\LoadRunner”。然后点击“配置缺省值(O)...”,进入图7-9所示的界面。

    图7-9  配置缺省值

    在图7-9的“源和输出文件夹”处选择“文件夹(F)”,“源文件夹名(S):”默认为“src”,无须改变,在“输出文件夹名(O):”处输入“classes”,完成后返回图7-8所示界面。在图7-8中点击“下一步”,进入图7-10所示的界面。

    图7-10  配置结果界面

    在图7-10中,单击“完成”,新建Java项目工作完成。在图7-11中可以看到新建的项目“LoadRunnerDev”。

    图7-11  包资源管理器

    l  建立Java文件

    如图7-12所示,在LoadRunnerDer中选中“src”,点击鼠标右键,进入“新建”,点击“类”,进入图7-13所示的新建Java类文件设置界面。

    图7-12  新建Java类文件

    在图7-13中,输入包名称“com.lr.test”、类名称“HelloWord”,其他各项设置默认即可。点击“完成”,进入源代码编辑界面,如图7-14所示。

    图7-13  文件基本配置信息

    图7-14  文件编辑界面

    在源代码编辑界面,输入测试语句“System.out.println("HelloWord!");”如图7-14所示。代码编辑完成后,按照图7-15编译与运行程序。如果编译执行成功,可以在Eclipse的控制台看到输出结果,如图7-16所示。

    图7-15  执行Java程序

    图7-16  查看编译结果

    l  编译与运行Java程序

    编译后的class文件可以在“D:\LoadRunner\classes\com\lr\test”下找到,如图7-16所示。需要注意的是,类文件的存放路径是根据建立项目的设置来决定的。

    l  开发虚拟用户脚本

    进入到“D:\LoadRunner\classes”目录下,把整个“com”文件夹复制到“C:\j2sdk1.4.1\lib”,这样LoadRunner创建的所有Java Vuer脚本均可以直接调用;如果放到虚拟用户脚本的当前路径下,则只有当前的虚拟用户脚本可以调用。多台主机进行并发测试时,应该把编译好的类文件放到对应的虚拟用户脚本目录下。根据图7-1和图7-2所示新建一个Java虚拟用户脚本,并对照图7-17,输入同样的测试脚本,尤其要在代码开始处输入包的导入语句“import com.lr.test.*;”。

    图7-17  Java虚拟用户示例脚本

    l  运行虚拟用户脚本

    点击Virtual User Generator 工具栏上的  图标开始执行脚本。正确的执行结果如图7-18所示,可以看到执行日志中有“System.out: HelloWord!”。如果运行不正确,读者可以参照前面的过程进行分析,同时检查JDK的路径设置。

    图7-18  正确执行的虚拟用户脚本

    与 C Vuser脚本相比,Java Vuser 脚本是先编译再执行,而C Vuser脚本是解释性的。VuGen在JDK安装路径内查找javac编译器,并在脚本内编译Java代码。该阶段由VuGen窗口底部的“正在编译... ”状态消息来指示。如果在编译期间出错,则这些错误将在执行日志中列出。

    测试脚本保存后,接下来可以放到Controller中来运行,读者可以自己进行实验。需要注意的是,如果进行多台计算机联机测试,则所有运行测试脚本的客户机必须安装JDK环境并正确设置路径,否则将会出现如图7-19所示的提示。

    图7-19  JDK环境不正确的提示

    要想正确使用Java虚拟用户,首先要保证测试环境配置正确。执行测试时,可以先用本节的示例程序来检查环境是否正确,然后再进行复杂功能的开发。

    LoadRunner的Java API

    LoadRunner为访问Vuser函数提供了特定的 Java API,这些函数都是lrapi.lr类的静态方法。借助Java API可以大大增强Java虚拟用户脚本的可用性。本节将介绍常用的Java API的用法,更多的函数及其用法读者可以参考LoadRunner联机手册。

    在Java虚拟用户中,Java API函数的用法与Vuser函数中的用法基本一致,只是写法稍稍不同,更符合Java语言的特点。

    1. 事务函数(Transaction Functions)

    (1)int lr.start_transaction( String transaction_name ):标记事务开始;

    (2)int lr.end_transaction ( String transaction_name, int status ):标记事务结束。

    2. 信息函数(Informational Functions)

    (1)String lr.get_group_name( ):返回 Vuser 组的名称;

    (2)String lr.get_host_name( ):返回执行 Vuser 脚本的负载生成器的名称;

    (3)String lr.get_master_host_name ( ):返回运行Controller计算机的名称;

    (4)int lr.get_scenario_id( ): 返回当前方案的ID;

    (5)int lr.get_vuser_id( ) :返回当前 Vuser 的ID。

    3. 运行时函数(Run-Time Functions)

    (1)void lr.peek_events ( );:指示可以暂停Vuser 脚本的位置;

    (2)int lr.rendezvous( String rendezvous_name ):在 Vuser 脚本中设置集合点;

    (3)void lr.think_time( double time ):暂停脚本执行,模拟实际用户操作之间的思考时间。

    4. 字符串函数(String Functions)

    (1)String lr.eval_string ( String instring ):用当前值替换参数;

    (2)int lr.eval_int ( String name ):用整型值替换参数;

    (3)int lr.next_row ( String dat_file ):指示使用指定参数的下一行数据。

    5. 消息函数(Message Functions)

    (1)int lr.debug_message( int message_level, String message):向输出窗口发送测试过程的调试消息;

    (2)int lr.error_message ( String message ):向Vuser日志文件和输出窗口发送错误消息以及位置的详细信息;

    (3)int lr.log_message ( String message ):向 Vuser 日志文件发送消息;

    (4)int lr.message ( String message ):向输出窗口发送消息;

    (5)int lr.output_message ( String message ):向日志文件和输出窗口发送消息和位置信息;

    (6)int lr.vuser_status_message ( String message ):向Controller窗口中的“Vuser状态”区域发送消息。

  • (转)loadrunner中Lr_save_string()函数和Itoa()函数的使用

    2008-10-15 10:12:46

                Lr_save_string()函数和Itoa()函数的使用

     

    /*

    目的:使用for循环添加多条有规律的数据,比如说:a1a2a3......a1000

    方法:从上面看1-1000是一个有序序列,并且前面的a都是固定的,所以只需要用for循环将1-1000循环出来就可以了。

          但是loadrunner使用的是C语言的语法,所以不能向在java中一样,将两个变量直接相加(+)(+:连字符)

          所以这个时候就需要将首先将int变量转换成string,然后再用lr_save_string()函数将该变量用loadrunner可以识别的参数化方式保存起来,再应用到录制的脚本中就可以了

         

    函数简介:

          int itoa ( int value, char *str, int radix );

          函数目的:int类型转换成string

          参数介绍:value 要转换的int型的值

                     str 目标字符串,即将转换成的string值保存到str

                    radix:转换数字时所用的基数 10:十进制;2:二进制……

                   

          int lr_save_string (const char *param_value, const char *param_name);

          函数目的:param_value值保存到param_name变量中

          参数介绍:param_value:要保存的值

                    param_name 变量名称

     

    问题:为什么要用itoa()lr_save_string()两个函数相结合使用呢?

          因为lr_save_string()中的两个参数都是char类型的指针,int类型的值必须经过转换才能在lr_save_string()函数中使用,所以此处就要将itoa()lr_save_string()两个函数相结合使用。

    */

     

    Action()

    {

           int i;

           char str[100];   //定义一个数组用来保存int类型转换后的值

     

           for(i=0;i<=9;i++){

                  itoa(i,str,10);

                  lr_save_string(str,"ID");

                  lr_output_message("==str:=%s==ID:=%s====",str,lr_eval_string("{ID}"));

           }

     

     /*

    lr_save_string()将数组保存到变量中以后就可以应用到Loadrunner录制的脚本中了

    {ID}loardrunner识别参数的方式

     

        web_url("login",

                  "URL=http://server0.im.sonoro.cn:18001/login?username=a{ID}&password=test&autoLogin=false&1211433835878&1211433835878",

                  "TargetFrame=",

                  "Resource=0",

                  "RecContentType=text/html",

                  "Referer=http://server0.im.sonoro.cn:18001/proxy.html?1211433821547",

                  "Snapshot=t6.inf",

                  "Mode=HTML",

                  LAST);

     

    */

           return 0;

    }

  • (转)LoadRunner如何设置文本和网页图像的检查点

    2008-10-15 10:07:21

    通过 VuGen 可在网页上添加搜索文本字符串的检查。可以在录制期间或录制之后添加文本检查。

      在创建文本检查时,需要定义检查的名称、检查范围、要检查的文本和搜索条件。

      要在录制之后添加文本检查,请执行下列操作:
      1.在 VuGen 主窗口中,右键单击与要对其执行检查的网页相应的步骤。从弹出菜单中选择“在之后插入”。将打开“添加步骤”对话框。
      2.在“步骤类型”树中,展开“Web 检查”。
      3.选择“文本检查”,然后单击“确定”。将打开“文本检查属性”对话框。请确保“规格”选项卡可见。
      4.在“搜索”框中,键入要验证其存在与否的字符串。ABC 图标表示尚未为“搜索”框中的字符串分配参数。有关分配参数的详细信息,请参阅第 7 章“定义参数”。
      5.要相对于邻近文本指定搜索字符串的位置,请选中“其右侧”或“其左侧”复选框。然后,在适当的字段中键入文本。例如,要验证字符串support@mercuryinteractive.com是否出现在单词“e-mail:”的右侧,请选中“其右侧”,然后在“其右侧”框中键入“e-mail:”。ABC 图标表示尚未为“其右侧”或“其左侧”框中的字符串分配参数。
      6.命名文本检查。单击“常规”选项卡,然后在“步骤名”框中键入文本检查的名称。使用一个以后容易识别该检查的名称。
      7. 属性表显示其他用于定义检查的属性。清除“仅查看活动属性”复选框可以查看活动和非活动属性。要启用某个属性,请单击该属性名左侧的单元格。在“值”列中为属性分配一个值。有关分配属性值的详细信息,请参阅第 454 页的“定义其他属性”。
      8.单击“确定”接受设置。代表新文本检查的图标将被添加到脚本中的关联步骤中。在脚本视图中,“文本检查”图标显示为 web_find 函数。

      要在录制期间添加文本检查,请执行下列操作:
      1.使用鼠标标记所需的文本。
      2.单击录制工具栏上的“插入文本检查”图标。
      除了使用 web_find 函数外,还可以使用两个其他的增强函数来搜索 HTML 页内的文本:
      web_reg_find
      web_global_verification
      web_reg_find 函数是注册类型函数。它将注册对 HTML 页上的文本字符串进行的搜索。注册意味着它不会立即执行搜索 - 仅在执行下一个操作函数(如web_url)之后,才会执行检查。注意,如果正在使用并发函数组,则web_reg_find 函数仅在分组结束后才会执行。该函数与 web_find 函数的不同之处在于:它并不局限于基于 HTML 的脚本(请参见“录制选项” > “录制”选项卡)。该函数还具有其他属性(如实例)通过该属性可以确定文本出现的次数。在执行标准文本搜索时, web_reg_find是首选函数。

      通过 VuGen 可添加在网页上搜索图像的用户定义的检查。图像可以由 ALT 属性、SRC 属性或这两者来标识。可以在录制期间或录制之后添加用户定义的图像检查。录制之后,可以在脚本中编辑任何现有的图像检查。

      要添加图像检查,请执行下列操作:
      1.在 VuGen 主窗口中,右键单击与要对其执行检查的网页相应的步骤。从弹出菜单中选择“在之后插入”。将打开“添加步骤”对话框。
      2.在“步骤类型”树中,展开“Web 检查”。
      3.选择“图像检查”,然后单击“确定”。将打开“图像检查属性”对话框。请确保“规格”选项卡可见。
      4.选择一种标识图像的方法:
      a)要使用图像的 ALT 属性来标识图像,请选中“替换图像名(ALT 属性)”复选框,然后键入 ALT 属性。在运行脚本时, Vuser 将搜索具有指定的 ALT 属性的图像。
      b)要使用图像的 SRC 属性来标识图像,请选中“图像服务器文件名(SRC 属性)”复选框,然后键入 SRC 属性。在运行脚本时, Vuser 将搜索具有指定的 SRC属性的图像。ABC 图标表示尚未为 ALT 或 SRC 属性分配参数。
      5.要命名图像检查,请单击“常规”选项卡。在“步骤名”框中,键入图像检查的名称。使用一个以后容易识别该检查的名称。
      6.属性表显示其他用于定义检查的属性。清除“仅查看活动属性”复选框可以查看活动和非活动属性。要启用某个属性,请单击该属性名左侧的单元格。在“值”列中为属性分配一个值。有关分配属性值的详细信息,请参阅第 454 页的“定义其他属性”。
      7.单击“确定”以接受设置。代表新图像检查的图标将被添加到 Vuser 脚本中的关联步骤中。

      可以指定插入到 Vuser 脚本中的每个 Web 检查的其他属性。在检查属性对话框的“常规”选项卡上的属性表中设置其他属性。

  • (转)如何用QTP解决图片验证码(解析QuickTest文本识别机制)?

    2008-10-15 10:06:30

    本文出自songfun的51Testing软件测试博客,转载请保留出处及链接:http://www.51testing.com/?songfun51Testing软件测试网 lb(sdG/C-j*_
    51Testing软件测试网U+OAT%VHj8j
    大家在使用QTP进行自动化测试的过程中经常会遇到图片验证码的问题——大家所关心的就是如何解决此类问题。51Testing软件测试网S s)O @+m QJ E
    这里我们首先要去了解为什么会有图片验证码。其实验证码的本质作用就是防止有人利用工具(灌水机、注册机,当然也不小心包括了我们的自动化测试工具)恶意猜解登陆或者不停的注册和灌水的。因此如果我们完全寄希望于通过GUI识别来获取内容是不切实际的——先打好预防针,免得读者希望太大,失望更大,呵呵!
    Z3GZF4X0 下面说说验证码的解决思路:
    Gy'`1Jd{ OeT0 其实解决图片验证码的思路有很多,我这里主要结合QTP9.5的新特性给大家介绍其中一种解决方案,就是利用它的OCR机制抓取文本内容。51Testing软件测试网%a4Q S1\y'n#QP,hP X
    在QTP9.5中,对象识别能力有了进一步改善,其中针对文本识别方面进行了优化,引入了ABBYY公司的OCR解决方案——这个相关的功能体现在QTP菜单的“Tools-->Options-->General--Use text recognition mechanisms in this order”里,详细内容后面会有具体介绍。51Testing软件测试网7} O0imK?
    先来看看ABBYY是何许公司,登录他们的官方网站可以看到一段相关介绍:“ABBYY是世界OCR(光学字符识别)、ICR(手写体识别)和语言软件的领航者。ABBYY 致力于人工智能(AI)和语言软件开发。提供全套文档识别,转换和数据捕获技术的产品解决方案。”如果你使用过图像文档转换的软件,一定会听说过FineReader OCR Professional ,其实它就是ABBYY公司的产品,用官方的说法就是“将通过扫描仪、MFP 或数码相机生成的图像快速转换为可编辑和可搜索的电子格式,而且识别率很高”,说白了就是可以借助它先进的OCR机制“读”出图片里的文本内容,并转换为PDF之类的文档。
    S,h h} {)n(v i0 有了ABBYY这么强大的背后支持,QTP自然底气十足,那么QTP到底如何以OCR机制识别文本呢?我们首先先了解一下什么是OCR。
    C;p;C#{.j2ZE5T0 打开“百度百科_OCR”,它的说明:“OCR(Optical Character Recognition,光学字符识别),是属于图型识别(Pattern Recognition,PR)的一门学问。其目的就是要让计算机知道它到底看到了什么,尤其是文字资料。 由于OCR是一门与识别率拔河的技术,因此如何除错或利用辅助信息提高识别正确率,是OCR最重要的课题,ICR(Intelligent Character Recognition)的名词也因此而产生。而根据文字资料存在的媒体介质不同,及取得这些资料的方式不同,就衍生出各式各样、各种不同的应用。”这里有个关键词:“正确率”,也就是“识别率”——既然不能够总是100%,我们自然不可能完全寄希望于通过QTP能够每次100%正确的去识别图片里的文本。尤其是“道高一尺魔高一丈”的今天,验证码加入了大量的干扰素,如扭曲、变形、错位、随机背景花纹,给OCR识别增加了很多难度——本来就不希望被软件识别到嘛。
    .GIG)q"MQt:}C x0
    )s+j h*z$}(O0 本文出自songfun的51Testing软件测试博客,转载请保留出处及链接:http://www.51testing.com/?songfun51Testing软件测试网 i.WC| {1W2ut2Q
    51Testing软件测试网WN#`n'M1m
    MhAXF,A/J0 了解了OCR之后,我们再来看看QTP对应的这个设置。如前面所说,通过QTP菜单的“Tools-->Options”选中到“General--Use text recognition mechanisms in this order”,这里的四个选项就是对应的不同设置。我们看看帮助的描述(我做了翻译):51Testing软件测试网 Uz"\;Oa g/kh
    =================================51Testing软件测试网WZ4i"a9j,A|P&P
    使用文本识别机制
    sTP/dq0
    7blEu"v!\R0R0 指定QTP在采用 “文本”或者“文本区域” 的 检查点或输出值 的步骤时,捕获文本内容所使用的文本识别机制。
    !],H OBw[0 以下有三种识别方式:51Testing软件测试网'J W/RgZ1F*J
    1、先使用Windows API,再使用OCR(默认)。
    }2xU(l+?4^.n d._0     指示QTP首先尝试以基于Windows API的机制从对象上直接获取文本内容。如果未获取到文本(比如,文本属于图片的一部分),QTP就会使用OCR的机制尝试获取这段文本。51Testing软件测试网;D(Kc%_]*Y/C&R#e }|
        强烈建议在使用中日韩(象形文字)、英的语言环境下采用这个设置。51Testing软件测试网 EL+r(h omoF

    $Te;|V&teH$a0 2、先使用OCR,再使用Windows API。51Testing软件测试网X4E7}4lk4Z$w
        指示QTP首先尝试使用OCR机制从对象上去获取文本。如果未获取到文本,QTP就会以Windows API的机制去获取文本内容。51Testing软件测试网7V/F2q ['Vv0}Fc-w4a
    51Testing软件测试网(g M5zZ9T9a&K8Kh
    3、仅使用Windows API方式。51Testing软件测试网hoBS;Rab\ r$Q
        指示QTP仅采用基于Windows API的机制从对象上获取文本内容。51Testing软件测试网l)n Kf1Z%z

    PO!H[:X6H:k9Q X0 4、仅使用OCR的方式。51Testing软件测试网3a[e[GSy Cp
        指示QTP仅采用基于OCR的机制从对象上获取文本内容。51Testing软件测试网 QT6A M/w~ d:SZQ
        在使用Windows Vista要使用这种方式。
    0v?\+r&hj0
    gL1T5u,\kD0 =================================51Testing软件测试网)Ps%t;G%co(^:Lt}
    本文出自songfun的51Testing软件测试博客,转载请保留出处及链接:http://www.51testing.com/?songfun51Testing软件测试网k3t%f)d!GO Q]
    51Testing软件测试网WN#`n'M1m
    Bb4p,]pv FP0 上面的内容已经解释的很明确了,接下来我们通过TextArea Output Value看看效果。51Testing软件测试网D.sH.j Yt'd^#g

    HG6`O!_0 如下图所示,QTP针对几张图片的识别效果:51Testing软件测试网(@rB:F7kF
    (一)、内容是51Testing的,QTP获取正确;内容是51Testing的G风格彩字,QTP获取错误(显示为IC_CHECK_PATTERN)
    I6hY8m:P g-\K0 51Testing软件测试网 xt Ow'bd

    +bnq jEB+V`.g1D0
    q:Q D!eO4T^)q/e0 (二)、内容是songfun的普通文本,QTP获取正确;内容是songfun的G风格彩字,QTP获取错误(也显示为IC_CHECK_PATTERN)
    \+Q3F$q6G x:WV'U0
    'n$rb.zs"D8tTc%h0 51Testing软件测试网*C0NR"a"i#|R:hz
    51Testing软件测试网*g,EQ/gM'hx
    51Testing软件测试网&dfgDO/?Av;G
    有兴趣大家可以自己做一些图片,甚至可以用QQ的验证码图片来试验一下,看看OCR效果。
    ]~$d!X4D^ a G051Testing软件测试网a?#mt)u aH]-W
    本文出自songfun的51Testing软件测试博客,转载请保留出处及链接:http://www.51testing.com/?songfun
    e \.lI$r+L9B#l$Z051Testing软件测试网WN#`n'M1m51Testing软件测试网6W1R-V}go[p
  • (转)LoadRunner编程之文件的操作

    2008-10-15 09:44:11

    这篇文章主要写下LoadRunner下如何进行文件的操作。

    1,文件的声明

        LoadRunner不支持FILE数据类型,所以在LoadRunner中用int来声明一个文件:

         int MyFile;

    2,文件的打开

         fopen():返回一个FILE数据类型的指针.因为LoadRunner不支持FILE数据类型,所以返回值需要转化成int.

          int MyFile;

          MyFile=(int)fopen("C:\\temp\\loans.txt","w");

          fopen()函数的第一个参数是创建文件的路径.第二个参数指定了创建文件的模式.下面是常用的几种模式

    “w” -  , 当需要往文件中写的时候. 如果文件存在,就覆盖该文件,如果文件不存在,根据第一个参数来创建新文件. 

    “r” – , 需要从文件中读的时候. 这个文件必须已经存在.

    “a” – 附加, 当往文件末尾添加数据时用到.

    “rw” – 读和写.

    第一个参数中注意文件路径为"\\",因为"\"C语言中为转义字符.另外,如果文件和脚本在同一个目录中,文件的完整路径可以省略.

    3, 读文件

            fscanf():用来读文件。函数语法如下:

           int MyFile;

                int LoanNumber;

                MyFile = fopen(“C:\\temp\\loans.txt”,”r”);

                fscanf(MyFile,”%d”, &LoanNumber);

         需要注意的是:MyFile是个文件指针(在LoadRunner中并不是真正的指针),被用来代替实际的文件。所有文件的操作都是使用文件指针而不是文件名称。

         练习1

         先创建一个文件c:\temp\loans.txt,文件包含的内容为:

         11111

         22222

         33333

         44444

         55555

     循环读取并显示该文件中的每行数据,脚本如下:

    Action()

    {

            int MyFile;

            int LoanNumber,i;

            // Assigning the file path to a string

            char FileName[80] = "C:\\temp\\loans.txt";

     

     

            // Opening the file

            // Note the use of variable to replace the file path

            //

            MyFile = (int)fopen(FileName,"r");

     

     

            // Reading and printing one loan number at a time

            for(i=1;i<=5;i++)

                   {

                   fscanf(MyFile,"%d", &LoanNumber);

                   lr_output_message("Loan Number %d: %d",i,LoanNumber);

                   }

     

            fclose(MyFile);

     

            return 0;

    }

    当文件打开之后,文件指针在文件的最开始。每读一次,指针就移动到下一行,这就是为什么程序能自动读取下面元素的原因。

    a)  如果把循环改为fori=1i<=7;i++),会出现什么样的结果呢?

    会出现三个都是打印55555的结果,原因是文件指针移动到最后就不再移动了,但是有7次循环,那多出来的2次循环打印的数据仍然是最后一行的数据。

    b) 如果不知道该文件下包含数据的行数, 就无法用for循环。需要使用while循环。可以使用feof函数。feofMyFile)在文件指针没有到达返回文件末尾的时候返回0,如果到末尾返回非0值。这样可以修改程序的循环为:

           whilefeofMyFile== 0);

    注意:如果文件末尾有空行,feof也会把它最为文件的一部分。

    4,写文件

       fprintf():用来往文件写。语法如下:

                int MyFile;

             char Name[] = “John Doe”;

             MyFile = fopen(“C:\\temp\\loan.txt”,”w”);

                   fscanf(MyFile,”%s”,Name);

      第一个参数是文件指针,第二个参数是格式,第三个参数是指定格式对应的变量。

    Action()

    {

            int MyFile;

            char Name[] = "John Doe";

     

     

            MyFile = fopen("C:\\temp\\names.txt","w");

    // note that "w" is used to write

           

    fprintf(MyFile,"%s", Name);

    // note that we are printing a string here

  • 项目测试与产品测试

    2008-04-11 14:39:47

    在新的公司呆了快一个月了,前两周非常郁闷,因为这次跳槽是跨行业的,所以对新的业务不了解,又没有人可以比较清晰的讲解这些,又错过公司的业务培训,还要排测试计划,针对感觉是狗咬刺猬——无从下口。这两周通过不断的向别人请教,总算有些眉目了。还好下周也要开始近两周的培训了,如果连业务都不了解,还还真不知道怎么跟客户打交道。

    以前做的是产品的测试,产品是比较长期的,一个版本测试完成,下一个版本只是一些新功能的添加,所以对整体系统比较了解,而且当时的公司对于项目的文档是能省就省,我们也一直抱怨这个是构成项目里各类人员沟通不畅的主要原因。现在在新公司,对我来说,就是一个全新的业务,各类项目文档要求是很高的,必须的逐字逐句的分析,这样在文档中都有明确的责任划分,如果在后期项目失败,估计这些文档都是失败的证据,现在第一个项目的计划测试快整理出来了,被review的人修改了一些,看来以后文档方面严谨的能力还需要提高。

  • QTP日志实践的几点总结(转)

    2008-03-25 22:49:01

    背景:在日常使用QTP中,因为有QC的存在,导致了QTP的察看结果的功能并不是用的很顺手,所以笔者在脱离开QC的情况下,在工作实践中总结了QTP的日志实现的一些方法。
    1、生成txt文件。这是从开发那边得到的启示。
    首先定义一个sub:
    Public Sub WriteLineToFile(message)
    Const ForReading = 1, ForWriting = 2, ForAppending = 8
    Dim fileSystemObj, fileSpec
    Dim currentTime
    currentDate = Date
    currentTime = Time
    testName = "log"
    Set fileSystemObj = CreateObject("scrīpting.FileSystemObject")
    fileSpec ="C:\" &testName& ".txt" 'change this according to your directory
    If Not (fileSystemObj.FileExists(filespec)) Then  
    Set logFile = fileSystemObj.CreateTextFile(fileSpec, ForWriting, True)  
    logFile.WriteLine ("#######################################################################")  
    logFile.WriteLine (currentDate & currentTime & " Test: " & environment.Value("TestName") )  
    logFile.WriteLine ("#######################################################################")  
    logFile.Close  
    Set logFile = Nothing
    End If
    Set logFile = fileSystemObj.OpenTextFile(fileSpec, ForAppending, False, True)
    logFile.WriteLine (currentDate & currentTime & " " & message)
    logFile.Close
    Set logFile = Nothing
    Set fileSystemObj = Nothing
    End Sub        
    这样就能在txt中直接明了的看到自己的日志了。(个人感觉比看QTP的results好多了了,当然QTP自身的results还有错误图片等等,下面会介绍我的解决方案)

    题外话:在实际应用中,我会在sub中增加一个flag,来标志不同的严重等级,在不同的情况下控制输出不一样类型的日志。
    2、使用QTP自身的抓图功能
    Public Function capture_desktop()
    Dim datestamp
    Dim filename
    datestamp = Now()
    filename = Environment("TestName")&"_"&datestamp&".png"
    filename = Replace(filename,"/","")
    filename = Replace(filename,":","")
    filename = "C:\QTP_ScreenShots"&""&filename
    Desktop.CaptureBitmap filename
    Reporter.ReportEvent micFail,"image","<img src='" & filename & "'>"
    End Function
    该函数主要就是用到Desktop.CaptureBitmap的这个方法,把桌面的图片抓下来,这样比较自由的抓下任意时候桌面的图片,方便我们检查结果。

    题外话:可以通过Function的返回值和上面提到的方法结合在一起的话,效果会更好的。
    3、使用outlook发送邮件
    Public Sub SendEmail(testname,strsubject,stremailcontent,attachment,strrecipient)
    Set ōut = CreateObject("Outlook.Application")
    Set mapi = out.GetNameSpace("MAPI")
    Set email = out.CreateItem(0)
    email.Recipients.Add(strrecipient)
    email.Subject = strsubject
    email.Body = stremailcontent
    Set ōAttachment = email.Attachments.Add(attachment)
    email.Send
    Set ōutlook = Nothing
    Set mapi = Nothing
    End Sub

    题外话:假如我们把日志和抓图都结合在一起作为附件发出去的话,在自动化测试中后期会很有用,当然前提是不使用QC的情况下。

    4、这是一个针对上面第3点如何把抓图放在一个doc中。
    Set ōWord = CreateObject("Word.Application")
    oWord.DisplayAlerts = False
    oWord.Visible = False
    oWord.documents.open "testWordDoc.doc"
    Set ōDoc = oWord.ActiveDocument
    Set ōRange = oDoc.content
    oRange.ParagraphFormat.Alignment = 0
    oRange.insertafter vbcrlf '& " " & vbcrlf
    oRange.collapse(0)
    oRange.InlineShapes.AddPicture "ImagePath.bmp", False, True
    oWord.ActiveDocument.Save
    oWord.Application.Quit True
    Set ōRange = Nothing
    Set ōDoc = Nothing
    Set ōWord = Nothing
    当然QTP和excel,word结合的不错的,所以在测试中灵活运动,效果会很好的
  • QTP Excel函数

    2008-03-25 22:45:07


    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")
    ' *********************************************************************************************

    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

     

  • 我终于回来啦

    2008-02-25 16:38:32

    终于把新工作确定下来了,心里也算是放下了一块大石头。

    现在终于可以潜心的研究自动化测试了,虽然知道自动化测试没法完全替代手工,但是它的作用在回归测试中能节省很多的人力,是我一直看中的。去了新公司,主要的工作职责就是去做功能和性能自动化,虽然之前从未接触过性能测试,但是还是很有信心来努力挑战的。

    接下来除了希望技术方面有所提升以外,更希望能获得继续领导和管理的机会来提升我个人的综合能力。

  • QTP User-Defined Function 学习经验汇总[转]

    2008-01-30 15:31:15

    1. 可以通过Function Definition Generator方便的定制自定义函数(Function)
    2. Built-in Function优先级高于User-Defined Function。因此若存在同名的话,QTP会优先调用内置的Function
    3. 通过RegisterUserFunc可以将自定义的函数注册为特定对象的方法,甚至可以覆盖原有对象的方法(Method)。通过UnRegisterUserFunc取消注册
    注册方式:RegisterUserFunc TOClass, MethodName, FunctionName, True
    反注册方式:UnRegisterUserFunc TOClass, MethodName
    4. 定义在Action中的Function以及注册的Method只能在当前Action中使用,若需要供全局使用则定义到Function Library中
    5. 如果Method在Action中注册并且被其他Action调用时,该Method定义也适用于调用Action(Calling Action)。但如果Function定义在被调用Action中(Called Action),则Calling Action会因为找不到Function定义而失败。这种情况的话,需要将Function 定义在Function Library中
    6. QTP在测试执行前会清除所有的Method Register
    7. 默认情况下,User-Defined Function的运行结果不会出现在Test Result中,可以自己用Reporter.ReportEvent添加log
    8. QTP在打开Test时加载了关联的Function Library,因此,若其他人或者你用其他编辑器修改了对应的Function Library,只有在QTP重新打开该Test后才生效
    9. QTP搜索Function的顺序是先Test在Function Library。另外,同名的Function存在于多个Function Library时,后一个被使用
    10. 对于同一个Method先后注册了两个不同的Function,后面的Method注册会覆盖前面的。当用UnRegisterUserFunc反注册时,会将该Method返回到原始状态,而不会回到前一个注册
    11. 在某Action中使用ExecuteFile后,该Function只能在当前Action中使用
    12. 对于存储在QC中的外部资源,如Function Library,QTP打开时为其创建了一个本地副本。因此若其他人修改了QC上的外部资源,或你使用其他编辑器进行修改时,该修改只有在QTP重新打开该Test才生效。但对于存储在本地的外部资源,不存在该问题
    13. 在Test Settings中设置了Default Function Library列表后,新建Test时这些Library即被集成到新创建的Test中。以后对Default Function Library列表的修改对已有Test不产生任何影响。
  • QTP自动化测试流程

    2008-01-29 20:16:10

    黑色字体是原文,蓝色字体是我的注释,代表我个人的看法,仅供参考。

    1)准备TestCase
            - 在进行自动化之前,将
    测试内容进行文档化,不建议直接录制脚本
            - 在录制脚本之前设计好脚本,便于录制过程的流畅
            - 由于
    测试用例设计和脚本开发可能不是同一个人完成,便于团队合作
            - 便于后期的维护
            - 文档化的方式:TD或者文档

    Test Case的建立是所有脚本成立的先觉条件,所以在正式开始编写脚本前,必须确保:
            - Case覆盖率高(需求覆盖、代码覆盖等)
            - Case书写步骤清晰,便于脚本与之一一对应
            - Case期望结果明了,便于脚本对期望结果进行检查
            - Case经过开发、测试Review,保证产品所有主要人员对产品及测试达成同一认识
            - 针对不同测试阶段,挑选在回归测试中需要自动化实现的Case(实属脚本计划阶段)

     
    2)配置QTP
            QTP支持不同的开发环境,在正式录制之前,需要根据被测程序的开发环境,选择合适的Add-In,并进行加载。

    做到以下几点会对后期的脚本维护产生莫大的方便:
            - 建立统一的脚本架构
            -
    共享资源的建立(对象库、测试数据等等)
            - 共用Function Library的建立
            - 建立统一的代码规范(含命名规范、注释、代码缩进、位图检查等)
            - 统一所有的编码风格
            - 统一配置测试环境,确保所有测试环境均能运行所写脚本

    3)录制脚本
            启动QTP的录制功能,按照Test Case的操作步骤描述执行,QTP自动记录每一步操作,并自动生成VBscrīpt脚本。

    除必要的位图检查之外,严格要求脚本必须使用手写,防止脚本录制导致代码臃肿以及可读性差。
     
    4)修改增强脚本
            刚刚录制好的脚本可能包含错误,或者没有达到预期的目的,这就需要在录制脚本的基础上,进行修改增强
            - 删除录制过程中多余的以及错误的操作,以最少的脚本完成任务
            - 如果前面操作的输出是后面操作的输入,则需要使用变量或者输出值来进行替换
            - 不是所有的操作都可以通过录制产生的,有些需要通过手工编码实现这些功能
            - 录制产生的脚本是线性的,可以加入条件、循环控制语句,实现更复杂的流程
            - 对脚本进行结构化
            - 加入注释,便于阅读和维护
     
    5)调试脚本
            - 回放通过的脚本,不一定是正确的,也可能会包含错误
            - 在测试脚本正式使用之前,要保证其本身的正确性
            - 避免测试脚本故障和被测程序故障搅在一起,不容易定位

    脚本调试完成后,需要完成如下几步才能真正的用在实际项目当中:
            - 单个脚本调试成功后,需要其他人员Review(类似极限编程)后方可Checkin代码
            - 把所有单独运行成功的脚本集合在一起,进行脚本的集成测试和系统测试

    6)回放脚本
            - 对于回放的错误,不要急于马上提交Bug,首先要判断是脚本本身的错误还是程序的错误,确认后再提交。
     
    7)脚本维护
            - 随着工作的不断推进,脚本量会越来越多
            - 被测试程序的不断更新,也需要更新相应的测试脚本
            - 采用版本管理工具保存脚本,如CVS、VSS,可以随时获取历史版本
            - 采用统一的脚本架构
            - 采用统一的命名规范
            - 添加充分的注释,避免时间久了,自己都不能马上读懂脚本

    如果前期工作做的好,脚本维护的成本会低出很多,所以强烈建议在前期能够形成统一的制度。

  • 如何解决返回数据库查询纪录条数(转)

    2008-01-29 19:37:21

    方法一
    Set   oRs   =   Server.CreateObject("ADODB.RecordSet")   
      oRs.Open   sSql,   oConn,   1,   1   
      来读数据.
    仅检索数据:rs.open   SQL,conn,1   
      更新数据:rs.open   SQL,conn,2,2,1

    方法二   
    用Select   Count(*)   As   RecordCount   From   [table]   
      oRs("RecordCount")来获取   
    方法三
    用Do   While   Not   oRs.Eof   
      RecordCount   =   RecordCount   +   1   
      Loop


    方法一原理如下:
    通常人们使用以下两种方法来执行SQL语句:     
      Set   Rs=Conn.Execute(SqlStr)     
      和     
      Set   Rs=Server.CreateObject(“ADODB.RecordSet“)     
      Rs.Open   SqlStr,Conn,CursorType,LockType     
       
      (RecordSet对象方法请看这里)     
       
       
      由于默认的记录集游标是服务器游标,     
      Rs.CursorLocation   =   adUseServer     
      所以返回Rs.RecordCount=-1,     
      应该把服务器游标改为客户端游标,     
      Rs.CursorLocation   =   adUseClient     
      Rs.Open   SqlStr,Conn,CursorType,LockType     
       
      rs.cursortype     
       
      光标类型   recordcount   属性     
      ---------------------------------------------     
      ForwardOnly   0(默认)   返回-1     
      Keyset   1   正确的记录数     
      Dynamic   2   -1或不正确的记录数,依数据源而定     
      Static   3   正确的记录数
  • Scripting Techniques (转)

    2008-01-29 18:29:42

    Adding Elements to a Dictionary


    Demonstration scrīpt that adds three key-item pairs to a scrīpt Runtime Dictionary. scrīpt must be run on the local computer.
    Set ōbjDictionary = CreateObject("scrīpting.Dictionary")
    objDictionary.Add "Printer 1", "Printing"   
    objDictionary.Add "Printer 2", "Offline"
    objDictionary.Add "Printer 3", "Printing"

    Creating an Instance of Internet Explorer


    Demonstration scrīpt that creates an instance of Internet Explorer, opened to a blank page.
    Set ōbjExplorer = Wscrīpt.CreateObject("InternetExplorer.Application")
    objExplorer.Navigate "about:blank"   
    objExplorer.ToolBar = 0
    objExplorer.StatusBar = 0
    objExplorer.Width=300
    objExplorer.Height = 150 
    objExplorer.Left = 0
    objExplorer.Top = 0
    objExplorer.Visible = 1

    Creating scrīpt Documentation Using scrīpt Comments


    Demonstrates the use of the FileSystemObject as a way to copy comments from a scrīpt to a separate text file. Requires comments to have been marked using '*.
    Const ForReading = 1
    Const ForWriting = 2
    Set ōbjFSO = CreateObject("scrīpting.FileSystemObject")
    Set ōbjscrīptFile = objFSO.OpenTextFile("c:\scrīpts\Service_Monitor.vbs", _
        ForReading)
    Set ōbjCommentFile = objFSO.OpenTextFile("c:\scrīpts\Comments.txt", _ 
        ForWriting, TRUE)
    Do While objscrīptFile.AtEndOfStream <> TRUE
        strCurrentLine = objscrīptFile.ReadLine
        intIsComment = Instr(1,strCurrentLine,"'*")
        If intIsComment > 0 Then
            objCommentFile.Write strCurrentLine & VbCrLf
        End If
    Loop
    objscrīptFile.Close
    objCommentFile.Close

    Determining the Number of Items in a Dictionary


    Demonstration scrīpt that counts the number of key-item pairs in a scrīpt Runtime Dictionary. scrīpt must be run on the local computer.
    Set ōbjDictionary = CreateObject("scrīpting.Dictionary")
    objDictionary.Add "Printer 1", "Printing"   
    objDictionary.Add "Printer 2", "Offline"
    objDictionary.Add "Printer 3", "Printing"
    Wscrīpt.Echo objDictionary.Count

    Displaying Real Time Events in a Command Window


    Creates a temporary event consumer that monitors the event log for error events. When an error event occurs, the scrīpt displays the event information in the command window.
    strComputer = "."
    Set ōbjWMIService = GetObject("winmgmts:" _
        & "{impersonationLevel=impersonate,(Security)}!\\" & _
            strComputer & "\root\cimv2")
    Set colMonitoredEvents = objWMIService.ExecNotificationQuery _
        ("Select * from __InstanceCreationEvent within 5 where TargetInstance isa " _
            & "'Win32_NTLogEvent' and TargetInstance.EventType = '1'")
    Do
        Set ōbjLatestEvent = colMonitoredEvents.NextEvent
            Wscrīpt.Echo "Record No.: " & _
                objLatestEvent.TargetInstance.RecordNumber
            Wscrīpt.Echo "Event ID: " & objLatestEvent.TargetInstance.EventCode
            Wscrīpt.Echo "Time: " & objLatestEvent.TargetInstance.TimeWritten
            Wscrīpt.Echo "Source: " & objLatestEvent.TargetInstance.SourceName
            Wscrīpt.Echo "Category: " & _
                objLatestEvent.TargetInstance.CategoryString
            Wscrīpt.Echo "Event Type: " & objLatestEvent.TargetInstance.Type
            Wscrīpt.Echo "Computer: " & _
                objLatestEvent.TargetInstance.ComputerName
            Wscrīpt.Echo "User: " & objLatestEvent.TargetInstance.User
            Wscrīpt.echo "Text: " & objLatestEvent.TargetInstance.Message
    Loop

    Displaying Tabular Output in a Command Window


    Retrieves service data from a computer, and then outputs that data in tabular format in a command window.
    Set colServices = GetObject("winmgmts:"). _
        ExecQuery("Select * from Win32_Service")
    For Each objService in colServices
        intPadding = 50 - Len(objService.DisplayName)
        intPadding2 = 17 - Len(objService.StartMode)
        strDisplayName = objService.DisplayName & Space(intPadding)
        strStartMode = objService.StartMode & Space(intPadding2)
        Wscrīpt.Echo strDisplayName & strStartMode & objService.State 
    Next

    Masking Command Line Passwords


    Demonstration scrīpt that uses scrīptPW.dll to mask passwords entered at the command line.
    Set ōbjPassword = CreateObject("scrīptPW.Password") 
    Wscrīpt.StdOut.Write "Please enter your password:" 
    strPassword = objPassword.GetPassword() 
    Wscrīpt.Echo
    Wscrīpt.Echo "Your password is: " & strPassword

    Masking Passwords Using Internet Explorer


    Demonstration scrīpt that creates an instance of Internet Explorer, and retrieves a password typed into a password-style text box. Requires a Web page named password.htm with the appropriate text box.
    Set ōbjExplorer = Wscrīpt.CreateObject _
        ("InternetExplorer.Application", "IE_")
    objExplorer.Navigate "file:///c:\scrīpts\password.htm"   
    objExplorer.Visible = 1             
    objExplorer.ToolBar = 0
    objExplorer.StatusBar = 0
    objExplorer.Width=400
    objExplorer.Height = 250 
    objExplorer.Left = 0
    objExplorer.Top = 0
    Do While (objExplorer.Document.Body.All.OKClicked.Value = "")
        Wscrīpt.Sleep 250                 
    Loop 
    strPassword = objExplorer.Document.Body.All.PasswordBox.Value
    objExplorer.Quit
    Wscrīpt.Sleep 250
    Wscrīpt.Echo strPassword

    Removing All Elements from a Dictionary


    Demonstration scrīpt that deletes all the key-item pairs from a scrīpt Runtime Dictionary. scrīpt must be run on the local computer.
    Set ōbjDictionary = CreateObject("scrīpting.Dictionary")
    objDictionary.Add "Printer 1", "Printing"   
    objDictionary.Add "Printer 2", "Offline"
    objDictionary.Add "Printer 3", "Printing"
    colKeys = objDictionary.Keys
    Wscrīpt.Echo "First run: "
    For Each strKey in colKeys
        Wscrīpt.Echo strKey
    Next
    objDictionary.RemoveAll
    colKeys = objDictionary.Keys
    Wscrīpt.Echo VbCrLf & "Second run: "
    For Each strKey in colKeys
        Wscrīpt.Echo strKey
    Next

    Removing Debugging Comments


    Demonstrates the use of the FileSystemObject as a way to remove debugging comments from a scrīpt. Requires comments to have been marked as '* BUG.
    Const ForReading = 1
    Const ForWriting = 2
    Set ōbjFSO = CreateObject("scrīpting.FileSystemObject")
    Set ōbjTextFile = objFSO.OpenTextFile("C:\scrīpts\CreateUser.vbs", ForReading)
     
    Do While objTextFile.AtEndOfStream <> true
        strNextLine = objTextFile.Readline
        intCheckForBugComment = Instr(strNextLine, "'* BUG")
        If intCheckForBugComment = 0 Then
            strSavedLines = strSavedLines & strNextLine & VbCrLf
        End If
    Loop
     
    Set ōbjTextFile = objFSO.OpenTextFile _
        ("c:\scrīpts\CreateUser.vbs ", ForWriting)
    objTextFile.Write strSavedLines 
    objTextFile.Close

    Removing One Element from a Dictionary


    Demonstration scrīpt that deletes a specific key-item pair from a scrīpt Runtime Dictionary. scrīpt must be run on the local computer.
    Set ōbjDictionary = CreateObject("scrīpting.Dictionary")
    objDictionary.Add "Printer 1", "Printing"   
    objDictionary.Add "Printer 2", "Offline"
    objDictionary.Add "Printer 3", "Printing"
    colKeys = objDictionary.Keys
    Wscrīpt.Echo "First run: "
     
    For Each strKey in colKeys
        Wscrīpt.Echo strKey
    Next
     
    objDictionary.Remove("Printer 2")
    colKeys = objDictionary.Keys
    Wscrīpt.Echo VbCrLf & "Second run: "
     
    For Each strKey in colKeys
        Wscrīpt.Echo strKey
    Next

    Retrieving Command Line Arguments from an Active Directory Container


    Demonstration scrīpt that retrieves the names of all the computers in an Active Directory container, and then returns service information from each of those computers.
    Set ōbjDictionary = CreateObject("scrīpting.Dictionary")
    i = 0
    Set ōbjOU = GetObject("LDAP://CN=Computers, DC=fabrikam, DC=com")
    objOU.Filter = Array("Computer")
    For Each objComputer in objOU 
        objDictionary.Add i, objComputer.CN
        i = i + 1
    Next
    For Each objItem in objDictionary
        Set colServices = GetObject("winmgmts://" & _
            objDictionary.Item(objItem) _
                & "").ExecQuery("Select * from Win32_Service")
        Wscrīpt.Echo colServices.Count
    Next

    Retrieving Command Line Arguments from a Text File


    Demonstration scrīpt that opens a hypothetical text file consisting of server names, then retrieves service information from each on the servers in the file.
    Const ForReading = 1
    Set ōbjDictionary = CreateObject("scrīpting.Dictionary")
    Set ōbjFSO = CreateObject("scrīpting.FileSystemObject")
    Set ōbjTextFile = objFSO.OpenTextFile("c:\scrīpts\servers.txt", ForReading)
    i = 0
    Do Until objTextFile.AtEndOfStream 
        strNextLine = objTextFile.Readline
        objDictionary.Add i, strNextLine
        i = i + 1
    Loop
    For Each objItem in objDictionary
        Set colServices = GetObject("winmgmts://" & _
            objDictionary.Item(objItem) _
                & "").ExecQuery("Select * from Win32_Service")
        Wscrīpt.Echo colServices.Count
    Next

    Retrieving a Web Page


    Retrieves the HTML source for the Web page http://www.microsoft.com. This scrīpt contributed by Maxim Stepin of Microsoft.
    url="http://www.microsoft.com"
    Set ōbjHTTP = CreateObject("MSXML2.XMLHTTP")
    Call objHTTP.Open("GET", url, FALSE)
    objHTTP.Send
    Wscrīpt.Echo(objHTTP.ResponseText)

    Saving Data in XML Format


    Demonstration scrīpt that retrieves service information for a computer, and then saves that data as an XML file.
    Const ForAppending = 2
    Set ōbjFSO = CreateObject("scrīpting.FileSystemObject")
    Set ōbjTextFile = objFSO.OpenTextFile _
        ("c:\scrīpts\service_status.xml", ForAppending, True)
    objTextFile.WriteLine ""
    objTextFile.Write ""
    objTextFile.WriteLine ""
    strComputer = "."
    Set colServices = GetObject("winmgmts:" _
        & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2"). _
            ExecQuery("Select * from Win32_Service")
    For Each objService in colServices    
        objTextFile.WriteLine ""
        objTextFile.WriteLine ""
        objTextFile.WriteLine objService.DisplayName
        objTextFile.WriteLine ""
        objTextFile.WriteLine ""
        objTextFile.WriteLine objService.State
        objTextFile.WriteLine ""
        objTextFile.WriteLine ""
    Next
    objTextFile.WriteLine ""
    objTextFile.Close

    Sorting WMI Data


    Demonstration scrīpt showing how WMI data can be sorted using a disconnected recordset (by itself, WMI does not allow you to specify a sort order for returned data). In this scrīpt, service information is retrieved using WMI and is stored in a disconnected recordset, a recordset that is not tied to a physical data source. The Sort method is then used to sort the service data by service state rather than by service name.
    Const adVarChar = 200
    Const MaxCharacters = 255
     
    Set DataList = CreateObject("ADOR.Recordset")
    DataList.Fields.Append "ServiceName", adVarChar, MaxCharacters
    DataList.Fields.Append "ServiceState", adVarChar, MaxCharacters
    DataList.Open
     
    strComputer = "."
    Set ōbjWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    Set ServiceList = objWMIService.ExecQuery _
        ("Select * from Win32_Service")
     
    For Each Service in ServiceList
        DataList.AddNew
        DataList("ServiceName") = Service.Name
        DataList("ServiceState") = Service.State
        DataList.Update
    Next
     
    DataList.Sort = "ServiceState"
    DataList.MoveFirst
     
    Do Until DataList.EOF
        Wscrīpt.Echo DataList.Fields.Item("ServiceName") _
            & vbTab & DataList.Fields.Item("ServiceState")
        DataList.MoveNext
    Loop

    Suppressing Multiple Event Notifications


    Issues an alert if available space on a disk drive falls below 100 megabytes. Will wait one hour before issuing the next alert.
    dtmStartTime = Now
    strComputer = "."
    Set ōbjWMIService = GetObject("winmgmts:" _
        & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
    Set ōbjDiskDrives = objWMIService.ExecQuery _
        ("Select * from Win32_LogicalDisk")
    For Each objDrive in objDiskDrives
        If objDrive.FreeSpace < 10000000 Then
            Wscrīpt.Echo "Drive is low on disk space."
        End If
    Next
    Do
    Set ōbjDiskDrives = objWMIService.ExecQuery _
        ("Select * from Win32_LogicalDisk")
    For Each objDrive in objDiskDrives
        If objDrive.FreeSpace < 10000000 Then
            intElapsedHours = DateDiff("h", dtmStartTime, Now)
                If intElapsedHours >= 1 Then
                    Wscrīpt.Echo "Drive is low on disk space." 
                dtmStartTime = Now
            End If  
        End If
    Next
    Wscrīpt.Sleep 1000
    Loop

    Tracking scrīpt Progress in a Command Window


    Demonstrates the use of StdOut as a method for indicating the progress being made by a scrīpt.
    Wscrīpt.Echo "Processing information. This might take several minutes."
    strComputer = "."
    Set colServices = GetObject("winmgmts:" _
        & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2"). _
        ExecQuery("Select * from Win32_Service")
    For Each objService in colServices
        Wscrīpt.StdOut.Write(".")
    Next
    Wscrīpt.StdOut.WriteLine
    Wscrīpt.Echo "Service information processed."

    Tracking scrīpt Progress Using Internet Explorer


    Demonstrates how to use Internet Explorer as a method for indicating the progress being made by a scrīpt.
    Set ōbjExplorer = Wscrīpt.CreateObject("InternetExplorer.Application")
    objExplorer.Navigate "about:blank"   
    objExplorer.ToolBar = 0
    objExplorer.StatusBar = 0
    objExplorer.Width=400
    objExplorer.Height = 200 
    objExplorer.Left = 0
    objExplorer.Top = 0
    Do While (objExplorer.Busy)
        Wscrīpt.Sleep 200
    Loop    
    objExplorer.Visible = 1             
    objExplorer.Document.Body.InnerHTML = "Retrieving service information. " _
        & "This might take several minutes to complete."
    strComputer = "."
    Set colServices = GetObject("winmgmts: \\" & strComputer & "\root\cimv2"). _
        ExecQuery("Select * from Win32_Service")
    For Each objService in colServices
        Wscrīpt.Sleep 200
    Next
    objExplorer.Document.Body.InnerHTML = "Service information retrieved."
    Wscrīpt.Sleep 3000
    Wscrīpt.Quit

    Using a Text File as a Command Line Argument


    Demonstration scrīpt that allows you to drag a text file (consisting of server names) onto the scrīpt icon in Windows Explorer. The scrīpt then opens the text file, then retrieves service information from each on the servers in the file.
    Set ōbjArgs = Wscrīpt.Arguments
    Const ForReading = 1
    Set ōbjDictionary = CreateObject("scrīpting.Dictionary")
    Set ōbjFSO = CreateObject("scrīpting.FileSystemObject")
    Set ōbjTextFile = objFSO.OpenTextFile(objArgs(0), ForReading)
    i = 0
     
    Do While objTextFile.AtEndOfStream <> True
      strNextLine = objTextFile.Readline
      objDictionary.Add i, strNextLine
      i = i + 1
    Loop
     
    For Each objItem in objDictionary
      Set colServices = GetObject("winmgmts://" & objDictionary.Item(objItem) _
          & "").ExecQuery("Select * from Win32_Service")
      Wscrīpt.Echo colServices.Count
    Next

    Verifying the Existence of a Dictionary Key


    Demonstration scrīpt that verifies the existence of a particular key within a scrīpt Runtime Dictionary. scrīpt must be run on the local computer.
    Set ōbjDictionary = CreateObject("scrīpting.Dictionary")
    objDictionary.Add "Printer 1", "Printing"   
    objDictionary.Add "Printer 2", "Offline"
    objDictionary.Add "Printer 3", "Printing"
    If objDictionary.Exists("Printer 4") Then
        Wscrīpt.Echo "Printer 4 is in the Dictionary."
    Else
        Wscrīpt.Echo "Printer 4 is not in the Dictionary."
    End If
  • QTP调用.NET类库(转)

    2008-01-29 17:14:25

      QTP9.2这个版本提供了调用.net框架的功能,使用DotNetFactory对象就可以实现。QTP的帮助文档里面提供了一个例子:
     
    Set var_CreateInstance = DotNetFactory.CreateInstance("System.Windows.Forms.Form", "System.Windows.Forms")

    var_CreateInstance.Show
     
      下面说一下如何用DotNetFactory调用自己开发的.net类库。
     
      首先用Visual Studio 2003或者2005创建一个新项目:类库,用的是C#。新建一个类,假设命名空间是Test.myTest,类名是QTPTest。我们再新建一个公共方法: public string DoAction()
     
      假设编译后产生的文件是d:\mtTest.dll。下面在QTP里面写脚本:
     
    Set ōbj = DotNetFactory.CreateInstance("Test.myTest.QTPTest", "d:\mtTest.dll")
     
    obj.DoAction
     
      这样就可以在QTP中使用.net类库了,我们可以借助于.net框架的强大功能,把很多测试脚本需要使用的公用功能(比如测试数据准备),用C#实现,然后在QTP中调用,让QTP脚本更强大。

     

  • Send Email through VBS

    2008-01-29 15:20:54

    脚本资源来自微软脚本库:

    Set ōbjEmail = CreateObject("CDO.Message")

    objEmail.From = "monitor1@fabrikam.com"
    objEmail.To = "admin1@fabrikam.com"
    objEmail.Subject = "Atl-dc-01 down"
    objEmail.Textbody = "Atl-dc-01 is no longer accessible over the network."
    objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
    objEmail.Configuration.Fields.Item    ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "STMP'Server
    objEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25  ' Port
    objEmail.Configuration.Fields.Update

    objEmail.Send

321/212>
Open Toolbar