QTP成长园地

发布新日志

  • Jmeter 脚本增强

    2011-07-05 14:08:58

     

    Script. Enhancement:

     

    1 添加http cookie 管理器( HTTP Cookie Manager   Add->Config Element)

    2添加断言,能够判断web服务器返回是否与期望值一致。Assertion Add->Assertion->Response Assertion  然后添加 Listener->Assertion Result 来查看运行以后的断言结果

    3添加并发时间点 Synchronizing Timer Add->Timer

     

    4参数化设置 Parameterize

    4.1 用户自定义变量 Config Element -> User Define Variables Add 使用该变量时${变量名}

    4.2 从外部文件获取数据 Extract from CSV file      ${__CSVRead(D:\user.txt,0)

    4.3 从之前服务器返回的值中获取数据 Extract from Response   Post processors->Regular Expression Extract 

    Reference Name 注 将返回值存放到该变量中

    Reqular Expression<a href="(.*)/">  注:()内的内容为返回的数值

     

    4.4.利用  JDBC 从外部数据库中获取数据  Config Element-> JDBC Connection Configuration ;Sampler->JDBC Request

     

     

  • 公司局域网内Jmeter脚本录制方法

    2011-07-05 13:23:47

    Jmeter 本身自带的脚本录制机制都说不是很理想,大部分使用者利用badboy录制后再转化为Jmeter脚本.jmx。
    尽管如此,抱着学习Jmeter的态度,还是研究了一下。 Jmeter官方网站上和网络上提供的脚本录制文档都是在非局域网中录制。通过本人的研究和学习,整理了如何在公司局域网内脚本录制方法。
     
     
    公司内网的计算机是通过proxy server访问外网  假设proxy server 为:10.63.240.16, port 为8080
     
    Step1: launch jmeter with proxy server ip and port
    用命令行模式在cmd 里启动jmeter 并且输入 jmeter -H 10.63.240.16 -P 8080
     
    Step2: 在线程组中添加 http Request Default (right click “add -> config element -> Http Request Defaults”)
     
    Protocol – enter “HTTP”    
    Server name – enter “jakarta.apache.org
    Path – leave blank
    Port number – enter “80”
     
    Step3: 在控制台中添加http proxy server ( add -> non-test elements -> Http Proxy Server)
     
    Port field - Enter “9090” 注意这个端口号是可以随意指定的,前提是该端口号没有被其他程序占用,且这个端口要和step4中internet 设置的proxy port要一致!
    Target Controller – click on the drop down and select “test plan > thread group”
    “Patterns to include”. -Enter “.*\.html”.
    Click the “start” and open IE
     
    Step4: 在ie选项中设置 proxy server  
     
    Address – enter “Localhost” or the IP address of your system  (127.0.0.1)
    Port – enter “9090”. 与step3中设置的端口号要一致
     
  • Memory Leak diagnoses

    2009-06-23 15:54:46

    There are a number of counters in the memory category that you can use to spot poor performance that may be caused by insufficient RAM. Here are some of those counters:

    PAGES/SEC – this value counts the number of times per second that the computer must access virtual memory rather than physical memory. A value above 20 is considered to be problematic, but it may indicate a problem with the way that your virtual memory is configured rather than a problem with the physical memory.

    Committed Bytes and Available Bytes – The Committed Bytes counter traces the amount of virtual memory that’s in use. The Available Bytes counter monitors how much memory is actually available. As you might expect, as the Available Bytes counter decreases, paging increases, thus slowing down your machine. If you determine that the Available Bytes are often in short supply, you can correct the problem by adding memory. However, before you do, try watching both counters together as you open and close programs. If the committed bytes don’t decrease and available bytes don’t increase as you close programs, the system may have a memory leak which is caused by a software problem rather than insufficient RAM.

    Pool Nonpaged Bytes and Pool Nonpaged Allocs – Another way to test for memory leaks is to watch these two counters. The Pool Nonpaged Bytes counter counts pages of memory that can’t be moved to virtual memory, but must stay in the physical RAM.  Normally, if this value is too high, you’ll have to add more memory. However, you can watch the Pool Nonpaged Allocs counter to see just how many calls are being made to that portion of the memory. If the number of calls don’t seem to correspond with the number of memory pages, you may have a memory leak rather than insufficient memory.

    Cache Bytes – This counter monitors the amount of memory being used for the file system cache. Anything over 4 MB is considered to be to much. The solution is to add more memory.

  • LR 中lr_set_user的使用

    2009-05-22 10:38:49

    在使用LR的时候,回放服务器报401 Access Denied错误,
    WEB服务器不允许匿名访问,而我们又没有提供正确的用户名/密码时,服务器就会给出这个返回代码。在IIS中,设置IIS的安全属性为不允许匿名访问,此时直接访问的话就会得到以下返回结果:

    HTTP/1.1 401 Access Denied
    Server: Microsoft-IIS/5.1
    Date: Mon, 06 Mar 2006 09:15:55 GMT
    WWW-Authenticate: Negotiate
    WWW-Authenticate: NTLM
    Connection: close
    Content-Length: 3964
    Content-Type: text/html
     
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
    <html dir=ltr>
    ……
    此时跳出对话框,让我们输入用户名和密码,当我们在输入了用户名和密码以后,服务器与客户端会再进行两次对话。首先客户端向服务器索取一个公钥,服务器端会返回一个公钥,二者都用BASE64编码,相应的消息如下(编码部分已经做了处理):
    GET / HTTP/1.1
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
    Accept-Language: zh-cn
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
    Host: 192.168.0.55:8080
    Connection: Keep-Alive
    Authorization: Negotiate ABCDEFG……
     
    HTTP/1.1 401 Access Denied
    Server: Microsoft-IIS/5.1
    Date: Mon, 06 Mar 2006 09:20:53 GMT
    WWW-Authenticate: Negotiate HIJKLMN……
    Content-Length: 3715
    Content-Type: text/html
     
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
    <html dir=ltr>
    ……
    客户端拿到公钥之后使用公钥对用户名和密码进行加密码,然后把加密以后的结果重新发给服务器:
    GET / HTTP/1.1
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
    Accept-Language: zh-cn
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
    Host: 192.168.0.55:8080
    Connection: Keep-Alive
    Authorization: Negotiate OPQRST……
    这样,如果验证通过,服务器端就会把请求的内容发送过来了,也就是说禁止匿名访问的网站会经过三次请求才可以看到页面。但因为客户端浏览器已经缓存了公钥,用同一个浏览器窗口再次请求这个网站上的其它页面时就可以直接发送验证信息,从而一次交互就可以完成了。

    脚本代码如下:


    #include "web_api.h"


    Action()
    {
      int i=0;
      int iLink_Counts=0;
      int iRnd_link=0;
      char buffer[20]="";
      char url[20]=""; 

      web_set_user("192.168.1.111\\administrator", "123456", "192.168.1.111:80");

      web_reg_save_param("Save_Links",
                          "LB=<a href=\"",
           "RB=\"",
                          "ORD=All",
                          LAST); 

     web_url("192.168.1.84",
      "URL=http://192.168.1.111/",
      "Resource=0",
      "RecContentType=text/html",
      "Referer=",
      "Snapshot=t3.inf",
      "Mode=HTML",
      LAST);
      

        //获得参数文件数组大小
        lr_output_message("数组大小:%d",atoi(lr_eval_string("{Save_Links_count}")));
        iLink_Counts=atoi(lr_eval_string("{Save_Links_count}"));

        for(i=1;i<=iLink_Counts;i=i+1)
        {
            sprintf(buffer,"{Save_Links_%d}",i);
            lr_output_message("%s",lr_eval_string(buffer)) ;  
         }   

       srand(time(NULL));

       iRnd_link=rand() % iLink_Counts +1;

       sprintf(buffer,"{Save_Links_%d}",iRnd_link);

      // url="URL="+ lr_eval_string(buffer"); 

       strcpy(url,"URL=");
       strcat(url,lr_eval_string(buffer));


       web_url(lr_eval_string(buffer),
      url,
      "Resource=0",
      "RecContentType=text/html",
      "Referer=",
      "Snapshot=t3.inf",
      "Mode=HTML",
      LAST);

     return 0;
    }

  • LR 从XML文件读取数据(转载)

    2009-05-21 15:47:19

    1.配置文件"c:\\hfeitest.xml"
    <users>
     <user>
      <name>abc0015admin0</name>
      <productId>B001261</productId>
      <unitId>A0000Q1</unitId>
      <customerId>B00141</customerId>
      <supplierId>B001262</supplierId>
      <storeId>B001162</storeId>
      <accountId>B001162</accountId>
      <employeeId>A00010</employeeId>
      <departmentId>A00010</departmentId>
      <paymentMethodId></paymentMethodId>
     </user>
    </users>
    2.代码
    #include "as_web.h"
     
    char *productId;//产品
    char *unitId;//计量单位
    char *customerId;//客户
    char *supplierId;//供应商
    char *storeId;//仓库
    char *accountId;//帐号
    char *employeeId;//职员
    char *departmentId;//部门
    char *paymentMethodId;//付款方式
    //作者:黄飞
    //日期:20080216
    //功能:根据传入用户参数,初始化产品等变量配置,达到动态获取参数的目的
    initData(char userId)
    {
     char *filename = "c:\\hfeitest.xml";
     char *content;
        char buffer[1000];
     long file_stream;
       
        if ((file_stream = fopen(filename, "r" )) == NULL) {
      lr_output_message("Unable to create %s", filename);
      return -1;
        }
     lr_save_string(lr_eval_string(""),"XML_Input_Param");
     while(!feof(file_stream))
     {
      fread(buffer, sizeof(char), 999, file_stream);
      buffer[len] = '\0';
      lr_save_string(buffer,"content");
      lr_save_string(lr_eval_string("{XML_Input_Param}{content}"),"XML_Input_Param");
     }
        fclose(file_stream);
     lr_output_message(lr_eval_string("{XML_Input_Param}"));
     lr_output_message(lr_eval_string("{userId}"));
     lr_xml_get_values("XML={XML_Input_Param}",
              "ValueParam=OutputParam",
              "Query=/users/user[name=\"{userId}\"]/productId",
              LAST);
     
        lr_save_string(lr_eval_string("{OutputParam}"), "productId");

      lr_output_message(lr_eval_string("UserNamaID={userId} and Query productId = {productId}"));

    }
    vuser_init()
    {
     char userId;
     lr_save_string(lr_eval_string("{username}"), "userId");
        initData(userId);
    ...
    }
  • LoadRunner 中关于自定义变量的使用

    2009-05-21 15:31:25

    用lr_save_string或sprintf()都可以
    引用:
    Action()
    {
            char *word="man";
            char para[50];
            lr_save_string (word ,"para");
            //sprintf(para,"%s",word);

            web_url("www.baidu.com",
             "URL=http://www.baidu.com/",
            "Resource=0",
            "RecContentType=text/html",
            "Referer=",
            "Snapshot=t1.inf",
            "Mode=HTML",
            LAST);

            web_submit_form("s",
            "Snapshot=t2.inf",
            ITEMDATA,
            "Name=wd", "Value={para}", ENDITEM,
            EXTRARES,
            "Url=http://s.baidu.com/w.gif?path=http://www.baidu.com/s?wd=123&t=1222584836609", "Referer=http://www.baidu.com/s?wd=123", ENDITEM,
            LAST);

    lr_output_message ("search============> :%s",lr_eval_string ("{para}"));

            return 0;
    }
  • cookie和sessionqu机制区别和如何使用

    2008-01-18 10:03:51

     
     
     在同事的qq 空间上看到一篇关于如何测试cookie的文章,于是搜索了相关内容,找到一篇文章个人感觉还不错,文章讲述了cookie和sessionqu机制区别和如何使用。
    摘自:http://www.java3z.com/cwbwebhome/article/article2/2821.html?id=1397

    由于项目需要,最近用session容器比较多,传载的同时加上了自己的一些理解,不足之处还请大家补充和纠正。
    一、cookie机制和session机制的区别
        具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于才服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上还有其他选择,比如说重写URL和隐藏表单域。
    二、会话cookie和持久cookie的区别
        如果不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览会话期的cookie被称为会话cookie。会话cookie一般不保存在硬盘上而是保存在内存里。
        如果设置了过期时间(setMaxAge(60*60*24)),浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间。存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存的cookie,不同的浏览器有不同的处理方式。
    三、如何利用实现自动登录
    *************************************************************************************
        当用户在某个网站注册后,就会收到一个唯一用户ID的cookie。客户后来重新连接时,这个用户ID会自动返回,服务器对它进行检查,确定它是否为注册用户且选择了自动登录,从而不需给出明确的用户名和密码,就可以访问服务器上的资源。
    *************************************************************************************
    四、如何根据用户的爱好定制站点
    *************************************************************************************
       网站可以使用cookie记录用户的意愿。对于简单的设置,网站可以直接将页面的设置存储在cookie中完成定制。然而对于更复杂的定制,网站只需仅将一个惟一的标识符发送给用户,由服务器端的数据库存储每个标识符对应的页面设置。
    *************************************************************************************
    五、cookie的发送
    *************************************************************************************
    1.创建Cookie对象
    2.设置最大时效
    3.将Cookie放入到HTTP响应报头
       如果你创建了一个cookie,并将他发送到浏览器,默认情况下它是一个会话级别的cookie:存储在浏览器的内存中,用户退出浏览器之后被删除。如果你希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以秒为单位的时间。将最大时效设为0则是命令浏览器删除该cookie。发送cookie需要使用HttpServletResponse的addCookie方法,将cookie插入到一个Set-Cookie HTTP请求报头中。由于这个方法并不修改任何之前指定的Set-Cookie报头,而是创建新的报头,因此我们将这个方法称为是addCookie,而非setCookie。同样要记住响应报头必须在任何文档内容发送到客户端之前设置。
    *************************************************************************************
    六、cookie的读取
    *************************************************************************************
    1.调用request.getCookies
      要获取浏览器发送来的cookie,需要调用HttpServletRequest的getCookies方法,这个调用返回Cookie对象的数组,对应由HTTP请求中Cookie报头输入的值。
    2.对数组进行循环,调用每个cookie的getName方法,直到找到感兴趣的cookie为止,cookie与你的主机(域)相关,而非你的servlet或JSP页面。因而,尽管你的servlet可能只发送了单个cookie,你也可能会得到许多不相关的cookie。
    例如:(login.jsp页面cookie实现用户名userName填写)
    login.jsp:
    <%
       String username = "";
            //从客户端读取硬盘中的cookie文件
            Cookie[] cookies = request.getCookies();
            if(cookies == null){
               username = "";
            }
           else{
              for (int i = 0; i < cookies.length; i++){
                    if ("USERNAME".equalsIgnoreCase(cookies[i].getName())){
                        username = cookies[i].getValue();
                   }
            }
    %>
      
    <form name="login"  method="post" action="login.do">
          <td width="100%" bgcolor="#CCCCCC" colspan="2">
       <p align="left">用户名<br>
                  <input type="text" name="username" value= "<%=username%>">
          </p>
          <p align="left">密 码 <br>
                  <input type="password" name="password">
          </p>
           <p align="left">
             <input type="submit" name="Submit" value="确定">
             <input name="reset" type="reset"  value="取消">
           </p>
    </form>
    LoginAction:
                    //将正确userName放入c1对象,并用"USERNAME"做key标识
                   Cookie c1= new Cookie("USERNAME",logindto.getUsername());
                   //如果不设置时间,则cookie为会话cookie,不写入客户端硬盘
                   c1.setMaxAge(60*60*24);  
                   response.addCookie(c1);  
    *************************************************************************************
    七、如何使用cookie检测初访者
    *************************************************************************************
    A.调用HttpServletRequest.getCookies()获取Cookie数组
    B.在循环中检索指定名字的cookie是否存在以及对应的值是否正确
    C.如果是则退出循环并设置区别标识
    D.根据区别标识判断用户是否为初访者从而进行不同的操作
    *************************************************************************************
    八、使用cookie检测初访者的常见错误
    *************************************************************************************
        不能仅仅因为cookie数组中不存在在特定的数据项就认为用户是个初访者。如果cookie数组为null,客户可能是一个初访者,也可能是由于用户将cookie删除或禁用造成的结果。但是,如果数组非null,也不过是显示客户曾经到过你的网站或域,并不能说明他们曾经访问过你的servlet。其它servlet、JSP页面以及非Java Web应用都可以设置cookie,依据路径的设置,其中的任何cookie都有可能返回给用户的浏览器。
    正确的做法是判断cookie数组是否为空且是否存在指定的Cookie对象且值正确。
    *************************************************************************************
    九、使用cookie属性的注意问题
    *************************************************************************************
    属性是从服务器发送到浏览器的报头的一部分;但它们不属于由浏览器返回给服务器的报头。
    因此除了名称和值之外,cookie属性只适用于从服务器输出到客户端的cookie;服务器端来自于浏览器的cookie并没有设置这些属性。因而不要期望通过request.getCookies得到的cookie中可以使用这个属性。这意味着,你不能仅仅通过设置cookie的最大时效,发出它,在随后的输入数组中查找适当的cookie,读取它的值,修改它并将它存Cookie,从而实现不断改变的cookie值。
    *************************************************************************************
    十、如何使用cookie记录各个用户的访问计数
    *************************************************************************************
    1.获取cookie数组中专门用于统计用户访问次数的cookie的值
    2.将值转换成int型
    3.将值加1并用原来的名称重新创建一个Cookie对象
    4.重新设置最大时效
    5.将新的cookie输出
    *************************************************************************************
    十一、session在不同环境下的不同含义
    *************************************************************************************
      session,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息,比如打电话是从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。然而当session一词与网络协议相关联时,它又往往隐含了“面向连接”和/或“保持状态”这样两个含义。
       session在Web开发环境下的语义又有了新的扩展,它的含义是指一类用来在客户端与服务器端之间保持状态的解决方案。有时候Session也用来指这种解决方案的存储结构。
    *************************************************************************************
    十二、session的机制
    *************************************************************************************
    session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存息。
         但程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否包含了一个session标识-称为session id,如果已经包含一个session id则说明以前已经为此客户创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个,这种情况可能出现在服务端已经删除了该用户对应的session对象,但用户人为地在请求的URL后面附加上一个JSESSION的参数)。如果客户请求不包含session id,则为此客户创建一个session并且生成一个与此session相关联的session id,这个session id将在本次响应中返回给客户端保存。
    *************************************************************************************
    十三、保存session id的几种方式
    *************************************************************************************
    A.保存session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。
    B.由于cookie可以被人为的禁止,必须有其它的机制以便在cookie被禁止时仍然能够把session id传递回服务器,经常采用的一种技术叫做URL重写,就是把session id附加在URL路径的后面,附加的方式也有两种,一种是作为URL路径的附加信息,另一种是作为查询字符串附加在URL后面。网络在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。
    C.另一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。
    *************************************************************************************
    十四、session什么时候被创建
    *************************************************************************************
    一个常见的误解是以为session在有客户端访问时就被创建,然而事实是直到某server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建。
    注意如果JSP没有显示的使用 <% @page session="false"%> 关闭session,则JSP文件在编译成Servlet时将会自动加上这样一条语句 HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的session对象的来历。
    由于session会消耗内存资源,因此,如果不打算使用session,应该在所有的JSP中关闭它。
    *************************************************************************************
    十五、session何时被删除
    *************************************************************************************
    session在下列情况下被删除:
    A.程序调用HttpSession.invalidate()
    B.距离上一次收到客户端发送的session id时间间隔超过了session的最大有效时间
    C.服务器进程被停止
    再次注意关闭浏览器只会使存储在客户端浏览器内存中的session cookie失效,不会使服务器端的session对象失效,除非此时Server端刚好session失效时间到了。
    *************************************************************************************
    十六、URL重写有什么缺点
    *************************************************************************************
        对所有的URL使用URL重写,包括超链接,form的action,和重定向的URL。每个引用你的站点的URL,以及那些返回给用户的URL(即使通过间接手段,比如服务器重定向中的Location字段)都要添加额外的信息。
    这意味着在你的站点上不能有任何静态的HTML页面(至少静态页面中不能有任何链接到站点动态页面的链接)。因此,每个页面都必须使用servlet或JSP动态生成。即使所有的页面都动态生成,如果用户离开了会话并通过书签或链接再次回来,会话的信息都会丢失,因为存储下来的链接含有错误的标识信息-该URL后面的SESSION ID已经过期了。
      
    *************************************************************************************
    十七、使用隐藏的表单域有什么缺点
    *************************************************************************************
         仅当每个页面都是有表单提交而动态生成时,才能使用这种方法。单击常规的<A HREF..>超文本链接并不产生表单提交,因此隐藏的表单域不能支持通常的会话跟踪,只能用于一系列特定的操作中,比如在线商店的结账过程。
    *************************************************************************************
    十八、会话跟踪的基本步骤
    *************************************************************************************
    1.访问与当前请求相关的会话对象
    2.查找与会话相关的信息
    3.存储会话信息
    4.废弃会话数据
    *************************************************************************************
    十九、getSession()/getSession(true)、getSession(false)的区别
    *************************************************************************************
    getSession()/getSession(true):当session存在时返回该session,否则新建一个session并返回该对象
    getSession(false):当session存在时返回该session,否则不会新建session,返回null。
    *************************************************************************************
    二十、如何将信息于会话关联起来
    *************************************************************************************
       setAttribute方法会替换上次setAttribute中设定的值;如果想要在不提供任何代替的情况下移除某个值,则应使用removeAttribute。这个方法会触发所有实现了HttpSessionBindingListener接口的值的valueUnbound方法。
    *************************************************************************************
    二十一、会话属性的类型有什么限制吗
    *************************************************************************************
    通常会话属性的类型只要是Object就可以了。除了null或基本类型,如int,double,boolean。如果要使用基本类型的值作为属性,必须将其转换为相应的封装类对象。
    *************************************************************************************
    二十二、如何废弃会话数据
    *************************************************************************************
    A.只移除自己编写的servlet创建的数据:
        调用removeAttribute(“key”)将指定键关联的值废弃
    B.删除整个会话(在当前Web应用中):
        调用invalidate,将整个会话废弃掉。这样做会丢失该用户的所有会话数据,而非仅仅由我们servlet或JSP页面创建的会话数据
    C.将用户从系统中注销并删除所有属于他(或她)的会话
        调用logOut,将客户从Web服务器中注销,同时废弃所有与该用户相关联的会话(每个Web应用至多一个)。这个操作有可能影响到服务器上多个不同的Web应用。
    *************************************************************************************
    二十三、使用isNew来判断用户是否为新旧用户的错误做法
    *************************************************************************************
    public boolean isNew()方法如果会话尚未和客户程序(浏览器)发生任何联系,则这个方法返回true,这一般是因为会话是新建的,不是由输入的客户请求所引起的。但如果isNew返回false,只不过是说明他之前曾经访问Web应用,并不代表他们曾访问过我们的servlet或JSP页面。
    因为session是与用户相关的,在用户之前访问的每一个页面都有可能创建了会话。因此isNew为false只能说用户之前访问过该Web应用,session可以是当前页面创建,也可能是由用户之前访问过的页面创建的。正确的做法是判断某个session中是否存在某个特定的key且其value是否正确。(待测试)
    *************************************************************************************
    二十四、Cookie的过期和Session的超时有什么区别
    *************************************************************************************
    会话的超时由服务器来维护,它不同于Cookie的失效日期。
    首先,会话一般基于驻留内存的cookie不是持续性的cookie,因而也就没有截至日期。即使截取到JSESSIONID cookie,并为它设定一个失效日期发送出去。浏览器会话和服务器会话也会截然不同。
    *************************************************************************************
    二十五、session cookie和session对象的生命周期是一样的吗
    *************************************************************************************
    当用户关闭了浏览器虽然session cookie已经消失,但session对象仍然保存在服务器端,直到其失效时间。
    *************************************************************************************
    二十六、是否只要关闭浏览器,session就消失了
    *************************************************************************************
    程序一般都是在用户做log off的时候发个指令去删除session,然而浏览器从来不会主动在关闭之前通知服务器它将要被关闭,因此服务器根本不会有机会知道浏览器已经关闭。服务器会一直保留这个会话对象直到它处于非活动状态超过设定的间隔为止。
    之所以会有这种错误的认识,是因为大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个session id就消失了,再次连接到服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的HTTP请求报头,把原来的session id发送到服务器,则再次打开浏览器仍然能够找到原来的session。恰恰是由于关闭浏览器不会导致session被删除,迫使服务器为session设置了一个失效时间,当距离客户上一次使用session的时间超过了这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。
    由此我们可以得出如下结论:
    关闭浏览器,只会是浏览器端内存里的session cookie消失,但不会使保存在服务器端的session对象消失,同样也不会使已经保存到硬盘上的持久化cookie消失。
    补充:那如何做到在浏览器关闭时删除session呢 ?
    严格的讲,做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascrīpt代码window.oncolose来监视浏览器的关闭动作,然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。
    *************************************************************************************
    二十七、打开两个浏览器窗口访问应用程序会使用同一个session还是不同的session
    *************************************************************************************
        通常session cookie是不能跨窗口使用的,当你新开了一个浏览器窗口进入相同页面时,系统会赋予你一个新的session id,这样我们信息共享的目的就达不到了。对session来说是只认id不认人,因此不同的浏览器,不同的窗口打开方式以及不同的cookie存储方式(如会话cookie和持久cookie)都会对这个问题的答案有影响。
    (在IE下测试,打开两个浏览器(不是新建窗口,是直接启动两次浏览器),得到的SessionID也是不一样)
    要实现跨窗口的会话跟踪,我们可以先把session id保存在persistent cookie中(通过设置session的最大有效时间),然后在新窗口中读出来,就可以得到上一个窗口的session id了,这样通过session cookie和persistent cookie的结合我们就可以实现了跨窗口的会话跟踪。(待测试)
    *************************************************************************************
    二十八、如何使用会话显示每个客户的访问次数
    *************************************************************************************
    由于客户的访问次数是一个整型的变量,但session的属性类型中不能使用int,double,boolean等基本类型的变量,所以我们要用到这些基本类型的封装类型对象作为session对象中属性的值.
    但像Integer是一种不可修改(Immutable)的数据结构:构建后就不能更改。这意味着每个请求都必须创建新的Integer对象,之后使用setAttribute来覆盖之前存在的老的属性的值。例如:
    Integer value = (Integer)request.getSession().getAttribute("cout");
    if (value == null){
         value = new CountClass(…); // 新创建一个不可更改对象
    }else{
         value = new CountClass(calculated(value)); // 对value重新计算后创建新的对象
    }
    request.getSession().setAttribute("cout",value);// 使用新创建的对象覆盖原来的老的对象
    *************************************************************************************
    二十九、如何使用会话累计用户的数据
    *************************************************************************************
    使用可变的数据结构,比如数组、List、Map或含有可写字段的应用程序专有的数据结构。通过这种方式,除非首次分配对象,否则不需要调用setAttribute。例如:
    List list_check = (List) request.getSession().getAttribute("ids_go");
    if(list_check = = null){
         list_check = new List(...);
         request.getSession().setAttribute(("ids_go",list_check );
    }else{
          list_check .clear();// 如果已经存在该对象则更新其属性而不需重新设置属性
    }
    List list_check1 = (List) request.getSession().getAttribute("ids_go");
    System.out.println(list_check1.size());//此时size为0
    *************************************************************************************
    三十、不可更改对象和可更改对象在会话数据更新时的不同处理
    *************************************************************************************
    不可更改对象因为一旦创建之后就不能更改,所以每次要修改会话中属性的值的时候,都需要调用setAttribute(“someIdentifier”,newValue)来代替原有的属性的值,否则属性的值不会被更新。
    可更改对象因为其自身一般提供了修改自身属性的方法,所以每次要修改会话中属性的值的时候,只要调用该可更改对象的相关修改自身属性的方法就可以了,这意味着我们就不需要调用setAttribute方法了。
    总结
    session机制本身并不复杂,然而其实现和配置上的灵活性却使得具体情况复杂多变。这也要求我们不能把仅仅某一次的经验或者某一个浏览器,服务器的经验当作普遍适用的。
  • 指定行的数据进行比较

    2007-09-26 14:28:11

    在录制查询功能或者是添加,修改记录时,需要在列表页面比对显示数据是否与预期值一致。因此写一个比对函数。共享一下:

    '-----------------------------------------------------------------
    'function:compare array with data of row in Table
    'call method:
    'Input parameter: obj_SelPage: SelectPage  which is QTP WebList object
    '                 obj_Table:   Table  which is  QTP WebTable object
    '                 pageNo: Index of row in  pagelist which be compared with array
    '                         The first index in the list is numbered 0
    '                 rowNo:  Index of row in  table which be compared with array
    '                         The first index in the table is numbered 1
    '                 data_array: Type array
    '                 num: compare cells  which column is from 1 to num . 

    'For example in QTP:
    '            ExecuteFile  "..\..\Lib\Common.vbs"
    '            Dim  data_array(3)       
    '      data_array(0)=datatable("userID","Action1")
    '            data_array(1)=datatable("Department","Action1")
    '            data_array(2)=datatable("Descrīption","Action1")
    '            data_array(3)=datatable("Account_Expires","Action1")  
    '            call compare_list(obj_SelPage,obj_Table,1,5,data_array)       
    '-----------------------------------------------------------------
    Public Sub  compare_list(obj_SelPage, obj_Table,pageNo,rowNo,data_array,num)

     Dim result
      result=false
     obj_SelPage.Select "#"&pageNo  'go to that  page  in which   row  is compared
     colnum=obj_Table.GetROProperty("cols") 'get  the number of columns in table
     If num>colnum Then
      'MsgBox " input parameter [num] can't greater than colnum"
      Reporter.ReportEvent micFail,  "check_list_result", "input parameter [num] can't greater than colnum"
     
     Else
       For c=1 to num
         If  trim(data_array(c-1))<>trim(obj_Table.GetCellData(rowNo, c)) then
           Reporter.ReportEvent micFail,  "check_list_result", "Expect  result:" & data_array(c-1) & ", Display  Result:" & obj_Table.GetCellData(rowNo, c)
           result=false
         Else
               Reporter.ReportEvent micPass,  "check_list_result", "Expect  result:" & data_array(c-1) & ", Display  Result:" & obj_Table.GetCellData(rowNo, c)
            result=true
         End If
       Next
     End If                     
    End  Sub

     

  • 在qtp中通过string 查找并定位列表页数和行数的VBS函数

    2007-09-26 14:06:55

    今天写了一个qtp中的VBS函数,功能:通过传入字符串来 查找并定位在table列表中的页数和行数的。

    '-----------------------------------------------------------------
    'function:Find pageNo, rowNo of a string in Table
    'call method:define variable pageNo,rowNo in QTP before call this function
    'Input parameter: obj_SelPage: SelectPage  which is QTP WebList object
    '                 obj_Table:   Table  which is  QTP WebTable object
    '                 pageNo:  Return index of page which string is located in list
    '                          The first index in the list is numbered 0
    '                 rowNo:   Return index of row which string is located 
    '                          The first index in the table is numbered 1
    '                 strValue: A string which you will find in Table
    '                 col:     the column of table where string will match with
    '                          The first col in the table is numbered 1
    'Return value: 
    '                  false : not find string in table
    '                  true :  find string in table
    'For example in QTP:
    '            ExecuteFile  "..\..\Lib\Common.vbs"
    '            Dim  ipage,irow
    '            value=FindStrInTab(obj_Select1,obj_Table1,ipage,irow,"jane",1)
    '            If value=true then
    '              msgbox  ipage
    '              msgbox  irow
    '           
    '            End If         
    '-----------------------------------------------------------------
    Public Function FindStrInTab(obj_SelPage, obj_Table, byref pageNo,byref rowNo,strValue, col)
     FindStrInTab=false
     num= obj_SelPage.GetROProperty("items count")
     For i =0 to num-1
        If  obj_SelPage.Exist Then
          obj_SelPage.Select "#"&i
        End If
        If obj_Table.Exist Then
          tabNum=obj_Table.GetROProperty("rows")
        End If

        For j=2 to  tabNum
          If  trim(obj_Table.GetCellData(j, col))= trim(strValue) then
           pageNo=i
           rowNo=j
           FindStrInTab=true
          Exit For            
        End if
      Next
      If  FindStrInTab=true Then
           Exit For 
      End If
     Next
    End Function

  • 导入导出ORACLE数据

    2007-09-26 13:54:23

    在QTP录制过程中,可能需要备份数据来初始化应用。提供以下exp ,imp语句:
    用法:进入DOS命令界面(开始-〉运行-〉cmd),输入 exp imp 语句

    导入导出数据
    导出:exp username/pw @数据库服务名 file=数据库存放路径 [tables=需要导出的表名]

    比如:exp test/test@test  file=G:\test.dmp tables=admin,user

    导入:imp username/pw@数据库服务名 file=数据库存放路径 full=y | fromuser=从备份文件导出指定用户  touser=将数据导入数据库中指定用户

    比如:imp test/test@test  file=G:\test.dmp fromuser=test1 touser=test2

          imp test/test@test  file=G:\test.dmp full=Y

  • 如何将ORACLE中取出的DATE型格式化字符‘MM/DD/YYYY’

    2007-09-26 13:42:01

    如何将ORACLE中取出的DATE型格式化字符‘MM/DD/YYYY’

    调用to_char(date,'MM/DD/YYYY')

    例子:select to_char(EFF,'MM/DD/YYYY') from  CD 

  • QTP中对提示文字设检查点的问题

    2007-09-20 16:58:14

     今天打算录制输入非法数据,检测提示文字是否正确的功能。原本想很简单,只要选中文字设置textcheckpoint 就OK了。 但是在运行时,系统总是报找不到text对象, 原因是系统识别对象是通过text的前后文字来定位的, 然而我录制的页面中text前面是个input框,也就是说text前面的值是在变的,所以在run case 的时候,  text前面的值改变了也就识别不到了。

    解决办法:取文字的上级对象, 我取到的是个TD对象,然后将TD对象设置标准检查点,设置参数。并且在对象库中将该TD对象的innertext属性删除。就OK啦

  • select框中数据与数据库数据进行比较

    2007-09-19 17:15:54

    'Connect Oracle
    ExecuteFile  "..\..\Lib\DBOperation.vbs"
    Dim  Res,Cmd,sql,dbnum,selectnum 

    'select中的数据个数
    selectnum=Browser("Welcome to test").Page("Welcome to test").WebList("select").GetROProperty("items count")

    DBConnect()
    sql ="select  count(*) from admin_groups"
    ExecuteSql(sql)' Execute SQL
    dbnum= Res(0)'数据库中的数据个数

    If  dbnum<>groupnum   Then
        Reporter.ReportEvent micFail,"比对数据库 "," 比对结果与数据库中不一致"
    else
       sql1="select GROUPID  from admin_groups"
       ExecuteSql(sql1)
       i=1
       Do while not Res.eof
         If     trim(Browser("Welcome to test").Page("Welcome to test").WebList("select").GetItem(i))<>trim(Res(0))Then
         Reporter.ReportEvent micFail,"比对数据库"," 比对结果与数据库中不一致 "
         Exit Do
         End If
       Res.movenext
       i=i+1
       Loop

       If   i=dbnum+1   Then
        Reporter.ReportEvent micPass,"比对数据库"," 比对结果与数据库中一致 "
          End If
    End If

    DBClose()

  • QTP连接ORACLE 数据库VBS函数

    2007-09-19 16:49:39

    今天写了个QTP连接ORACLE 数据库函数的VBS,共享一下:

    DBOperation.vbs
    '-----------------------------------------------------------------
    'function:数据库连接
    'call method:在调用文件中先定义Res,Cmd
    'For example:Dim  Res,Cmd
    '             DBConnect()
    '-----------------------------------------------------------------
    Public Sub DBConnect()
          Dim StrCon
          Set Res = CreateObject("ADODB.Recordset")  
          Set Cmd = CreateObject("ADODB.Command")
          'Oracle
          StrCon ="DRIVER={Oracle in OraHome92};SERVER=test;UID=userid;PWD=password;DBQ=test;DBA=W;APA=T;EXC=F;XSM=Default;FEN=T;QTO=T;FRC=10;FDL=10;LOB=T;RST=T;GDE=F;FRL=Lo;BAM=IfAllSuccessful;MTS=F;MDI=Me;CSR=F;FWC=F;PFC=6000;TLO=O;"
          Cmd.activeconnection=StrCon
          Cmd.CommandType =1
    End Sub
    '-----------------------------------------------------------------
    'function:执行SQL语句
    'Input parameter: StrSql
    'For example:Dim sql
    '             sql="select * from admin_groups"
    '             ExecuteSql(StrSql)           
    '---------------------------------------------------------

    Public Sub  ExecuteSql(StrSql)
     Cmd.CommandText=StrSql
     Set  Res = Cmd.Execute()

    End Sub

    '---------------------------------------------------------
    'function:关闭数据库
    'For example:DBClose()
    '---------------------------------------------------------
    Public Sub DBClose()
     Set Res=nothing
     Set Cmd.activeconnection=nothing
     Set Cmd=nothing
    End Sub

    调用例子:

    ExecuteFile  "c:\DBOperation.vbs"

    Dim  Res,Cmd

    DBConnect()  '调用连接数据库函数

    sql ="select  count(*) from admin_groups"

    ExecuteSql(sql) ' 调用执行sql函数

      Do while not Res.eof

          Msgbox(Res(0))

          Res.MoveNext

      Loop

    DBClose()  '调用关闭数据库

     

     

Open Toolbar