发布新日志

  • qtp一个比较综合的使用[原创]

    2007-06-21 17:03:05

        个人写的第2个还算实用的QTP脚本,学习QTP第5天开始觉得有点难了。还好我只是客串测试。
    [功能]
        1.启动一个VB的windows application。设置好Excel文件和QTP的安装路径。
        2.启动脚本进行测试,测试代码是QTP自带的订票系统。

    [脚本的参数设定]
        脚本中有2个参数-EXCEL文件和QTP安装路径从VBS文件传入。在QTP中设定如下:
        1.在KeyWord view界面。在Action1上点击右键,选Action properties,弹出 Action properties对话框。在其中添加2个入参。如下图所示:
        
       

       2.设置测试参数
        Test->Test Settings->Parameters.设置2个入参。如下图所示:
       

      3.将Action参数和Test参数关联起来
         1.在KeyWord view界面。在Action1上点击右键,选择Action Call properties
       

        点Vaiue
       
        在脚本中使用以下语句可以取得2个入参:
        filename= Parameter("InAction1")
        QtpPath= Parameter("InAction2")
    [脚本部分]
    Dim conn,rst,filename,coboname
    Dim user,passwd
    'filename="C:\DATA.xls"
    filename= Parameter("InAction1")
    QtpPath= Parameter("InAction2")
    'datatale.import(filename)
    Set conn= createobject("ADODB.Connection")
    'msgbox filename
    conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Persist Security Info=False;Data Source="&filename&";Extended Properties='Excel 8.0;hdr=yes'"
    Set rst= createobject("ADODB.Recordset")

    '  Excelファイルのデータを読み込む
    rst.Open "select  *   from [sheet1$] " ,conn,1,1

    ' table WHCT0717のデータをセットする
     While Not rst.EOF 
       systemutil.run  QtpPath&"\samples\flight\app\flight4a.exe",""
        user = rst.fields("user")
     passwd = rst.fields("password")
     Dialog("ログイン").WinEdit("代理店名:").Set  (user)
       ' Dialog("ログイン").WinEdit("代理店名:").Type  micTab
     Dialog("ログイン").WinEdit("パスワード:").set(passwd)
     Dialog("ログイン").WinButton("OK").Click
     reporter.filter=0
     If ( Dialog("ログイン").Dialog("フライト予約").WinButton("OK").Exist(2) )  Then
        text = Dialog("ログイン").Dialog("フライト予約").GetVisibleText
     reporter.ReportEvent micFail ,"Load Error",text
      Dialog("ログイン").Dialog("フライト予約").WinButton("OK").Click
      Dialog("ログイン").WinButton("キャンセル").Click
     else
       Window("フライト予約").close
     end if
         rst.MoveNext
       Wend
     rst.close

       脚本部分最主要的是注意QTP对象的选择和使用。(Tools-->object Repository 对象的添加和删除)

    [VB application]
         以下是Button1单击的触发事件
         Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim qtApp
            Dim qtTest 
            Dim qtResultsOpt
            Dim pDefColl, pDef, rtParams, rtParam1, rtParam2
            Dim QtpTestPath
            qtApp = CreateObject("QuickTest.Application") 
            qtApp.Launch()
            qtApp.Visible = True '使得QTP的程序可见


            ' 设置运行属性
            QtpTestPath = QtpPath.Text & "\Tests\Test3" '设置脚本路径
            qtApp.Options.Run.RunMode = "Fast"
            qtApp.Open(QtpTestPath, True) ' Open the test in read-only mode

            ' set run settings for the test
            qtTest = qtApp.Test
            qtTest.Settings.Run.OnError = "NextStep" 
            qtResultsOpt = CreateObject("QuickTest.RunResultsOptions") 
            qtResultsOpt.ResultsLocation = "D:\program files\Mercury Interactive\QuickTest Professional\Tests\Test3" ' 设置放结果的地方

            pDefColl = qtApp.Test.ParameterDefinitions
            Dim cnt = pDefColl.Count
            Dim Indx = 1
            While Indx <= cnt
                pDef = pDefColl.Item(Indx)
                Indx = Indx + 1
            End While
            rtParams = pDefColl.GetParameters()
            rtParam1 = rtParams.Item("InParameter1")
            rtParam1.Value = DataFileName.Text
            ' MsgBox(TextBox1.Text)
            rtParam2 = rtParams.Item("InParameter2")
            rtParam2.Value = QtpPath.Text

            qtTest.Run(, True, rtParams) ' Run the test
            'MsgBox(rtParams.Item("OutParameter1").Value)

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

        End Sub

         以上几个部分虽然不是很多,然因为刚刚开始接触QTP,所以花了我近一天时间。主要是改成手动处理后
    对象的取得和逻辑判断的问题比较多,花了不少时间。希望对大家有用。

  • qtp和DB EXCEL TXT

    2007-06-21 14:54:31

       最近开始学习QTP的使用,结合有关资料,有了自己第一个脚本。
    [功能]
       1.从EXCEL文件读入数据,存入数据库的2张表中
       2.调用外部程序实现数据库的操作,结果存入第3张表中
       3.读出第3张表的数据和EXCEL文件预计结果作比较
       4.将测试结果写入txt文件,使用report功能在result中报错

    [代码]
       公司的电脑是日文操作系统,所以注释是日文。大家不看也罢。

    Dim conn,rst,filename,coboname
    Dim REPORT_ID,REPORT_SUB_ID,IDX
    Dim USER_CD,TF_UFIT_TORI_FLG

    set cnn=createobject("adodb.connection")
    set ōbjrsa=createobject("adodb.recordset")
    cnn.open "provide=msdaora;userid=panqy;password=8823;data source=panqy"
    filename="E:\DATA.xls"
    Set conn= createobject("ADODB.Connection")


    conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Persist Security Info=False;Data Source="&filename&";Extended Properties='Excel 8.0;hdr=yes'"
    Set rst= createobject("ADODB.Recordset")

    '  Excelファイルのデータを読み込む
    rst.Open "select  *   from [WHCT0717$] " ,conn,1,1
    result = rst.RecordCount
    msgbox "RecordCount = "&result

    ' table WHCT0717のデータをセットする
    While Not rst.EOF 
     ' IDX = rst.fields("IDX")
      REPORT_ID = rst.fields("REPORT_ID")
      REPORT_SUB_ID = rst.fields("REPORT_SUB_ID")
      objrsa.open "insert  into  WHCT0717 (REPORT_ID,REPORT_SUB_ID) values ('"&REPORT_ID&"','"&REPORT_SUB_ID&"') ",cnn,3,2
     ' msgbox "Data="&REPORT_ID
          rst.MoveNext
       Wend
      
    rst.close

    '  Excelファイルのデータを読み込む
    rst.Open"select  *   from [WHBT010Q$] " ,conn,1,1
    result = rst.RecordCount
    msgbox "RecordCount = "&result

    ' table  WHBT010Qのデータをセットする
    While Not rst.EOF 
     ' IDX = rst.fields("IDX")
      USER_CD = rst.fields("USER_CD")
      TF_UFIT_TORI_FLG = rst.fields("TF_UFIT_TORI_FLG")
      objrsa.open "insert  into  WHBT010Q ( USER_CD, TF_UFIT_TORI_FLG) values ('"&USER_CD&"','"&TF_UFIT_TORI_FLG&"') ",cnn,3,2
     ' msgbox "Data="&REPORT_ID
          rst.MoveNext
       Wend
     
    rst.close

    'batファイルを行う
    coboname = "E:\call.bat"
    SystemUtil.Run coboname

    CreateFile()
    '  テスト結果のsheetを読み込む
    rst.Open"select  *   from [WHCT0762$] " ,conn,1,1
    result1 = rst.RecordCount
    msgbox "RecordCount = "&result
    reporter.filter=0

    objrsa.open"select  * from WHCT0762"
    While (Not rst.EOF) AND  (NOT  objrsa.EOF)
     If rst.fields(1) <> objrsa.fields(1) Then
           ' msgbox "IDX="&rst.fields(0)&"ケースはエラーです"
        result = "IDX="&rst.fields(0)&": [エラー]"
        reporter.ReportEvent micFail ,"Error",result
        SetFile(result)
     else
          'msgbox "IDX="&rst.fields(0)&"のケースはOKです"
       result = "IDX="&rst.fields(0)&": [OK]"
         SetFile(result)
     End If
     rst.MoveNext
     objrsa.MoveNext
     Wend

    cnn.close
    Set cnn = nothing

    Sub CreateFile ()
        Dim fso, tf
     Set fso = CreateObject("scrīpting.FileSystemObject")
     Set tf = fso.CreateTextFile("E:\testfile.txt", True) ' Write a line with a newline character.
     tf.Close
     End Sub

     Sub SetFile (result)
        Dim fso, tf
     Set fso = CreateObject("scrīpting.FileSystemObject")
     Set tf = fso.OpenTextFile("E:\testfile.txt",8)
     tf.WriteLine(result)
     tf.WriteBlankLines(1)
     tf.Close
     End Sub

       虽然没涉及到Action顶级参数,QTP对象库等比较高端的手段的使用。但我想,对于学习QTP还是很有用的 。希望对正在学习QTP和准备学习QTP的人有帮助。

  • 用Schedule定时运行QTP脚本

    2007-06-20 18:22:41

    创建一个.vbs,在控制面板的Schedule里面定义自己的task就好

    vbs的脚本如下:

    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

  • TD与QTP连接

    2007-06-19 09:32:35

    1 、安装 TD,检验 TD 是否安装成功,启动 TD Server 服务器后,在与 Server 相连的其他计算机上,打开 IE 浏览器,在地址栏输入 http://TD Server ip 地址 /TDbin/start_a.htm 如果能够浏览到 TD 界面 说明安装成功。

    2
    、安装 QTP,验证 QTP 安装成功,进入 windows 操作系统,点击,开始 -> 程序 ->Quick Test Professional-> Quick Test Professional ,打开 QTP 使用界面,进行简单的录制,保证脚本录制成功,并且可以回放,与你的预操作达到的结果一致,证明 QTP 安装成功。

    3
    、安装插件,进入 TD 首页,点击见面上的 TD Add In,进入 TD Add In 界面点击 More TestDirector Add Ins 进入 More TestDirector Add Ins 界面,下载名为 TDplugInsSetup 的插件,大约 35 兆并且在 Server QTP 客户机上安装这个插件,安装成功后,会要求你重启电脑,重启后会看到,开始-程序中有个新安装的程序 “Quick Test Professinal add in for Quality Center” ,登入 TD 进入 test plan 检测是否可以在 test plan 中添加 QTP 类型的测试用例,点击后
    出现QUICKTEST.TEST 并且可以建立 QTP 的测试用例。

    4
    、检查没有问题之后
    还需要在安装 QTP 的机子上做一些相应的设定,进入 QTP 主界面 点击文件栏的 Tools-Options 进入 Options 对话框 在 Run Tab 中选择 Allow other Mercury products to run test and components 以及 Submit a defect to Qualiyt Center for each failed step 选中后 点击 ok 保存这个设置,在 QTP 主界面中点击 Tool Quality Center Connection,在 Server 中输入 http:// TDServer ip 地址 /TDbin( 本例中使用 htt......) 点击 connect 按钮 QTP 连接到服务器上 如果服务器连接有问题 则会提示连接失败。

    5
    、在 project connection 中包含一下几项:
       Domain
    TD 服务器站点管理中建立项目的域
       Project
    :域中你所建立的项目
       User
    :登陆项目所用的用户名
       Password
    :相应用户名使用的密码
       Reconnect on startup
    在下次启动 QTP 时自动登陆到你的项目中
       Save password for reconnection on startup
    为下次登陆保存密码
    完成了上述操作就 TD QTP 就连接起来
    可以从 TD 调用 QTP 脚本了。
  • QTP脚本还可以这样写

    2007-06-18 16:51:30

    文章出处:51testing博客 作者:阳阳 发布时间:2006-12-22

        一提到自动化测试工具,给人印象最深的就是录制和回放了。录制测试人员的操作过程,再回放出来并多次运行,达到使用机器代替人来执行测试的效果。

        QTP采用的关键字驱动与专家视图的设计思想,不但可以自动生成代码,使初学者快速入门,更为高级测试人员提供了便利的编程界面,使其可以高效的完成自动化测试脚本,不用完全依赖于录制和回放过程。

        下面就我个人的使用经验,简单谈谈如何不依赖于录制和回放来完成QTP脚本的。

        操作步骤很简点,主要分为三步:
        第一步,维护对象库,添加必需的对象以及配置对象的属性。
        第二步,在专家视图中,编写测试代码。
        第三步,运行并调试代码。

        举个简单的例子。

        以在51testing的网站上搜索关键字QTP为例。

        首先,打开QTP,点击工具栏上的Object Repository按钮,打开对象库维护界面。如图一(图片暂时上传不了)


        点击Add Objects按钮,添加站内搜索的文本框以及后面的查询按钮对象,如图二

        然后,在专家视图中,手动输入如下代码:
        Browser("软件测试
    专业网站:51Testing软件测试网").Page("软件测试专业网站:51Testing软件测试网").WebEdit("keyword").Set "QTP"
        Browser("软件测试专业网站:51Testing软件测试网").Page("软件测试专业网站:51Testing软件测试网").Image("GO").Click

        由于录制的过程中,待测试的页面是已经打开的,所以为了保证这个测试的前提条件,在前面添加打开IE的语句。
        SystemUtil.Run "iexplore.exe","
    "

        这样,使用QTP的自动化测试脚本就完成了,运行看看是否通过?结果是一次性通过,而且没有其他需要修改的地方了。

        还可以在此基础上增加关闭所有IE的函数,增加验证点等等使脚本更加健壮和完整,这里就不赘述了。

     

        如果使用录制和回放的方法来开发脚本,可能存在以下几个问题:

        一个是自动生成的代码有一些是没有用的,有时候反而会影响代码的质量;

        一个是通过录制生成的代码,健壮性都不好,如果要使脚本在无人值守的情况下顺畅地运行,还是需要手动修改的。比如在对象找不到的地方增加判断对象是否存在,再继续下一步操作等等;

        再有,就是录制的过程中,会使你的对象库中多出来一些脚本正常运行以外的多余的对象,给维护对象库也增加了工作量。

        比较这两种方法,总体感觉直接添加对象并编写代码的方式,可以弥补录制回放过程的不足,节省了脚本的开发时间,减少了对象库的维护工作量,大大提高了自动化测试脚本的开发效率。

        当然,能够这样做是有前提的。
        第一,必须对待测试的系统非常熟悉。即开始写自动化脚本之前就能从大脑中反映出每一个步骤中需要的对象及操作。
        第二,对QTP的工作原理以及工具本身非常熟悉。能够有办法解决脚本运行时出现的任何问题。
        第三,有良好的编程基础尤其是针对VBscrīpt语言的。如果对于代码的结构、可维护性都把握很好的话,那么效果就会更加明显了。

        补充一点,使用这种方法,你的对象库的设计一定要到位,保证在写代码的时候,很容易的找到你要操作的对象,否则就得不偿失了。

  • QTP中调用共享文件

    2007-06-18 16:47:53

    文章出处:51testing博客 作者:xiaonan 发布时间:2006-12-29
        在我们开发脚本的时候,发现有些脚本总是重复的出现在各个脚本中。那么我们是不是可以把这些脚本写成一个共享的function,放到一个共享的文件中?然后再给各个脚本调用呢?答案当然是肯定中。其实我在《QTP的一些小知识》中也提到了一个方法,就是利用ExecuteFile函数来调用.vbs文件。如:一个名为test.vbs的文件,我们只要在脚本中写上这么一句代码ExecuteFile("F:\test.vbs") ,就可以来直接执行这个.vbs文件了。

        现在我再来介绍另一种方法,这种方法也是QTP本身所提供的。就是设置菜单选项“setting”中的"resource"选项来做到调用共享文件的效果。在"resource"选项中,有三种文件格式是可以被调用的,分别是*.sql;*.vbs;*.txt三种后缀文件。这里我用一个*.txt文件为例。

        新建一个名为test.txt的文本文件,其保存内容如下:(注:保存的内容也必须合法)

    Function writeorderno(orderno)
    Dim fso, myfile
    Set fso=CreateObject("scrīpting.FileSystemObject")
    Set myfile=fso.openTextFile("C:\result1.txt",8,false)
    myfile.writeline orderno
    myfile.close
    End Function

        一个名为writeorderno的Function,其作用是把传进来的值写到C盘名为result1.txt的结果文件中去。(注:结果文件也是事先要准备好的)。共享文件准备完毕,那么就开始设置"resource"选项。打开“setting”窗口,找到"resource"选项。点击“+”的button。选择前面我们建好的文件。如下:

        确定关闭窗口。我们就来试验一下,是不是这个共享文件里的Function能够被调用了。在QTP专家视图里写上这么几句代码:

    Dim order

    order=1

    writeorderno order

        接下去就按run执行试验,结果测试通过。虽然在脚本中根本没对writeorderno函数做说明,但是当QTP运行到这句代码的时候,在本脚本里没说明的情况下,自己会到"resource"选项里去找。结果QTP能正确识别这个writeorderno 函数。打开c盘里的 result1.txt的结果文件,发现传进函数的值1,被正确的写了进去。预示着整个调用共享文件的成功。

  • QTP的学习历程

    2007-06-18 16:44:36

    文章出处:51testing博客 作者:higkoo 发布时间:2007-01-11
        对于我来说,学习QTP是一个漫长而有艰苦的过程  。首先我不是计算机及相关专业毕业的(医学相关)。跳入测试部时,我正在接受程序员的培训课程。由于自己认为需要,于是开始学习QTP。

        刚开始使用QTP,就一直对着说明书,不停的“订飞机票”(订飞机票是说明书里的一个例子)。学会了一个步骤就拿到公司产品上玩玩,回忆起来还是挺有趣的。

       当我用一些简单的功能开始录制脚本时,发现保存ActiveXScreen的话,生成的脚本很中空间(因为程序会保存每个不同的录制页面),多录一些硬盘空间就满了,而且回放过程会很慢。  但如果不保存活动页(ActiveXScreen),对脚本的再改造/维护起来就相对困难一些。

       于是我开始去了解“关键字”视图里的内容,尝试了解代码。慢慢的,我了解到“关键字”视图显示了整个操作步骤,第个组件相对于程序里一个元素。同时还记录了录制过程对该元素的操作和结果。

        然后我又开始在论坛在找些资料看看,从有点所谓的高级应用中,我发现脚本的维护并不一定要有“活动页”。实际是QTP所有对象的识别,都存在脚本的一个对象库里了。QTP经常出现无法识别对象的问题,可以从这里着头修改。  
       为了减少QTP脚本占用空间大、录制慢的问题。我查阅了一些资料,可以在设置中进行修改,让脚本中不保存活动控件(ActiveX)或仅保存出错时的录制页面。干脆,我就从此录制页面了。所有的调试都从“关键字”视图和“专家”视图中进行修改。而且关于对象库,QTP也有个选项,可以设置加载页面上所有的对象,我修改成只保存页面上录制过程使用的对象。  这样,脚本的容量问题就解决了,录制后的脚本会比以前小很多,来了个彻底的瘦身。关于录制速度的问题,和保存“活动页”、动态脚本也有一定的关系,另外可以减小启动的加载项(如:去掉VB插件、.net插件,不需要的就不加进来)。这样的脚本上传到TestDirector上,或从TestDirector上调用就不会太慢了。

       然而真正的问题,棘手的问题就不是上面所述的那么简单了。不过都是有办法解决了的,嘿嘿……
       以下是我经常遇到的问题:
           一、无法识别控件。
           二、错误回放过程未知弹出窗口。
           三、加载.net插件后和TD的关联问题。
           四、动态加载元素的识别问题。
           五、调用外部dll的问题。
           六、随机验证码的问题。

    问题一,解决办法有三种:
       1、更改QTP自身对某控件的识别方式,在 tools——Object Identification 中。在这里列出了所有QTP能识别的控件,以及控件的识别方式。你可以给他添加X、Y坐标进行识别。或更明显的,列表中的信息,不按名称识别,而是按ID识别。这个修改可以解决一些问题,具体的赶紧动手试试吧……
       2、使用虚拟物件,来定义一个控件,在 tools——Virtual Object 中。在这里可以自定义一个控件。例如在ASP的程序中,程序出错,在客户端的表现形式大部分是一样的,你可以把整个错误页面当成一个控件来识别(感觉不错)。如果加一个判断,出错后你想做什么就由你自己定了。
       3、使用低级录制或鼠标录制。用 Test——LowLevelRecording/AnlogRecording 吧,用它录制就不需要什么设置了,他会记录你的程序控件相对屏幕的位置。用LowLevelRecording还有代码可改,用AnlogRecording动作就被封装了(维护性极差)。两者因实际环境更取其长吧……

    问题二的解决过程:
    关于弹出提示的问题,我当时需要情况是这样的。一个信息录入系统,由于数据量很大,查询需要一段时间。QTP回放时动作比较快,点了保存,程序还没反应过来它就进行了下一步操作。这时的操作就和录制时不一样了,程序给出一个提示,但这个提示是录制过程没有的。弹出框是一般都是POP形势(至上)的,导致QTP无法继续回放,结果就是回放失败。  
    解决办法有两个:
           
    1、进行判断,当出现这个提示时,点是/否/取消按钮。
            2、通过 Tools——Recorvery Scenario Manager 设置默认操作。
        我最初就是用的第一种方法。写一个函数判断是否出现这个提示,如果出现就点“取消”然后wait(2)。    每个可能出现弹出框的动作后都调用一次这个函数。虽然可以解决这个问题,但回放的效率就低了,而且需要你预知提示框的信息。
        当我知道了第二种方法,显然更科学^_^。它可以对所有预知甚至不知的提示进行指定的操作。
        实际上,当程序出现了未预知的提示时,可能就是程序的BUG,所以使用上述办法解决工具问题时,也要考虑是否会掩盖程序的缺陷。

    问题三的解决办法:
          用好QTP后,会不自觉的和TD关联起来。但从TD直接启动QTP时,程序只会加载QTP自带的插件,如果你安装了其它插件(如.net、java、etc.),默认是不加载的。这会导致上传的脚本无法正确执行。解决办法很简单,去 Test——Setting里进行Modify 吧。从本地打开的脚本,这里不能进行Modify的。所以办法很简单,但如果不知道的话就很难了。当初为这个问题我可是废了八牛三虎之力呢……

    问题四的解决过程:
         当我开始改代码时,定义一个动作,然后可以生成N个动作。假设N个动作产生了N个结果,你要对这结果进行处理时,你会发现这N个结果都不能被识别:

    网页上有个表格,是往数据库里加数据的。
    两个表格显示在同一个页面上,左边为父表,右边为子表。
    点击左表,右表显示其子项目。 
    结构如下:  
    A
    ├─1
    ├─2
    ├─3
    └─4
    B
    ├─1
    ├─2
    ├─3
    └─4
                        ……
    思想很清晰:
    添加一个父项A、选中此父项A、对其添加子项1、2、3、4
    添加一个父项B、选中此父项B、对其添加子项1、2、3、4  ……

    代码也很简单:
    dim M          '定义父项数
    dim N          '定义每个父项包含的子项数

    For i=1 to M
          Call 添加父项( i )       
          选中父项( i )              '问题就出在这里  
       For j=1 to bwfl step 1
           Call 添加子项( j )
        Next       
    Next

    现在问题出来了,思路应该没有问题(除非这方法真的行不通),循环也是顺着思想来的。

    问题是,无法实现选中的父项(最多识别到一个)。
    由于此循环可以在录制过程进行,如果不改变变量名称,循环可且只可以成功运行一次。问题是这个名称都是从DataTable里获取的。
    因为,在运行过程中生成的项目没有加到对象库中,无法被识别。

       这个问题最后是从思想上解决的。答案是我做的是功能测试,为什么不先加父项,检查父项的功能是否正常,然后再去测子项的功能。不去改变名字,因为那没有必要。核心答案“功能测试、测试功能”。即对测试工具首先需要有正确的认识。
       当然,这个问题可以用代码去实现,但那需要有一定的编程功底且耗时,可维护性不一定好。有需要的朋友可以去试一下,然后把你的经验也共享一下。

    问题五,是对QTP很大的一个扩充。  
        对于QTP调用外部DLL的功能,由于我的编程功底不够,没有相关人士配合我,我只能望之垂涎了!
        如果能调用外部DLL的话,QTP的功能就可以变得很强大。自己写的程序,自己编一些过程用QTP进行测试,我想“后果很严重”  。真想有一次给我尝试的机会……

    问题六,解决办法有4个:
        1、测试的时候,让程序员把这块限制去掉,免去验证这关。
        2、让程序员提供一个万能验证码,测试可以绕过这一关。
        3、请程序员提供识别的方法,从获取的图片
    读出验证数据,再传给QTP。
        4、进行位图检查,将验证码分段进行图像验证。

        实际上,验证码的目的就是防止用程序灌水或机器录入信息。所以有点为难我们测试了。
    方法1,如果程序已在发布并有客户使用,危险性是可想而知的。方法2虽然可以解决验证这一关,但跳过了输入码与验证码一致性问题。方法3就需要程序员配合了,可能就需要调用DLL了。方法4却将图像分段,把获取的图像和已经的图像进行比对,比对通过取对应的值;这个在数字验证会好做一点,因为最多就四个图像的比对。
        关于网上的汉字验证码,那块的测试我就不知道他们是怎么做的了。真想了解一下!  
     
        以上就是我对过去QTP学习过程的一个总结。供天下各界朋友参观、发言、讨论,也是对我过去的一个写照,可能N年后,自己看到会很有感觉呢  。
        现在又有项目来了,我学习的时间慢慢也少了。新项目里融合了C++程序,QTP对C++的识别似乎很不理想,也许是需要插件支持吧。过程中我尝试了Rational的Robot,Robot对C++的识别很好,但Rational一套组件内容太多,对汉字的支持似乎也不是很好。用了一段时间我就把它从硬盘中给清掉了……  
  • QTP中的descriptive programming

    2007-06-18 16:12:57

    文章出处:www.51testing.com 作者:周坚 发布时间:2005-10-19

    【摘要】自动化功能测试是一种企业级的用于检验应用程序是否如期运行的功能性测试工具。通过自动捕获,检测,和重复用户交互的操作,能够辨认缺陷并且确保那些跨越多个应用程序和数据库的业务流程在初次发布就能避免出现故障,并且保持长期可靠运行。在市场上用的比较多的主要包括Mercury公司的WinRunner,QuickTest Professional和IBM的Rational Robot。笔者对于QuickTest Professional相对较为熟悉,希望有机会向大家逐步介绍QuickTest Professional中的一些要点及技巧。在本文里主要介绍了QuickTest Professional中的一项核心内容Descrīptive Programming,希望对大家有所借鉴和帮助。在文中,为了方便起见,将QuickTest Professional简称QTP。(本文是基于Quick Test Professional V8.0而写)。

    【关键词】

    描述性编程Descrīptive Programming

    功能测试Functional Test

    专家视图Expert View

    关键字视图Keyword View

    对象模型Object Model

    运行时对象Run-Time Object

    测试对象Test Object

    【正文】

    .QTP功能测试基本方法

    我们简单介绍一下有关功能测试的基本方法,这实际上对于所有自动化功能测试产品来说都是一样的。一般情况下,用QTP来进行功能测试的基本方法主要包括三个主要阶段:

       

    1、创建测试或组建

    首先可以通过在应用程序或网站上录制会话,或者建立对象库并使用关键字驱动功能向关键字视图中手动添加步骤来创建测试或组件。在QTP里面我们可以通过两种方式添加步骤来创建测试或组件:

    • 在应用程序或网站上录制会话。
    • 建立对象库并使用这些对象在关键字视图或专家视图中手动添加步骤

    然后在在测试或组件中插入检查点,检查页面、对象或文本字符串中的特定值或特征,通过它可以标识网站或应用程序是否正常运行。或是通过用参数替换固定值扩展测试或组件的范围。提供数据表中的数据,定义环境变量和值,定义测试、组件或操作参数和值,或者使用QTP生成随机数字或当前用户和测试数据等。

    最后如果需要的话使用QTP中众多的功能测试功能来增强测试或组件或添加编写语句来实现更复杂的测试目标。

    2、运行测试和组建

    控制运行会话,帮助标识和消除测试或组件中的缺陷。使用“单步执行”、“单步跳过”和“单步退出”命令逐步运行测试或组件,或设置断点使测试或组件在预定点暂停。每当测试或组件在断点处停止时,可以在“调试查看器”中查看其变量的值。

    3、分析结果

    在运行测试或组件之后,通过两种方式可以查看其结果:在“结果”窗口中查看结果;自动报告在运行会话过程中检测到的缺陷,可能的话并上报到其他缺陷管理产品中。

    .试图与对象模型

    在介绍QTP中的Descrīptive Programming前,我们有必要先介绍一下ExpertView及在ExpertView里进行编码的一些基本知识。

    在QTP里面提供了两种视图,第一种我们把它称为KeywordView(关键字视图,在早期的版本中称为TreeView),第二种把它成为ExpertView(专家视图),这两种视图分别是针对两种类型的人进行使用的。

    1、KeywordView(关键字视图)

    通过关键字视图,QTP提供了一种模块化的表格格式创建和查看测试或组件的步骤。每个步骤在关键字视图中都是一行,这样用户可以轻松的修改任何一部分组成。

    在录制会话过程中,用户在应用程序上执行的每个步骤在关键字视图中记录为一行。例如,在51testing的页面上执行的下列三个步骤:

    • 在“用户名”编辑框中输入 zhoda02。
    • 在“密码”编辑框中输入加密字符串 41c630a213508cd49eb35089db1b893144b9。
    • 单击“登录”按钮。

    那么,关键字视图将包含下列行:

       

    很显然,关键字视图非常直观有效,使用的人可以很清晰的看到被录制对象的录制层次及运行步骤,比较适合那些对于业务操作流程熟悉的人员使用。但是,如果需要一些增强型的操作,那就需要切换到专家视图里进行了。

    2.ExpertView(专家视图)

    QTP在关键字视图中的每个节点在专家视图中对应一行脚本。上面例子对应的脚本如下:(删除后一句是因为前后重复,一句可以说明问题)

    Browser("51Testing软件测试网:软件测试的专业网站").Page("51Testing软件测试网:软件测试的专业网站").WebEdit("username").Set "zhoda02"

    Browser("51Testing软件测试网:软件测试的专业网站").Page("51Testing软件测试网:软件测试的专业网站").WebEdit("password").SetSecure "41c630a213508cd49eb35089db1b893144b9"

    Browser("51Testing软件测试网:软件测试的专业网站").Page("51Testing软件测试网:软件测试的专业网站").WebButton("登录").Click

    对于QTP来说,其核心编码语言是Visual Basic scrīpt,因此,如果用户熟悉VBscrīpt,可以运用自如的添加和更新语句,并通过编程方式增强测试和脚本,而这一切必须在专家视图中完成。

    更为重要的是,有些操作是必须在专家视图中才可以完成的,例如:要处理动态对象、客户化报告、获取对象运行时的属性值(Run-time Value)等等,这些都必须通过专家视图中的VBscrīpt编码完成。

    然而,QTP里所有的操作都是基于对象进行的,所以我们必须对对象模型有一个基本了解,才可以在专家视图内进行Descrīptive Programming。

    3、测试对象模型

    测试对象模型是一大组对象类型或类,QTP用这些对象类型或类来表示应用程序中的对象。每个测试对象类都有一个可以唯一标识属于该类的对象的属性列表,以及一组 QTP可以对其进行录制的方法。它包括测试对象(Test Object)和运行时对象(RunTime Object)。

    测试对象是QTP在测试或组件中创建的用于表示应用程序中的实际对象的对象。QTP存储有关该对象的信息,这些信息有助于它在运行会话期间标识和检查该对象。

    运行时对象是网站或应用程序中的实际对象,在运行会话期间执行针对该对象的方法。

    如果录制时执行应用程序的相应操作,则一般情况下QTP将完成以下操作:

    • 标识 QTP测试对象类(表示执行了操作的对象),并创建相应的测试对象
    • 读取应用程序中对象属性的当前值,然后将属性和属性值列表与测试对象一起存储。
    • 选择该对象的唯一名称,一般使用该对象某个重要属性的值。
    • 使用适当的 QPT 测试对象方法录制对对象执行的操作。

    例如,假定使用以下 HTML 源代码单击“查找”按钮:

    <INPUT TYPE="submit" NAME="Find" VALUE="Find">

    QTPl将单击的对象标识为 WebButton 测试对象。它将创建一个名为 Find 的 WebButton 对象,然后为该 Find WebButton 对象录制下列属性和属性值,同时还会录制对WebButtion的Click方法。

       

    在关键字视图及专家视图中显示内容分别为:

       

    Browser("Mercury Interactive").Page("Mercury Interactive").WebButton("Find").Click

    运行测试或组件时,QTP通过其测试对象类及其描述(一组用于唯一标识该对象的测试对象属性和属性值)来标识应用程序中的每个对象。测试对象及其属性和属性值的列表存储在对象库中。例如在上例中,QTP将在运行会话期间在对象库中搜索 WebButton 对象,通过名称 Find 来查找其描述。QTP根据找到的描述,在应用程序中查找 WebButton 对象,该对象带有 HTML 标记 INPUT、类型为 submit、值为 Find。找到对象后,它将对其执行 Click 方法。

    在这样一组对象模型的基础上,QTP为各类应用对象都提供了一组方法和属性,例如Web Objects,Windows Objects,SAPGUI Objects,ActiveX,Java等。下面是一些Web Objects的方法和示例:

    对象 方法
    Browser

    Check

    Frame

    Click

    Image

    Exist

    Link

    GetCellData

    Page

    GetProperty

    WebArea

    GetROProperty

    WebButtion

    Mouseover

    WebCheckBox

    RowCount

    WebEdit

    Select

    WebList

    Set

    WebRadioGroup

    SetProperty

    WebTable Submit

    例1:获取单元格中的值

    thisText = Browser(…).Page(…).Frame.(…).WebTable("sample").GetCellData(2,1)

    例2:获取图片的名称

    ObjectName = Browser(…).Page(…).Image("Find").GetProperty("Name")

    例3:检查某个对象是否存在,如果存在弹出对话框说明对象存在。

    If Browser("Browser").Page("Page").Applet("login.html").JavaEdit("username").Exist Then

    MsgBox("The object exists.")

    End if

    .描述性编程(descrīptive programming)

    1、descrīptive programming概述

    通常情况下,当在录制一个操作时,QTP会将被操作对象加入到对象库里(Object Repository)。一旦对象存在于对象库里,我们就可以在专家视图里通过添加相关的对象方法来对该对象进行操作。我们可以通过引用层次型对象库里的对象描述(Object Descrīption)来添加相应的方法。

    因为QTP对象库中的每个对象都具有唯一名称,所以在引用时对象名是必须需要指定的。然后在测试运行期间,QTP在对象库中根据这个对象的名称和父对象来查找对象,并使用为这个测试对象存储的测试对象描述,在网站或应用程序中标识该对象。

    例如我们用QTP录制Yahoo Mail登录情况时我们需要输入用户名,于是在录制时我们就会录下一个WebEdit对象,它的缺省逻辑名为“login”,该编辑字段位于名为 “Yahoo! Mail - The best” 的页面上,并且该页面在浏览器中使用名称 Yahoo!进行录制。如图所示,即为录制时的对象库的内容:

       

    那么如果我们想要应用该对象,就可以在专家视图输入以下信息:

    Browser("Yahoo!").Page("Yahoo! Mail - The best").WebEdit("login").Set “xxx”

    或者我们也可以调用一些方法,获取改对象在运行时的对象名,如:

    Browser("Yahoo!").Page("Yahoo! Mail - The best").WebEdit("login").GetROProperty(“name”)

    然而,我们可以发觉到,上面的例子在处理对象时,对象已经存在于对象库里,因此我们可以应用这个对象的逻辑名。实际使用中,情况往往并非如此简单,我们经常会遇到很多在页面上动态产生的对象,换而言之,对象库里没有这些对象,我们也无从引用。因此我们必须采用其他的技术来完成这类操作,这也就是我们需要讲解的Descrīptive Programming。

    为了满足上面提到的动态对象的处理问题,QTP允许用户通过将对象属性编码到测试脚本里来动态识别对象,这就是我们通常意义下称为的Descrīptive Programming。通过这种方式,我们可以指示QTP不通过引用对象库和对象名来对实际对象进行操作。具体操作中,我们只需要为QTP提供对象的一组属性和值,这样QTP就可以来识别相应的对象并对其进行操作。这相当于,告诉QTP要识别对象的一些关键特征,根据这些特征QTP就可以一一匹配然后识别出来这个对象。

    而且,更为重要的是,通过这种Descrīptive Programming的方式,还可以让QTP识别具有某些相同属性的对象。我们先来举个例子来看一下:我们假设当前的Windows系统中打开了若干的Yahoo主页面(多于一个),现在我们要关闭所有的正在浏览Yahoo主页面的浏览器。

    对于上面那个例子来说,我们先看一个简单一点的情况,假设只有且仅有一个Yahoo主页面:那么我们可以用下面的方法来

    Window("Text:=Yahoo! - Microsoft Internet Explorer").Close

    我们可以看到语句里我们要查找的对象是Window窗口标题为“Yahoo! - Microsoft Internet Explorer”,然后把它关闭,具体的语法说明我们稍后为解释。但是上面的语句仅仅适合前面提到的条件“只有且仅有一个Yahoo主页面”,如果有多个同样的窗口就会出错,原因是通过语句可以匹配到多个对象,而QTP不知道应该对哪个对象进行关闭动作。我们需要进一步的缩小匹配范围:

    Dim i

    i = 0

    while (Window("Text:=Yahoo! - Microsoft Internet Explorer", "index:="&i).exist)

    Window("Text:=Yahoo! - Microsoft Internet Explorer", "index:="&i).close

    i = i +1

    wend

    这里我们可以看到,对于具有相同属性的对象,我们可以通过index参数来对其进行区别,第一个对象为index=0,第二个为index=1等等,依次类推。当然我们还可以通过CreationTime和Location参数来定位对象,这里就不详细叙述了。

    通过上面的例子,我们对Descrīptive Programming有一个基本了解了,下面我们详细讲解一下Descrīptive Programming:在具体实现中,我们有两种类型的Descrīptive Programming方法。可以列出直接在测试语句中描述对象的属性和值的集合;或者向 Descrīption 对象中添加属性和值的集合,然后在语句中输入 Descrīption 对象的名称。下面我们分别举例介绍。

    2、直接在语句中输入编程描述

    通过多个指定描述对象的property:=value对,可以直接在语句中描述对象,这是最直接有效的方法。

    常规语法为:

    TestObject("PropertyName1:=PropertyValue1", "..." , "PropertyNameX:=PropertyValueX"}

    TestObject - 测试对象的类。

    PropertyName:=PropertyValue - 测试对象的属性及其值。各个property:=value 对之间应用逗号和引号分开。

    例如:以下语句指定 Mercury Tours 页面中名为author且索引值为 3 的 WebEdit 测试对象。当测试运行时,QTP 将查找具有匹配属性值的 WebEdit 对象,并输入文本jojo。

    Browser("Mercury Tours").Page("Mercury Tours").WebEdit("Name:=Author", "Index:=3").Set "Mark Twain"

    我们也可以从从描述中的特定位置(从 Page 对象描述开始)开始使用Descrīptive Programming。

    Browser("Mercury Tours").Page("Title:=Mercury Tours").WebEdit("Name:=Author", "Index:=3").Set "jojo"

    此外,如果我们希望在在一个测试或组件中多次使用相同的Descrīptive Programming,则可以将创建的对象赋值给变量,这样使用会方便很多。

    例如:我们需要完成下面一系列操作

    Window("Text:=HyperSna").WinButton("Caption:=日期").Click

    Window("Text:=HyperSna").WinButton("Caption:=时间").Click

    Window("Text:=HyperSna").WinButton("Caption:=确定").Click

    那么,为了方便其见,我们可以将Window("Text:=HyperSna")赋值到一个变量,然后再使用,参见下面的代码:

    Set WinHyper = Window("Text:=HyperSna")

    WinHyper.WinButton("Caption:=日期").Click

    WinHyper.WinButton("Caption:=时间").Click

    WinHyper.WinButton("Caption:=确定").Click

    如果使用了VBscrīpt里面的With语句,还可以简化为以下代码:

    With Window("Text:=HyperSna")

    .WinButton("Caption:=日期").Click

    .WinButton("Caption:=时间").Click

    .WinButton("Caption:=确定").Click

    End With

    下面我们来看一个更为详细的例子,在QTP产品缺省安装里面自带了一个网上订机票的示例称为Mercury Tour,我们看一下在订票过程中何时需要用Descrīptive Programming。

    首先登入系统后,如果需要订票,就要先搜索航班,此时系统要求输入订票乘客的数量,假设我们在第一次录制脚本时选择了1个Passenger,并成功完成订票。然后,我们需要参数化乘客数量来测试订票系统,我们会发现回放会失败。原因在于,不同的乘客的数量导致在订票时需要输入每个乘客的姓名,而录制时,只输入了一个乘客的姓名。而乘客姓名的输入框是随着乘客数量的变化而动态生成的,我们不可能从对象库里得到没有录制的对象,因此必须使用Descrīptive Programming。

       

    在录制单个乘客时,我们得到的录制语句是:

    Browser("Welcome: Mercury Tours").Page("Book a Flight: Mercury").WebEdit("passFirst0").Set "Michael"

    Browser("Welcome: Mercury Tours").Page("Book a Flight: Mercury").WebEdit("passLast0").Set "Wang"

    显然WebEdit("passFirst0")和WebEdit("passLast0")是录制时产生的对象并存放到对象库里的。通过对象库,我们可以看到对象的属性如下

       

    系统对于发生多个FirstName时,命名规则是passFirst0,passFirst1…依次类推。因此只要通过简单的Descrīptive Programming就可以完成动态FirstName与LastName的识别工作。这里我们假设参数化的乘客数已经赋值给intPassNum,下面是脚本中的关键语句:

    counter = 0

    For i = 0 to (intPassNum)

    Browser("Find a Flight:").Page("Book a Flight:").WebEdit("name:=passFirst"&i).Set "Michael"

    Browser("Find a Flight:").Page("Book a Flight:").WebEdit("name:=passLast"&i).Set "Wang"

    counter = counter + 1

    Next

    3、使用descrīption对象

    使用 Descrīption 对象可以返回包含一组 Property 对象的 Properties 集合对象。Property 对象由属性名和值组成。然后,可以在语句中指定用返回的 Properties 集合代替对象名。(每个 property 对象都包含一个属性名和值)。

    要创建 Properties 集合,可以使用以下语法输入 Descrīption.Create 语句:

    Set MyDescrīption = Descrīption.Create()

    创建 Properties 对象(例如,以上示例中的MyDescrīption)后,就可以输入语句,以便在运行会话期间在 Properties 对象中添加、编辑、删除或检索属性和值。这样,就可以在运行会话期间,使用动态方法确定哪个属性以及多少个属性应包含在对象描述中。

    在 Properties 集合中填充一组 Property 对象(属性和值)后,可以在测试语句中指定用 Properties 对象代替对象名。

    例如,假设我们需要完成以下一个操作:

    Window("Error").WinButton("text:=OK", "index:=1").Click

    我们可以通过Descrīption对象来实现同样的功能,参加下面的代码:

    Set MyDescrīption = Descrīption.Create()

    MyDescrīption("text").Value = "OK"

    MyDescrīption("index").Value = 1

    Window("Error").WinButton(MyDescrīption).Click

    Set MyDescrīption = Nothing

    【小结】以上是对QTP中有关处理动态对象中的Descrīptive Programming的简单介绍,希望对大家能够有所帮助,就总体而言,如果能够熟练掌握Descrīptive Programming,那么有很多实际中的问题就可以迎刃而解。当然Descrīptive Programming只是QTP中的一个功能,QTP在实际功能测试中还有很多强大的功能,作为QTP学习的一个系列有机会我会一一介绍。

  • 用QTP调用外部vbs读写XML的例子

    2007-06-18 16:07:48

    目前,企业中对XML的应用越来越广泛,作为自动化测试的测试工程师,也应该掌握XML的读写操作。
    以下我使用XML DOM技术演示一个例子,用以读取XML指定节点的节点内容值。
    读取函数原型 GetXml strXmlPath,nodeName
    这个函数的第一个参数表示xml文件所在路径,第二个参数表示希望获取到的xml节点名,请结合下列例子看
    首先,新建一个vbs文件(取个名字叫readXml.vbs),输入代码:

    CODE:

    '==================================================================
    ' Author : songfun
    '
    ' Descrīption : Read XML
    '==================================================================
    Dim strXML

    GetXml "c:\search.xml","TestResult" '这个函数的第一个参数表示xml文件所在路径,第二个参数表示希望获取到的xml节点名,请结合下列例子看
    MsgBox strXML


    Function GetXml (ByVal strXmlFilePath,ByVal xmlNodeName)
    Dim xmlDoc,xmlRoot

    Set xmlDoc = CreateObject("Microsoft.XMLDOM") '创建XML DOM对象
    xmlDoc.async = False '控制加载模式为同步模式(xml树加载完毕后再执行后续代码)
    xmlDoc.load strXmlFilePath '载入xml文件
    If xmlDoc.parseError.errorCode <> 0 Then
    MsgBox "XML文件格式不对,原因是:" & Chr(13) & xmlDoc.parseError.reason
    Exit Function
    End If
    Set xmlRoot = xmlDoc.documentElement
    xmlRecursion xmlRoot,xmlNodeName '调用xml递归函数传入指定的根和节点名
    GetXml = True 'xmlRecursion (xmlRoot)

    End Function

    Function xmlRecursion(byval xmlNode,byval strNodeName)
    If xmlNode.nodeName = strNodeName And xmlNode.hasChildNodes Then
    If xmlNode.childNodes.item(0).nodeName = "#text" Then
    strXML = strXML & xmlNode.nodeName & ":" & xmlNode.childNodes.item(0).nodeValue & Chr(13)
    End If
    End If
    If xmlNode.hasChildNodes Then
    For Each childNodeItem In xmlNode.ChildNodes
    If childNodeItem.hasChildNodes Then
    xmlRecursion childNodeItem,strNodeName
    End If
    Next
    End If
    End Function
    接着,自己构造一个xml文件(取个名字叫search.xml),如:

    CODE:

    <?xml version="1.0" encoding="GB2312"?>

    <ROOT>
    <TestCase>
    <TestNumberOne>1</TestNumberOne>
    <TestNumberTwo>2</TestNumberTwo>
    <TestNumberThree>+</TestNumberThree>
    <TestResult>3</TestResult>
    </TestCase>
    <TestCase>
    <TestNumberOne>3</TestNumberOne>
    <TestNumberTwo>2</TestNumberTwo>
    <TestNumberThree>-</TestNumberThree>
    <TestResult>1</TestResult>
    </TestCase>
    <TestCase>
    <TestNumberOne>3</TestNumberOne>
    <TestNumberTwo>7</TestNumberTwo>
    <TestNumberThree>*</TestNumberThree>
    <TestResult>21</TestResult>
    </TestCase>
    <TestCase>
    <TestNumberOne>2</TestNumberOne>
    <TestNumberTwo>5</TestNumberTwo>
    <TestNumberThree>/</TestNumberThree>
    <TestResult>0.4</TestResult>
    </TestCase>
    </ROOT>
    然后,在QTP的expert view中调用刚才写的vbs文件:
    executefile "c:\readXml.vbs"

    点“Run”,就能看到这个效果了。
    当然,如果你不用调用外部文件的方式,也可以,如下图。


  • 经典编程书籍(C++, 网络, Windows, Linux)

    2007-06-13 16:51:30

    1、C++ Language
    ------------------------------

    Bjarne Stroustrup. The C++ Programming Language (Special 3rd Edition)
    《C++程序设计语言(特别版)》

    Bjarne Stroustrup. The Design and Evolution of C++
    《C++语言的设计和演化》

    Stanley B.Lippman, Josée LaJoie, Barbara E.Moo. C++ Primer (4th Edition)
    《C++ Primer中文版(第4版)》

    Scott Meyers, Effective C++ (3rd Edition)
    《Effective C++中文版(第三版)》

    Scott Meyers, More Effective C++
    《More Effective C++中文版》

    Herb Sutter, Exceptional C++
    《Exceptional C++中文版》

    Herb Sutter, More Exceptional C++
    《More Exceptional C++中文版》

    Nicolai M. Josuttis, The C++ Standard Library: A Tutorial and Reference
    《C++标准程序库:自修教程与参考手册》

    Scott Meyers, Effective STL

    Brian W.Kernighan, The Prictice of Programming
    《程序设计实践》

    Steve McConnell, Code Complete , 2nd Edition
    《代码大全(第二版)》

    Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. Design Patterns: Elements of Reusable Object-Oriented software
    《设计模式:可复用面向对象软件的基础》

    John Lakos, Large-Scale C++ Software Design
    《大规模C++程序设计》


    2、网络编程
    ------------------------------

    Richard Stevens, TCP/IP Illustrated, Vol.1 / Vol.2 / Vol.3
    《TCP/IP详解》(三卷)

    Richard Stevens, Bill Fenner, Andrew M. Rudoff.
    Unix Network Programming, Vol. 1: The Sockets Networking API, Third Edition
    《UNIX网络编程》

    Jon C. Snader, Effective TCP/IP Programming
    《高级TCP/IP编程》

    Douglas Schmidt, Steven Huston,C++ Network Programming, Vol.1 / Vol.2
    《C++网络编程 卷1:运用ACE和模式消除复杂性》
    《C++网络编程,卷2:基于ACE和框架的系统化复用》

    Anthony Jones, Jim Ohlund. Network Programming for Microsoft Windows
    《Windows网络编程(第2版)》

    非常详尽的TCP/IP资源介绍:
    Uri's TCP/IP Resources List: http://www.private.org.il/tcpip_rl.html


    3、Windows
    ------------------------------

    Mark E. Russinovich, David A. Solomon.
    Microsoft Windows Internals, Fourth Edition

    Charles Petzold, Programming Windows (Fifth Edition)
    《WINDOWS程序设计(第5版)》

    Jeffrey Richter, Programming Applications for Microsoft Windows Fourth Edition
    《WINDOWS核心编程》

    Jim Beveridge, Robert Wiener. Multithreading Applications in Win32
    《WIN32多线程程序设计》

    侯捷, 《深入浅出MFC》

    George Shepherd, David Kruglinski. Programming with Microsoft Visual C++ .NET, Sixth Edition
    《Visual C++ .NET技术内幕(第6版)》

    Jeff Prosise, Programming Windows with MFC Second Edition
    《MFC Windows程序设计(第2版)》

    Jeffrey Richter, Applied Microsoft .NET Framework Programming
    《Microsoft .NET框架程序设计(修订版)》

    John Robbins, Debugging Applications for Microsoft .NET and Microsoft Windows
    《Microsoft .NET和Windows应用程序调试》

    Chris Cant, Writing Windows WDM Device Drivers
    《Windows WDM设备驱动程序开发指南》


    4、Linux
    ------------------------------

    Richard Stevens, Advanced Programming in the UNIX Environment
    《UNIX环境高级编程》

    Richard Stevens, Bill Fenner, Andrew M. Rudoff.
    Unix Network Programming, Vol. 1: The Sockets Networking API, Third Edition
    《UNIX网络编程》

    John Lions, Lion'Cornmentary on UNIX 6th Edition With Source Code
    《莱昂氏UNIX源代码分析》

    Robert Love, Linux Kernel Development, 2nd Edition
    《Linux内核设计与实现(第2版)》

    Daniel Pierre Bovet, Marco Cesati. Understanding the Linux Kernel, 3rd Edition
    《深入理解Linux内核(第三版)》

    Jonathan Corbet, Alessandro Rubini, Greg Kroah-Hartman. Linux Device Drivers, 3rd Edition
    《LINUX设备驱动程序(第三版)》

    Marshall Kirk McKusick, Keith Bostic, Michael J. Karels and John S. Quarterman.
    The Design and Implementation of the 4.4 BSD Operating System
    《4.4BSD操作系统设计与实现》

    毛德操, 胡希明. 《Linux内核源代码情景分析》


    5、Others
    ------------------------------

    Donald E.Knuth, Art of Computer Programming, Volume 1-3
    《计算机程序设计艺术》(三卷)

    Thomas H.Cormen Charles E.Leiserson Ronald L.Rivest Clifford Stein.
    Introduction to Algorithms, Second Edition
    《算法导论(第二版)》

    Bruce Schneier, Applied Cryptography
    《应用密码学》
  • 如何將Excel的文件导入Access文件

    2007-06-13 10:56:43

    1、sSheetName:要导出资料的文件名称   (Sheet   name),例如   Sheet1  
      2、sExcelPath:要导出资料的   Excel   档案路径名称   (Workbook   path),例如   C:\book1.xls  
      3、sAccessTable:要导入的   Access   Table   名称,例如   TestTable  
      4、sAccessDBPath:要导入的   Access   档案路径名称,例如   C:\Test.mdb  
       
      在声明中加入以下:  
       
      Private   Sub   ExportExcelSheetToAccess(sSheetName   As   String,   _  
      sExcelPath   As   String,   sAccessTable   As   String,   sAccessDBPath   As   String)  
      Dim   db   As   Database  
      Dim   rs   As   Recordset  
      Set   db   =   OpenDatabase(sExcelPath,   True,   False,   "Excel   5.0")  
      Call   db.Execute("Select   *   into   [;database="   &   sAccessDBPath   &   "]."   &   _  
      sAccessTable   &   "   FROM   ["   &   sSheetName   &   "$]")  
      MsgBox   "Table   exported   successfully.",   vbInformation,   "Yams"  
      End   Sub  
      使用范例如下:將   C:\book1.xls   中的   Sheet1   导入   C:\Test.mdb   成为   TestTable  
       
      ExportExcelSheetToAccess   "Sheet1",   "C:\book1.xls",   "TestTable",   "C:\Test.mdb"
  • QTP导入EXCEL文件

    2007-06-13 10:44:36

    找了很久,结合资料和VB。终于可以从EXCEL中读入数据

    Dim conn,rst,filename
    Dim var
    filename="E:\test.xls"
    Set conn= createobject("ADODB.Connection")
    conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Persist Security Info=False;Data Source="&filename&";Extended Properties='Excel 8.0;hdr=yes'"
    Set rst= createobject("ADODB.Recordset")
    rst.Open "select  *   from [Sheet1$] " ,conn,1,1
    result = rst.RecordCount
    msgbox "RecordCount = "&result
     While Not rst.EOF 
      var = rst.fields("a")
      msgbox "Data="&var
          rst.MoveNext          
       Wend
    rst.close
    Set rst=nothing

     

  • 数据驱动在QTP的运用

    2007-06-13 09:48:50

    前言:

       最近看了不少朋友写的blog文章后,就越显自己的文章比较稚嫩.但我觉得这也是一种学习的方式,现在抱着一种共同学习的态度来探讨一下数据驱动在QTP中运用.很希望看我文章朋友能不吝啬的发表一下自己对这个方面的看法,那真是万分感谢啊.

       所谓数据驱动就是用一个数据文件把测试脚本驱动起来,来达到更接近用户化更智能的测试.其目的是把测试人员从维护复杂的脚本程序中解放出来,只需维护好数据文件即可,减少了很多修改脚本的麻烦.下面讲一下通过四种途径来达到数据驱动.

    1.datatable

    QTP本身程序就给我们提供了这么一个数据表,我们可以把测试数据或测试用例填入这个数据表中.

    如:设计用例

          username  passwd    

    case1  mercury    mercury 

    case2   xxxxxxx     xxxxxx

    录制脚本

    For i=1 to Datatable.GetRowCount    51Testing软件测试网g'Dg*nI~:kPSA@
    Dialog("Login").WinEdit("Agent Name:").Set DataTable("username", dtGlobalSheet)
    "@ y;A ^(x123330
    Dialog("Login").WinEdit("Password:").Set DataTable("passwd", dtGlobalSheet)51Testing软件测试网g!paj/LKkx
    Dialog("Login").WinButton("OK").Click51Testing软件测试网QxC ribE(_U
    datatable.GlobalSheet.SetNextRow 51Testing软件测试网%j|"?Cz%ai
    Next

    本例是验证一个登录系统,通过DataTable不同的用例设计,驱动起这段脚本,达到测试的效果.当然上面的例子中还少一个很重要的步骤,那就是结果比较.如果不能进行结果比较的自动化测试不能够称为自动化测试.
    $?6ye;X lM.lU3@123330当然我们这里主要讲的是数据驱动,所以不在对上面的例子进行补充.

    2.文本文件

    我们可以把文本文件当成数据文件,通过对文本文件的读写操作,来实现数据驱动.

    例:文本文件内的内容

      mercury,mercuy

    读文件的代码

    Function writeorderno(orderno)
    {;[V3z3i123330Dim fso, myfile,username,passwd51Testing软件测试网y-SO4VM2g
    Set fso=CreateObject("scrīpting.FileSystemObject")51Testing软件测试网U'K)t5L5T MLY:M
    Set myfile=fso.openTextFile("C:\testing.txt",1,false)
    ]|BA!iJCE123330tmp=split(myfile.readline,",")
    &w'g&A~uU123330username=tmp(0)51Testing软件测试网0?0K#]9[m%VhC+L o
    passwd=tmp(1)
    5C4U ~2UE123330myfile.close
    Q'i Q{:xm*]8`123330End Function

    写文本文件的代码

    Function writeorderno(orderno)
    1w2m v.`#u`123330Dim fso, myfile51Testing软件测试网4k K5@7R,g G'Z"{
    Set fso=CreateObject("scrīpting.FileSystemObject")51Testing软件测试网f E m.?+I4qO
    Set myfile=fso.openTextFile("C:\result1.txt",8,false)51Testing软件测试网DT0Z8T P
    myfile.writeline orderno51Testing软件测试网'JlU |:v\/d
    myfile.close51Testing软件测试网4L0n.T@j4WdZ x
    End Function

    3EXCEL文件

    我们可以把EXCEL文件当成数据文件,通过对EXCEL文件的读写操作,来实现数据驱动.

    可以把EXCEL文件当作对象的方式来完成写的操作

    Dim Excel,ExcelSheet
    #gy3h IO1N7_123330Set Excel=CreateObject("Excel.Application")51Testing软件测试网cNQ y B]C
    Set ExcelSheet=CreateObject("Excel.Sheet")51Testing软件测试网#Ua$o;`.|a~F
    ExcelSheet.Application.visible=true51Testing软件测试网o.?$s+` w h
    ExcelSheet.ActiveSheet.Cells(1,1).value=151Testing软件测试网*Y9\Wi)nJ8{/l"A
    ExcelSheet.ActiveSheet.Cells(1,2).value=2
    u,Fy8X6^@#r1C123330ExcelSheet.ActiveSheet.Cells(1,3).value=3
    2y+Fq nA@ S \$p)S8jb123330Excel.Save "C:\test.xls"51Testing软件测试网(^/b9\ ]|k#rc
    Set ExcelSheet=Nothing

    用ADO的方式连接EXCEL文件来做读的操作

    51Testing软件测试网/u j*KH n#WbH1T~Q
    Dim conn,input,filename51Testing软件测试网I9sW8p5s3~ K
    filename="D:\公基本情况(tb_gsgk)-标准格式.xls" '
    } I)Q.o,m;J9v;X123330Set conn= createobject("ADODB.Connection")
    T3p(P8f*s?123330conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Persist Security Info=False;Data Source="&filename&";Extended Properties='Excel 8.0;hdr=yes'"51Testing软件测试网m7|O"}RvA'Vb
    Set input= createobject("ADODB.Recordset")
    %Zj1^"j&ch-}123330input.Open "select  *   from [公基本情况-标准格式$] " ,conn,2,2 
    sZvY3S$l"K123330input.close
    8x{ ][ Q nN`123330Set input=nothing

    4.数据库

    可以利用设计数据表,把测试数据和测试用例放在数据表里,用ADO或者其他任何可以访问连接数据库的方式连接数据库,来实现数据驱动

       Dim res,cmd,sql
    /E1ZbJeX Ac K(O123330     Set Res=createobject("adodb.recordset")51Testing软件测试网 @+Z1e(B#p"W:k
         Set Cmd=createobject("adodb.command")
    S3KUEx'iwAX123330     Cmd.activeconnection="Provider=SQLOLEDB.1;Password=111111;Persist Security Info=True;User ID=sa;Initial Catalog=xhq;Data Source=192.168.191.142"  '这句话是连接数据库的数据源,要做修改51Testing软件测试网4RsA*y4`b
        Cmd.CommandType = 151Testing软件测试网y;ID:]DW:^8i
        sql="selec t * from 表 where name=username"
    PP\xivN123330    Cmd.CommandText = sql
    &dj~"J[\,G G123330    Set res = Cmd.Execute()51Testing软件测试网3c B5Vw3~
        Set res = nothing
    *h0MKs#kY123330    Set cmd.ActiveConnection = nothing51Testing软件测试网*MRZ&kM%dj l&dn4J
        Set Cmd= nothing

    以上四种方法都可以帮助我们实现数据驱动,应该说数据驱动在自动化测试中运用的比较的广泛,才有必要拿出来探讨一下.

  • ado读取excel文件中数据的2种方式

    2007-06-12 19:04:07

    'ado读取excel文件中数据的2种方式

    Dim cnn,rst,strnn
    strnn="Provider=MSDASQL.1;Persist Security Info=False;Data Source=ExcelFiles;"
    strnn=strnn & "Initial Catalog=c:\REDB00000811.xls"
    set cnn=createobject("ADODB.connection")
    set rst=createobject("ADODB.recordset")
    cnn.open strnn
    '使用表名跟美元符号
    rst.open "select * from [sheet1$]",cnn,1,1
    rst.movefirst
    tmp0=rst.fields(0)
    tmp1=rst.fields(1)
    tmp2=rst.fields(2)
    tmp3=rst.fields(3)
    tmp4=rst.fields(4)
    tmp5=rst.fields(5)
    rst.movenext
    tmp6=rst.fields(0)
    rst.close
    '与特定地址 (为示例, $ Sheet 1 [ A1:B10 ]) 指定区域。
    rst.open "select * from [sheet1$A3:E5]",cnn '其实,数据是A4到E5的数据。A3所在的一行数据不                                             '取。
    rst.movefirst
    tmp7=rst.fields(0)
    rst.movenext
    tmp8=rst.fields(0)
    tmp9=rst.fields(4)
    rst.close
    cnn.close
    Set rst=nothing
    Set cnn=nothing
  • 测试运行过程中改变QTP窗口状态

    2007-06-12 19:02:59

    测试脚本的运行过程中,QTP窗口可能会影响测试步骤。
    有时,QTP窗口挡住了测试对象的弹出窗口或者页面控件,造成对象不可见Object is not visible错误。

    在测试脚本的开头部分加入如下代码,就可以让QTP在开始运行时最小化QTP窗口。
    Dim objQTPWin
    Set ōbjQTPWin = GetObject("" , "QuickTest.Application")
    objQTPWin.WindowState = "Minimized"
    Set ōbjQTPWin = Nothing
    其中objQTPWin.WindowState还支持最大化"Maxmized"和恢复"Restored"状态,如果把上面的代码包装成一个函数,就是根据需要在测试运行中随时改变QTP窗口的状态了。

    除了最小化以外,还可以利用QTP窗口对象的Visible属性隐藏QTP窗口。
    Dim objQTPWin
    Set ōbjQTPWin = GetObject("" , "QuickTest.Application")
    objQTPWin.Visible = False
    Set ōbjQTPWin = Nothing
    和最小化窗口不同的是,隐藏窗口以后连Windows任务栏上也不看不到QTP窗口了。
    如果需要显示QTP窗口,应该把Visible属性设置为True。
  • QTP与Oracle数据库链接脚本

    2007-06-12 19:00:48

    1)首先要在控制面板中,加一个odbc数据源。
    (2)在qtp中建立连接和记录集
    set cnn=createobject("adodb.connection")
    set ōbjrsa=createobject("adodb.recordset")
    (3)连接数据库
    cnn.open "provide=msdaora;userid=apts;password=apts;data source=afctwo"
    userid/password,是登陆数据库的用户名和密码,这样数据库就连接上。
    (4)对数据库进行操作。
    objrsa.open "select bustypefullname from bustypeinfo",cnn,3,2
    a=objrsa("bustypefullname").value得到字段bustypefullname的值赋值给了变量a

    需要参考ADO

    http://doc.51windows.net/ado/?url=/ado/dir.htm

    例子:

    '删除网络硬盘下所有的文件夹和文件
    '@userName 用户名
    '@domainName 用户所在域名
    Function delAll(userName, domainName)
     Dim wfType
     Dim var
     wfType = 0  ' 0为该用户的跟目录的起始点
     
     Dim rs,sql,pkey,domainId, userId
     set conn=createobject("adodb.connection")
     set rs =createobject("adodb.recordset")
     
     ' Oracle client is required to be installed on your box
    conn.open= "Provider=OraOLEDB.Oracle.1;Password=umail;Persist Security Info=True;User ID=umailrc;SERVER=192.168.6.245;Data Source=umail;DBQ=umail;"
     sql="select domainid from domain where domainname='" & domainName & "'"
     rs.open sql,conn '执行sql语句
     domainId = rs("domainId")
       rs.close
     sql = "select userid from email_users where username= '" & userName & "' and domainId = '" & domainId &"'"
      rs.open sql,conn
     userId = rs("userid")
       rs.close
     sql = "delete from wfs_files where WF_OWNER_ID = '" & userId &"' and WF_TYPE<>0"
     rs.open sql,conn
     sql = "select count(*) from wfs_files where WF_OWNER_ID = '" & userId &"'"
     rs.open sql, conn
     var = rs(0)
     If var = "1" Then
      reporter.ReportEvent micPass, "清空网络硬盘中所有文件和文件夹", "清空成功"
       conn.close
      set conn=nothing '删除对象
     Else
      reporter.ReportEvent micFail, "清空网络硬盘中所有文件和文件夹", "清空失败"
      
     End If
     
      
    End Function

我的栏目

我的存档

数据统计

  • 访问量: 9320
  • 日志数: 16
  • 建立时间: 2007-06-12
  • 更新时间: 2007-06-21

RSS订阅

Open Toolbar