<?xml version="1.0" encoding="gb2312" ?>
<rss version="2.0">
<channel>
<title>软件测试工具</title>
<link>http://www.ltesting.nethttp://www.ltesting.net/ceshi/ceshijishu/rjcsgj/</link>
<description>测试技术 / 软件测试工具</description>
<language>zh-cn</language>
<item>
    <title><![CDATA[QTP连接oracle并操作数据库的方法]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/2012/0504/204800.html</link>
    <description><![CDATA[<p>
	　　QTP连接oracle并操作数据库的方法这里以oracle 9i为例子，其他的数据库连接方法是相通的。</p>
<p>
	　　a.首先要在本机建议ODBC数据源，这个属于基本操作，这里不讲，跳过;</p>
<p>
	　　b.获取oracle的连接串的方法，在本地新建一个.txt文件，修改扩展名名*.udl，双击*.udl文件，打开数据库链接属性，定位到&ldquo;提供程序&rdquo;选显卡，选中 oracle的连接 oracle provider for OLE DB,点击下一步，输入数据源，数据库用户名以及密码，点击测试连接，然后用UE或记事本打开*.udl文件，oracle的连接串已经生成了，例如</p>
<p>
	　　Provider=OraOLEDB.Oracle.1;Persist Security Info=False;User ID=test;Data Source=192.168.13.19</p>
<p>
	　　以上就是udl文件生成的oracle连接串</p>
<p>
	　　现在我们需要手动添加一个oracle连接串的密码字段Password，插入到User ID后面，中间用分号隔开;</p>
<p>
	　　即 Provider=OraOLEDB.Oracle.1;Persist Security Info=False;User ID=test;;Password=test;Data Source=192.168.13.19</p>
<p>
	　　c.在qtp中来连接数据库</p>
<p>
	　　Dim Cnn &#39;定义一个数据库连接串</p>
<p>
	　　Set Cnn = CreateObject(&quot;ADODB.Connection&quot;)</p>
<p>
	　　Cnn.ConnectionString =&quot;Provider=OraOLEDB.Oracle.1;Persist Security Info=False;User ID=test;Password=test;Data Source=31&quot;</p>
<p>
	　　Cnn.Open &#39;打开数据库连接</p>
<p>
	　　If Cnn.State = 0 Then &#39;判断数据库连接是否成功</p>
<p>
	　　Reporter.ReportEvent micFail, &quot;testing&quot;, &quot;连接数据库失败&quot;</p>
<p>
	　　else</p>
<p>
	　　Reporter.ReportEvent micPass, &quot;testing&quot;, &quot;连接数据库成功&quot;</p>
<p>
	　　End If</p>
<p>
	　　if Cnn.State&lt;&gt; 0 then</p>
<p>
	　　Set Rs=CreateObject(&quot;ADODB.Recordset&quot;) &#39;生成记录集对象</p>
<p>
	　　strsql =&quot;Select * from t_sys_user&quot; &#39;从数据库中查询t_sys_user的所有记录</p>
<p>
	　　Rs.Open strsql ,Cnn,1,3 &#39;执行sql语句，记录可以自由移动，单数记录处于只读模式</p>
<p>
	　　ydl=Rs(&quot;USER_ID&quot;) &#39;取得字段为USER_ID的记录，游标定义在第一行，所以取得的是该字段所在行的第一行数据</p>
<p>
	　　msgbox ydl</p>
<p>
	　　dim a</p>
<p>
	　　a=&quot;1188&quot; &#39;该a的数据库可以从外部获取，可以是某个页面的某个值，拿来跟数据库中的值做比较</p>
<p>
	　　for i=1 to Rs.Recordcount &#39;开始遍历数据库中所有的行数，Rs.Recordcount表示统计数据库表的总记录数</p>
<p>
	　　if Rs(&quot;USER_ID&quot;)=a then &#39;将数据库中USER_ID字段的值与变量a进行挨个比较，</p>
<p>
	　　msgbox &quot;a在数据库中存在&quot;</p>
<p>
	　　exit for &#39;如果找到记录a，则推出for循环</p>
<p>
	　　else</p>
<p>
	　　Rs.MoveNext &#39;如果数据库中的值与a不相等的话，那么在数据库中将游标移到下一行</p>
<p>
	　　end if</p>
<p>
	　　next</p>
<p>
	　　end if</p>
<p>
	　　RS.close &#39;关闭记录集</p>
<p>
	　　Set RS=nothing &#39;释放对象</p>
<p>
	　　Cnn.Close &#39;关闭数据连接</p>
<p>
	　　Set Cnn=nothing &#39;释放对象</p>
<p>
	　　另外，如果要判断游标是否到最好一行，则用</p>
<p>
	　　For i=1 to Rs.Recordcount</p>
<p>
	　　If Rst.EOF Then</p>
<p>
	　　msgbox &quot;已经达到数据库最后一行记录&quot;</p>
<p>
	　　Exit for</p>
<p>
	　　else</p>
<p>
	　　Rst.MoveNext</p>
<p>
	　　End If</p>
<p>
	　　Next</p>
<p>
	　　、RecordSet对象的详细用法</p>
<p>
	　　RecordSet对象(代表来自基本表或命令执行结果的记录的全集。)</p>
<p>
	　　为了更精确地跟踪数据，要用RecordSet组件创建包含数据的游标，游标就是储存在内存中的数据：</p>
<p>
	　　rs = Server.CreateObject(&quot;ADODB.RecordSet&quot;)</p>
<p>
	　　rs.Open(sqlStr,conn,1,A)</p>
<p>
	　　RS.OPEN SQL,CONN,A,B</p>
<p>
	　　A:</p>
<p>
	　　ADOPENFORWARDONLY(=0)</p>
<p>
	　　只读,且当前数据记录只能向下移动</p>
<p>
	　　ADOPENKEYSET(=1)</p>
<p>
	　　只读,当前数据记录可自由移动</p>
<p>
	　　ADOPENDYNAMIC(=2)</p>
<p>
	　　可读写,当前数据记录可自由移动</p>
<p>
	　　ADOPENSTATIC(=3)</p>
<p>
	　　可读写,当前数据记录可自由移动,可看到新增记录</p>
<p>
	　　B:</p>
<p>
	　　ADLOCKREADONLY(=1)</p>
<p>
	　　缺省锁定类型，记录集是只读的，不能修改记录</p>
<p>
	　　ADLOCKPESSIMISTIC(=2)</p>
<p>
	　　悲观锁定，当修改记录时，数据提供者将尝试锁定记录以确保成功地编辑记录。只要编辑一开始，则立即锁住记录。</p>
<p>
	　　ADLOCKOPTIMISTIC(=3)</p>
<p>
	　　乐观锁定 ，直到用Update方法提交更新记录时才锁定记录。</p>
<p>
	　　ADLOCKBATCHOPTIMISTIC(=4)</p>
<p>
	　　批量乐观锁定，允许修改多个记录，只有调用UpdateBatch方法后才锁定记录。</p>
<p>
	　　当不需要改动任何记录时，应该使用只读的记录集，这样提供者不用做任何检测。</p>
<p>
	　　对于一般的使用，乐观的锁定可能是最好的选择，因为记录只被锁定一小段时间，</p>
<p>
	　　数据在这段时间被更新。这减少了资源的使用。</p>
<p>
	　　在RecordSet组件中，常用的属性和方法有：</p>
<p>
	　　rs.Fields.Count：RecordSet对象字段数。</p>
<p>
	　　rs(i).Name：第i个字段的名称，i为0至rs.Fields.Count-1</p>
<p>
	　　rs(i)：第i个字段的数据，i为0至rs.Fields.Count-1</p>
<p>
	　　rs(&quot;字段名&quot;)：指定字段的数据。</p>
<p>
	　　rs.RecordCount：数据记录总数。</p>
<p>
	　　rs.EOF：是否最后一条记录。</p>
<p>
	　　rs.MoveFirst：指向第一条记录。</p>
<p>
	　　rs.MoveLast：指向最后一条记录。</p>
<p>
	　　rs.MovePrev：指向上一条记录。</p>
<p>
	　　rs.MoveNext：指向下一条记录。#p#分页标题#e#</p>
<p>
	　　rs.GetRows：将数据放入数组中。</p>
<p>
	　　rs.Properties.Count：ADO的ResultSet或Connection的属性个数。</p>
<p>
	　　rs.Properties(item).Name：ADO的ResultSet或Connection的名称。</p>
<p>
	　　rs.Properties：ADO的ResultSet或Connection的值。</p>
<p>
	　　rs.close()：关闭连接。</p>
<p>
	　　Recordset 对象的属性</p>
<p>
	　　1、CursorType 属性</p>
<p>
	　　AdOpenForwardOnly： 仅向前游标，默认值。除了只能在记录中向前滚动外，与静态游标相同。当只需要在记录集中单向移动时，使用它可提</p>
<p>
	　　高性能。(顾名思义，这种游标只能向前移动。然而，由于这种游标功能有限，将它用于系统资源时是非常有效的。)</p>
<p>
	　　AdOpenKeyset： 键集游标。尽管从您的记录集不能访问其他用户删除的记录，但除无法查看其他用户添加的记录外，键集游标与动态游标相似</p>
<p>
	　　。仍然可以看见其他用户更改的数据。(KeySet游标允许你看见自它创建起其他用户所做的修改，然而你却不能看到其他用户增加或删除的记</p>
<p>
	　　录。)</p>
<p>
	　　AdOpenDynamic ：动态游标。可以看见其他用户所作的添加、更改和删除。允许在记录集中进行所有类型的移动，但不包括提供者不支持的书</p>
<p>
	　　签操作。(此类型的游标功能强大同时也是耗费系统资源最多的游标。Dynamic游标可以看到他们保存记录集合的所有变化。使用Dynamic游标</p>
<p>
	　　的用户可以看到其他用户所做的编辑、增加、删除。如果数据提供者允许这种类型的游标，那么它是通过每隔一段时间从数据源重取数据来支</p>
<p>
	　　持这种可视性的。毫无疑问这会需要很多的资源。 )</p>
<p>
	　　AdOpenStatic：静态游标。可以用来查找数据或生成报告的记录集合的静态副本。另外，对其他用户所作的添加、更改或删除不可见。</p>
<p>
	　　(Static类游标只是数据的一幅快照。这就是说，它无法看到自它创建以后其他用户对RecordSet所做的修改。采用这类游标你可以向前和向后</p>
<p>
	　　航行。由于其功能简单，资源的需求比Dynamic要小! )</p>
<p>
	　　需要注意的是：一旦打开RecordSet，你就无法改变CursorType属性。但是，如果你首先关闭RecordSet，改变CursorType属性，然后重新打开</p>
<p>
	　　RecordSet，那么你仍可以有效地改变游标的类型!</p>
<p>
	　　2、LockType 属性</p>
<p>
	　　在任何同时可被多用户修改的数据库应用程序中，你必须处理可能发生的多个用户同时对同一条记录进行操作时的情况。当这种情况出现时，</p>
<p>
	　　数据的完整性就会受到威胁，这是因为一个用户可能会在不自觉地在保存自己所做的修改时覆盖他人的修改。到时候你会觉得自己好象是没有</p>
<p>
	　　做事。为了处理这种情况。ADO允许你在对RecordSet对象进行更新时决定并发事件控制的类型，当一个用户编辑时，如何由他对记录进行锁定</p>
<p>
	　　。这就是由LockType属性所决定的。这个属性有四个值：</p>
<p>
	　　adLockReadonly：默认值，只读。无法更改数据。(这是RecodSet的默认值，如果你把锁定的方式设为该值，那么你将不能更新 Recordset。</p>
<p>
	　　)</p>
<p>
	　　adLockPessimistic：保守式记录锁定(逐条)。提供者执行必要的操作确保成功编辑记录，通常采用编辑时立即锁定数据源的记录的方式。(</p>
<p>
	　　如果设置为此类锁定，记录被锁定，且只有在编辑开始到将记录更新的提交给数据提供者这段时间内进行编辑的用户才可以访问! )</p>
<p>
	　　adLockOptimistic：开放式记录锁定(逐条)。提供者使用开放式锁定，只在调用 Update 方法时锁定记录。(只有在将数据提交给数据提供</p>
<p>
	　　者的那一瞬间才把记录锁定。)</p>
<p>
	　　adlockBatchOptimistic：开放式批更新。用于与立即更新模式相反的批更新模式。(设定为这种类型的锁定制式将被称为批量更新模式的</p>
<p>
	　　RecordSet。 可以加快更新RecordSet修改数据的速度，但因为同时更新多个记录，它也会恶化与并发访问相关的问题! )</p>
<p>
	　　3、AbsolutePage 属性</p>
<p>
	　　AbsolutePage属性设定当前记录的位置是位于哪一页的页数编号;使用PageSize属性将Recordset对象分割为逻辑上的页数，每一页的记录数为</p>
<p>
	　　PageSize(除了最后一页可能会有少于PageSize的记录数)。这里必须注意并不是所有的数据提供者都支持此项属性，因此使用时要小心。</p>
<p>
	　　与AbsolutePosition属性相同，AbsolutePage属性是以1为起始的，若当前记录为Recordset的第一行记录，AbsolutePage为1。可以设定</p>
<p>
	　　AbsolutePage属性，以移动到一个指定页的第一行记录位置。</p>
<p>
	　　4、AbsolutePosition属性</p>
<p>
	　　若您需要确定目前指标在RecordSet中的位置，您可以用AbsolutePosition属性。</p>
<p>
	　　AbsolutePosition属性的数值为目前指标相对於第一笔的位置，由1算起，即第一笔的AbsolutePosition为1。</p>
<p>
	　　注意,在存取RecordSet时，无法保证RecordSet每次都以同样的顺序出现。</p>
<p>
	　　若要启用AbsolutePosition，必须先设定为使用用户端cursor(指针)：rs.CursorLocation=3</p>
<p>
	　　5、PageCount属性</p>
<p>
	　　使用PageCount属性，决定Recordset对象包括多少&ldquo;页&rdquo;的数据。这里的&ldquo;页&rdquo;是数据记录的集合，大小等于PageSize属性的设定，即使最后</p>
<p>
	　　一页的记录数比PageSize的值少，最后一页也算是PageCount的一页。必须注意也并不是所有的数据提供者都支持此项属性。</p>
<p>
	　　6、PageSize属性</p>
<p>
	　　PageSize属性是决定ADO存取数据库时如何分页显示的关键，使用它就可以决定多少记录组成一个逻辑上的&ldquo;一页&rdquo;。设定并建立一个页的大小</p>
<p>
	　　，从而允许使用AbsolutePage属性移到其它逻辑页的第一条记录。PageSize属性能随时被设定。</p>
<p>
	　　7、RecordCount属性</p>
<p>
	　　这也是一个非常常用和重要的属性，我们常用RecordCount属性来找出一个Recordset对象包括多少条记录。使用 RecordCount 属性可确定</p>
<p>
	　　Recordset 对象中记录的数目。ADO 无法确定记录数时，或者如果提供者或游标类型不支持 RecordCount，则该属性返回 &ndash;1。读已关闭的#p#分页标题#e#</p>
<p>
	　　Recordset 上的 RecordCount 属性将产生错误。Recordset 对象的游标类型会影响是否能够确定记录的数目。对仅向前游标，RecordCount 属</p>
<p>
	　　性将返回 -1，对静态或键集游标返回实际计数，对动态游标取决于数据源返回 -1 或实际计数。</p>
<p>
	　　8、BOF与EOF属性</p>
<p>
	　　通常我们在ASP程序中编写代码来检验BOF与EOF属性，从而得知目前指标所指向的RecordSet的位置，使用BOF与EOF属性，可以得知一个</p>
<p>
	　　Recordset对象是否包含有记录或者得知移动记录行是否已经超出该Recordset对象的范围。</p>
<p>
	　　若当前记录的位置是在一个Recordset对象第一行记录之前时，BOF属性返回true，反之则返回false。</p>
<p>
	　　若当前记录的位置是在一个Recordset对象最后一行记录之后时，EOF属性返回true，反之则返回false。</p>
<p>
	　　(BOF与EOF都为True表示在RecordSet里没有任何记录。)</p>
<p>
	　　9、Filter 属性</p>
<p>
	　　为 Recordset 中的数据指定筛选条件，使用 Filter 属性可选择性地屏蔽 Recordset 对象中的记录，已筛选的 Recordset 将成为当前游标。</p>
<p>
	　　这将影响基于当前游标返回值的其他属性，如 AbsolutePosition、AbsolutePage、RecordCount 和 PageCount，因为将 Filter 属性设置为特</p>
<p>
	　　定值可将当前记录移动到满足新值的第一个记录。</p>
<p>
	　　这属性我认为相当有用处，有的时候我们打开了Recordset进行了某些判断以后我们还想过滤记录也就是重新调整 sql 语句，难道我们关闭</p>
<p>
	　　Recordset再用新的SQL语句打开?不是，我们用Filter属性进行过滤，比如说</p>
<p>
	　　rs.open exec,conn,1,1</p>
<p>
	　　if .... then rs.filter=&quot;name=&#39;xxx&#39;&quot;</p>
<p>
	　　而不是</p>
<p>
	　　rs.open exec,conn,1,1</p>
<p>
	　　if ... then</p>
<p>
	　　rs.close</p>
<p>
	　　exec=exec&amp;&quot; where name=&#39;xxx&#39;&quot;</p>
<p>
	　　rs.open exec,conn,1,1</p>
<p>
	　　end if</p>
<p>
	　　实际上再很多地方不得不用到Filter，在以后的ASP技巧中会说到，大家也可以想一下。</p>
<p>
	　　明天继续说Recordset对象的方法。</p>
<p>
	　　Recordset对象的方法</p>
<p>
	　　1、AddNew 方法</p>
<p>
	　　创建可更新 Recordset 对象的新记录。</p>
<p>
	　　recordset.AddNew FieldList, Values</p>
<p>
	　　FieldList 可选。新记录中字段的单个名称、一组名称或序号位置。</p>
<p>
	　　Values 可选。新记录中字段的单个或一组值。如果 Fields 是数组，那么 Values 也必须是有相同成员数的数组，否则将发生错误。字段名</p>
<p>
	　　称的次序必须与每个数组中的字段值的次序相匹配。</p>
<p>
	　　我们一般是</p>
<p>
	　　rs.addnew</p>
<p>
	　　rs(&quot;xx&quot;)=xx</p>
<p>
	　　rs(&quot;xx&quot;)=xx</p>
<p>
	　　rs.update</p>
<p>
	　　需要注意的是在立即更新模式(调用 Update 方法时提供者会立即将更改写入基本数据源)下，调用不带参数的 AddNew 方法可将 EditMode</p>
<p>
	　　属性设置为 adEditAdd。提供者将任何字段值的更改缓存在本地。调用 Update 方法可将新记录传递到数据库并将 EditMode 属性重置为</p>
<p>
	　　adEditNone。如果传送了 Fields 和 Values 参数，ADO 则立即将新记录传递到数据库(无须调用 Update)，且 EditMode 属性值没有改变</p>
<p>
	　　(adEditNone)。</p>
<p>
	　　可能大家会问在ASP中使用ADO的AddNew方法和直接使用&ldquo;Insert into...&rdquo;语句有和不同?那种方式更好?答：ADO的AddNew方法只是将</p>
<p>
	　　&ldquo;Insert into &rdquo;语句封装了起来，所以，当对大量数据进行操作的时候，直接使用SQL语句将会大大加快存取数据的速度，因为他减少了ADO</p>
<p>
	　　的&ldquo;翻译&rdquo;时间。</p>
<p>
	　　2、Delete 方法</p>
<p>
	　　删除当前记录或记录组。</p>
<p>
	　　recordset.Delete AffectRecords</p>
<p>
	　　AffectRecords AffectEnum 值，确定 Delete 方法所影响的记录数目，该值可以是下列常量之一。</p>
<p>
	　　AdAffectCurrent 默认。仅删除当前记录。</p>
<p>
	　　AdAffectGroup 删除满足当前 Filter 属性设置的记录。要使用该选项，必须将 Filter 属性设置为有效的预定义常量之一。</p>
<p>
	　　adAffectAll 删除所有记录。</p>
<p>
	　　adAffectAllChapters 删除所有子集记录。</p>
<p>
	　　使用立即更新模式将在数据库中进行立即删除，否则记录将标记为从缓存删除，实际的删除将在调用 Update 方法时进行。</p>
<p>
	　　3、Update 方法</p>
<p>
	　　保存对 Recordset 对象的当前记录所做的所有更改</p>
<p>
	　　recordset.Update Fields, Values</p>
<p>
	　　Fields 可选。变体型，代表单个名称;或变体型数组，代表需要修改的字段(一个或多个)名称及序号位置。</p>
<p>
	　　Values 可选。变体型，代表单个值;或变体型数组，代表新记录中字段(单个或多个)值。</p>
<p>
	　　如果希望取消对当前记录所做的任何更改或者放弃新添加的记录，则必须调用 CancelUpdate 方法。</p>
<p>
	　　4、CancelUpdate 方法</p>
<p>
	　　recordset.CancelUpdate</p>
<p>
	　　使用 CancelUpdate 方法可取消对当前记录所作的任何更改或放弃新添加的记录。在调用 Update 方法后将无法撤消对当前记录或新记录所做</p>
<p>
	　　的更改，如果在调用 CancelUpdate 方法时添加新记录，则调用 AddNew 之前的当前记录将再次成为当前记录。如果尚未更改当前记录或添加</p>
<p>
	　　新记录，调用 CancelUpdate 方法将产生错误。</p>
<p>
	　　5、Find 方法</p>
<p>
	　　搜索 Recordset 中满足指定标准的记录。如果满足标准，则记录集位置设置在找到的记录上，否则位置将设置在记录集的末尾。</p>
<p>
	　　Find (criteria, SkipRows, searchDirection, start)</p>
<p>
	　　criteria 字符串，包含指定用于搜索的列名、比较操作符和值的语句。</p>
<p>
	　　SkipRows 可选，长整型值，其默认值为零，它指定当前行或 start 书签的位移以开始搜索。</p>
<p>
	　　searchDirection 可选的 SearchDirectionEnum 值，指定搜索应从当前行还是下一个有效行开始。其值可为 adSearchForward 或#p#分页标题#e#</p>
<p>
	　　adSearchBackward。搜索是在记录集的开始还是末尾结束由 searchDirection 值决定。</p>
<p>
	　　start 可选，变体型书签，用作搜索的开始位置。</p>
<p>
	　　criteria &ldquo;比较操作符&rdquo;可以是&ldquo;&gt;&rdquo;(大于)、&ldquo;&lt;&rdquo;(小于)、&ldquo;=&rdquo;(等于)、&ldquo;&gt;=&rdquo;(大于或等于)、&ldquo;&lt;=&rdquo;(小于或等于)、&ldquo;&lt;&gt;&rdquo;</p>
<p>
	　　(不等于)或&ldquo;like&rdquo;(模式匹配)。 criteria 中的值可以是字符串、浮点数或者日期。字符串值以单引号分界(如&ldquo;state = &#39;WA&#39;&rdquo;)。</p>
<p>
	　　日期值以&ldquo;#&rdquo;(数字记号)分界(如&ldquo;start_date &gt; #7/22/97#&rdquo;)。</p>
<p>
	　　需要注意的是find是不支持多字段。但是可以用filter实现。&quot;name=&#39;abc&#39;&quot;AND &quot;city=&#39;sh&#39;&quot; 是不允许的</p>
<p>
	　　6、Move 方法</p>
<p>
	　　移动 Recordset 对象中当前记录的位置</p>
<p>
	　　recordset.Move NumRecords, Start</p>
<p>
	　　NumRecords 带符号长整型表达式，指定当前记录位置移动的记录数。</p>
<p>
	　　Start 可选，字符串或变体型，用于计算书签。也可为下列值之一：</p>
<p>
	　　AdBookmarkCurrent 默认。从当前记录开始。</p>
<p>
	　　AdBookmarkFirst 从首记录开始。</p>
<p>
	　　AdBookmarkLast 从尾记录开始。</p>
<p>
	　　需要注意的是：</p>
<p>
	　　(1)如果 NumRecords 参数大于零，则当前记录位置将向前移动(向记录集的末尾)。如果 NumRecords 小于零，则当前记录位置向后移动(</p>
<p>
	　　向记录集的开始)。</p>
<p>
	　　(2)从空的 Recordset 对象调用 Move 方法将产生错误。</p>
<p>
	　　(3)如果 Move 调用将当前记录位置移动到首记录之前，则 ADO 将当前记录放置在记录集(BOF 为 True)的首记录之前。在 BOF 属性已经</p>
<p>
	　　为 True 时试图向后移动将产生错误;如果 Move 调用将当前记录位置移动到尾记录之后，则 ADO 将当前记录放置在记录集(EOF 为 True)</p>
<p>
	　　的尾记录之后。在 EOF 属性已经为 True 时试图向前移动将产生错误。</p>
<p>
	　　7、MoveFirst、MoveLast、MoveNext 和 MovePrevious 方法</p>
<p>
	　　在指定 Recordset 对象中移动到第一个、最后一个、下一个或前一个记录并使该记录成为当前记录。</p>
<p>
	　　recordset.{MoveFirst | MoveLast | MoveNext | MovePrevious}</p>
<p>
	　　需要注意的是：</p>
<p>
	　　(1)使用 MoveNext 方法将当前记录向前移动一个记录(向 Recordset 的底部)。如果最后一个记录是当前记录并且调用 MoveNext 方法，</p>
<p>
	　　则 ADO 将当前记录设置到 Recordset (EOF 为 True)的尾记录之后。当 EOF 属性已经为 True 时试图向前移动将产生错误。</p>
<p>
	　　(2)使用 MovePrevious 方法将当前记录位置向后移动一个记录(向记录集的顶部)。Recordset 对象必须支持向后游标移动;否则方法调用</p>
<p>
	　　将产生错误。如果首记录是当前记录并且调用 MovePrevious 方法，则 ADO 将当前记录设置在 Recordset (BOF 为 True)的首记录之前。而</p>
<p>
	　　BOF 属性为 True 时向后移动将产生错误。</p>
<p>
	　　8、Clone 方法</p>
<p>
	　　创建与现有 Recordset 对象相同的复制 Recordset 对象。可选择指定该副本为只读。</p>
<p>
	　　Set rstDuplicate = rstOriginal.Clone</p>
<p>
	　　rstDuplicate 对象变量，标识正在创建的复制 Recordset 对象。</p>
<p>
	　　rstOriginal 对象变量，标识要被复制的 Recordset 对象。</p>
<p>
	　　使用 Clone 方法可创建多个 Recordset 对象副本，这对于希望在给定的记录组中保留多个当前记录十分有用。使用 Clone 方法比使用与初始</p>
<p>
	　　定义相同的定义创建和打开新 Recordset 对象要有效得多。</p>
<p>
	　　也就是说</p>
<p>
	　　rs.open exec,conn,1,1</p>
<p>
	　　rs2.open exec,conn,1,1</p>
<p>
	　　应该这么改写</p>
<p>
	　　rs.open exec,conn,1,1</p>
<p>
	　　rs2=rs.clone</p>
<p>
	　　需要注意的是：</p>
<p>
	　　(1)新创建副本的当前记录将设置为首记录。</p>
<p>
	　　(2)关闭原始 Recordset 时并不关闭它的副本，而关闭某个副本也将不关闭原始 Recordset 或任何其他副本。</p>
<p>
	　　9、Close 方法</p>
<p>
	　　关闭打开的对象及任何相关对象。</p>
<p>
	　　object.Close</p>
<p>
	　　需要注意的是：</p>
<p>
	　　(1)使用 Close 方法可关闭Recordset 对象以便释放所有关联的系统资源。关闭对象并非将它从内存中删除，可以更改它的属性设置并且在</p>
<p>
	　　此后再次打开。要将对象从内存中完全删除，可将对象变量设置为 Nothing。</p>
<p>
	　　(2)如果正在立即更新模式下进行编辑，调用 Close 方法将产生错误，应首先调用 Update 或 CancelUpdate 方法。</p>
<p>
	　　10、Open 方法，为什么最后说这个，因为前面的各项属性方法没有弄清楚，我们是不会理解CursorType参数的</p>
<p>
	　　recordset.Open Source, ActiveConnection, CursorType, LockType, Options</p>
<p>
	　　Recordset对象可以通过Source属性来连接Command对象。Source参数可以是一个Command对象名称、一段SQL命令、一个指定的数据表名称或是</p>
<p>
	　　一个Stored Procedure。假如省略这个参数，系统则采用Recordset对象的Source属性。ActiveConnection</p>
<p>
	　　Recordset对象可以通过ActiveConnection属性来连接Connection对象。这里的ActiveConnection可以是一个Connection对象或是一串包含数据</p>
<p>
	　　库连接信息(ConnectionString)的字符串参数。CursorType</p>
<p>
	　　Recordset对象Open方法的CursorType参数表示将以什么样的游标类型启动数据，包括adOpenForwardOnly、adOpenKeyset、adOpenDynamic及ad</p>
<p>
	　　OpenStatic，分述如下：</p>
<p>
	　　--------------------------------------------------------------</p>
<p>
	　　常数 常数值 说明</p>
<p>
	　　-------------------------------------------------------------</p>
<p>
	　　adOpenForwardOnly 0 缺省值，启动一个只能向前移动的游标(Forward Only)。#p#分页标题#e#</p>
<p>
	　　adOpenKeyset 1 启动一个Keyset类型的游标。</p>
<p>
	　　adOpenDynamic 2 启动一个Dynamic类型的游标。</p>
<p>
	　　adOpenStatic 3 启动一个Static类型的游标。</p>
<p>
	　　-------------------------------------------------------------</p>
<p>
	　　以上几个游标类型将直接影响到Recordset对象所有的属性和方法，以下列表说明他们之间的区别。</p>
<p>
	　　Recordset属性 adOpenForwardOnly adOpenKeyset adOpenDynamic adOpenStatic</p>
<p>
	　　AbsolutePage 不支持 不支持 可读写 可读写</p>
<p>
	　　AbsolutePosition 不支持 不支持 可读写 可读写</p>
<p>
	　　BOF 只读 只读 只读 只读</p>
<p>
	　　CursorType 可读写 可读写 可读写 可读写</p>
<p>
	　　EOF 只读 只读 只读 只读</p>
<p>
	　　Filter 可读写 可读写 可读写 可读写</p>
<p>
	　　LockType 可读写 可读写 可读写 可读写</p>
<p>
	　　PageCount 不支持 不支持 只读 只读</p>
<p>
	　　PageSize 可读写 可读写 可读写 可读写</p>
<p>
	　　RecordCount 不支持 不支持 只读 只读</p>
<p>
	　　AddNew 支持 支持 支持 支持</p>
<p>
	　　CancelBatch 支持 支持 支持 支持</p>
<p>
	　　CancelUpdate 支持 支持 支持 支持</p>
<p>
	　　Close 支持 支持 支持 支持</p>
<p>
	　　Delete 支持 支持 支持 支持</p>
<p>
	　　Move 不支持 支持 支持 支持</p>
<p>
	　　MoveFirst 支持 支持 支持 支持</p>
<p>
	　　MoveLast 不支持 支持 支持 支持</p>
<p>
	　　MoveNext 支持 支持 支持 支持</p>
<p>
	　　MovePrevious 不支持 支持 支持 支持</p>
<p>
	　　Open 支持 支持 支持 支持</p>
<p>
	　　Update 支持 支持 支持 支持</p>
<p>
	　　UpdateBatch 支持 支持 支持 支持</p>
<p>
	　　--------------------------------------------------------------</p>
<p>
	　　Recordset对象Open方法的LockType参数表示要采用的Lock类型，如果忽略这个参数，那么系统会以Recordset对象的LockType属性为预设值。</p>
<p>
	　　LockType参数包含adLockReadOnly、adLockPrssimistic、adLockOptimistic及adLockBatchOptimistic等，分述如下：</p>
<p>
	　　常数 常数值 说明</p>
<p>
	　　--------------------------------------------------------------</p>
<p>
	　　adLockReadOnly 1 缺省值，Recordset对象以只读方式启动，无法运行AddNew、Update及Delete等方法</p>
<p>
	　　adLockPrssimistic 2 当数据源正在更新时，系统会暂时锁住其他用户的动作，以保持数据一致性。</p>
<p>
	　　adLockOptimistic 3 当数据源正在更新时，系统并不会锁住其他用户的动作，其他用户可以对数据进行增、删、改的操作。</p>
<p>
	　　adLockBatchOptimistic 4 当数据源正在更新时，其他用户必须将CursorLocation属性改为adUdeClientBatch才能对数据进行增、删、改的操</p>
<p>
	　　作。</p>
<p>
	　　需要注意的是：</p>
<p>
	　　如果数据源没有返回记录，那么提供者将 BOF 和 EOF 属性同时设置为 True，并且不定义当前记录位置。如果游标类型允许，仍然可以将新数</p>
<p>
	　　据添加到该空 Recordset 对象。</p>
]]></description>
    <pubDate>Fri, 04 May 2012 10:02:15 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>QuickTestPro</category>
    <author>胡志超　　</author>
    <comments>测试窝</comments>
</item>
<item>
    <title><![CDATA[利用 Rational ClearCase 和 STAF 实现自动化脚本的自动更新和编]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/2012/0319/204432.html</link>
    <description><![CDATA[<p>
	　　简述</p>
<p>
	　　自动化测试在软件测试中的地位显得越来越重要，Rational Functional Tester(RFT)是跨平台的 GUI 自动测试工具，可以自动测试基于 Java、HTML 和 .Net 的应用程序。本文主要介绍如何利用 IBM Rational ClearCase, Ant 以及 STAF 对 RFT 脚本来实现自动编译和检测过程的自动化。</p>
<p>
	　　回页首</p>
<p>
	　　场景介绍</p>
<p>
	　　Lotus Automator(简称 LA)是一款基于 Linux 的自动化控制工具。通过使用 LA 测试人员可以登陆 Web 页面实施软件自动下载、安装配置、定制自动操作服务、管理和执行自动化测试。这一测试框架所需环境有 LA server、RFT clients、STAF。下面我们首先来介绍一下某测试团队基于 LA 这一框架下的自动化测试的场景及流程。</p>
<p>
	　　图 1. 当前自动化测试流程</p>
<center>
	<img alt="图 1. 当前自动化测试流程" border="1" height="345" src="/uploads/allimg/120319/1011493146-0.png" width="572" /></center>
<p>
	　　如图 1，测试人员通过 LA Web 页面提交任务到给 LA server，LA 通过 STAF 控制测试机上的 RFT 执行自动化脚本的更新，然后执行脚本，收集脚本执行信息以及发送邮件报告。</p>
<p>
	　　LA Admin 为了保证 LA 上的脚本的更新，会在本机安装好 RFT 和 ClearCase Remote Client(CCRC)，通过 CCRC 手动更新 ClearCase 上的最新代码，通过本机 RFT 编译脚本，然后打包压缩放到 LA 服务器上。如果有编译错误也是 LA Admin 发送邮件去通知脚本开发人员。</p>
<p>
	　　随着测试任务的加重和项目的扩大，当前这一流程的缺点越来越显示出来。每天有大量的代码更新，LA Admin 耗费了大量的时间在维护 LA Server 上的工作，重复性极高。测试工作也非常依赖于 LA Admin，否则就不能及时得到最新的脚本和最新的测试结果。</p>
<p>
	　　于是在这一场景中，测试团队经过分析提出了这样一个需求，如何将 LA Server 上的测试脚本能够每天进行自动更新和编译，并且最新的脚本中不能有编译错误，这样才能保证测试机上拿到的脚本也是最新的，也不会影响到测试任务的执行。同时也节省了 LA Admin 维护更新代码的时间，把每天重复性的工作自动化起来。</p>
<p>
	　　本文中就是要实现这样两个目标，一是自动更新没有编译错误的脚本到 LA Server 上，二是如果发现有编译错误，及时通知到脚本的开发人员要求及时修复编译错误。</p>
<p>
	　　回页首</p>
<p>
	　　工具简介</p>
<p>
	　　本文主要利用版本控制工具 Rational ClearCase，开源软件 STAF 和编译工具 Ant 来实现上述场景中的两个目标。</p>
<p>
	　　现在先简要介绍下这几个工具在本文中的应用。</p>
<p>
	　　ClearCase: ClearCase(CC) 主要应用于复杂产品的并行开发、发布和维护，其功能划分为四个范畴：版本控制、工作空间管理(Workspace Management)、构造管理(Build Management)、过程控制(Process Control)。本文中的 ClearCase 主要用于版本控制，代码的更新和查询代码更新者，以及创建代码的 baseline 以备后用。</p>
<p>
	　　STAF：STAF(Software Testing Automation Framework)是开源、跨平台、支持多语言的自动化测试框架，它的设计核心理念是称为&ldquo;服务&rdquo;的可重用组件(例如，进程调用，资源管理，日志和监控等)。STAF 提供的常用服务有程序调用服务(Process Service)，文件系统服务(FileSystem Service)，日志服务(Log Service)，资源池服务(ResPool Service)，监控服务(Monitor Service)，信号量服务(Sem Service)，压缩服务(Zip Service)，Ping 服务(Ping Service)，变量服务(Var Service)等等。</p>
<p>
	　　在本文中 STAF 除了用来作为测试机客户端和 LA 服务器通信之外，主要还用到定时服务(Cron Service)来定时启动服务，程序调用服务(Process Service)调用 Java 外部程序，邮件服务(Email Service)来发送邮件，压缩服务(Zip Service)来打包脚本上传到 LA 服务器。像 Cron 和 Email 这些服务需要 STAF V3 以上的版本。</p>
<p>
	　　ANT：Ant 是一种基于 Java 的 build 工具。当开始一个新的项目时，首先应该编写好 Ant 构建文件。构建文件定义了构建过程，并被团队开发中每个人使用。Ant 构建文件默认命名为 build.xml，也可以取其他的名字。这里主要用它来编译 RFT 脚本。</p>
<p>
	　　回页首</p>
<p>
	　　流程实现与步骤</p>
<p>
	　　现在我们就基于上面提到的这些工具来实现对 RFT 脚本进行自动更新和编译检错。</p>
<p>
	　　我们将用一台安装好 ClearCase Client 的机器替代 LA Admin 的工作，在这台机器上需要准备以下环境：</p>
<p>
	　　安装 ClearCase Client 并且加入到你所在的项目当中去</p>
<p>
	　　安装 STAF</p>
<p>
	　　安装 Ant</p>
<p>
	　　图 2. 改进后的自动化测试流程</p>
<center>
	<img alt="图 2. 改进后的自动化测试流程" border="1" height="430" src="/uploads/allimg/120319/1011493460-1.png" width="560" /></center>
<p>
	　　改进后的方案如图 2，从图 2 中我们可以看到 QE 的工作流程没有变，仍然跟以前一样通过 LA Web 页面提交任务到 LA 服务器上来控制测试机上的测试工作。改进的是把 LA Admin 的工作从这个流程当中去掉了。取而代之的是一台装好 ClearCase Client，STAF，Ant 的机器。利用 Ant 编译测试脚本，Cleartool 自动更新 View，找到发生编译错误的测试脚本的 owner，并且新增了一个创建每日的 baseline 的功能，方便找回任意时间的 baseline 代码。利用 STAF 开启定时服务，启动脚本进行测试代码的更新编译和上传，无需人工干预。</p>
<p>
	　　图 3. 测试脚本更新和编译流程</p>
<center>
	<img alt="图 3. 测试脚本更新和编译流程" border="1" height="330" src="/uploads/allimg/120319/10114923F-2.png" width="320" /></center>
<p>
	　　具体的更新和编译流程如图 3，下面我们来逐步解析下这个流程：</p>
<p>
	　　一、Update view(Cleartool)</p>
<p>
	　　首先是要通过 ClearCase Client 端来更新到最新的测试脚本，命令如下：</p>
<table border="0" cellpadding="0" cellspacing="0" sizcache="2" sizset="2" summary="This table contains a code listing." width="100%">
	<tbody sizcache="1" sizset="2">
		<tr>
			<td class="code-outline">
				<pre class="displaycode">
cleartool update &lt;path&gt;</pre>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　二、编译(Ant)</p>
<p>
	　　代码更新成功之后，下一步就是要编译。这里使用默认的 Ant 构建文件 build.xml。Ant 的编译命令如下：</p>
<p>
	　　首先清理原来的编译文件：</p>
<table border="0" cellpadding="0" cellspacing="0" sizcache="2" sizset="3" summary="This table contains a code listing." width="100%">
	<tbody sizcache="1" sizset="3">
		<tr>
			<td class="code-outline">
				<pre class="displaycode">
ant clean</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　然后重新编译整个工程：</p>
<table border="0" cellpadding="0" cellspacing="0" sizcache="2" sizset="4" summary="This table contains a code listing." width="100%">
	<tbody sizcache="1" sizset="4">
		<tr>
			<td class="code-outline">
				<pre class="displaycode">
ant &ndash;f build.xml &ndash;lib ecj.jar</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　通常会把 ant 的日志文件打印出来分析。如果编译成功在日志文件中可以看到如下关键字：</p>
<table border="0" cellpadding="0" cellspacing="0" sizcache="2" sizset="5" summary="This table contains a code listing." width="100%">
	<tbody sizcache="1" sizset="5">
		<tr>
			<td class="code-outline">
				<pre class="displaycode">
BUILD SUCCESSFUL
Total time: 25 seconds
Buildfile: build.xml</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　如果编译失败，则会打印出如下日志。从日志中可以分析出出现编译错误的两个 java 文件是 MailSignatureTasks.java 和 SignatureAddVCardWithPhoto.java，下面已经用黑体字标出。</p>
<table border="0" cellpadding="0" cellspacing="0" sizcache="2" sizset="6" summary="This table contains a code listing." width="100%">
	<tbody sizcache="1" sizset="6">
		<tr>
			<td class="code-outline">
				<pre class="displaycode">
ECHO is off.
Buildfile: build.xml

init:
 [echo] Check for necessary classpath elements, fail without them.
 [echo] RFT Java compiler W32 = C:\Program Files\IBM\SDP70\jdk\bin\javac.exe
 [echo] Jar (cbg) = C:\Documents and Settings\zhangsis\zhangsis_notesclient_int\
 wplcqe.02\notesclient\utilities\svt\cbg.perf_1.5.0.jar
 [echo] Jar (jcommon) = C:\Documents and Settings\zhangsis\zhangsis_notesclient_int\
 wplcqe.02\notesclient\utilities\svt\jcommon-1.0.6.jar
 [echo] Jar (jfreechart) = C:\Documents and Settings\zhangsis\zhangsis_notesclient_int\
 wplcqe.02\notesclient\utilities\svt\jfreechart-1.0.2.jar
 [echo] Jar (Notes) = C:\Documents and Settings\zhangsis\zhangsis_notesclient_int\
 wplcqe.02\notesclient\utilities\jars\Notes.jar

compile_datastore_w32:
 [echo] Compile the Java files in notesclient RFT datastore
[rft_javac_1.5] Compiling 195 source files to C:\Documents and Settings\zhangsis\
zhangsis_notesclient_int\wplcqe.02\notesclient
<strong>[rft_javac_1.5] C:/Documents and Settings/zhangsis/zhangsis_notesclient_int/
wplcqe.02/notesclient/tasks/client/mail/MailSignatureTasks.java:270: cannot find symbol</strong>
[rft_javac_1.5] symbol : method deletePhoto()
[rft_javac_1.5] location: class appobjects.dialog.client.mail.DlgAppendVcard
[rft_javac_1.5] 					dlgAppend.deletePhoto();
[rft_javac_1.5] ^
<strong>[rft_javac_1.5] C:/Documents and Settings/zhangsis/zhangsis_notesclient_int/wplcqe.02/
notesclient/testcases/client/pim/mail/signature/SignatureAddVCardWithPhoto.java:112: 
  cannot find symbol</strong>
[rft_javac_1.5] symbol : method setPhoto(java.lang.String)
[rft_javac_1.5] location: class appobjects.dialog.client.mail.DlgAppendVcard
[rft_javac_1.5]           log.altVerify(true, dlgAppend.setPhoto(sPicname), &quot;Set Photo&quot;);
[rft_javac_1.5] ^
[rft_javac_1.5] Note: * uses or overrides a deprecated API.
[rft_javac_1.5] Note: Recompile with -Xlint:deprecation for details.
[rft_javac_1.5] Note: Some input files use unchecked or unsafe operations.
[rft_javac_1.5] Note: Recompile with -Xlint:unchecked for details.
[rft_javac_1.5] 2 errors</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　三、压缩文件(STAF)</p>
<p>
	　　如果编译成功就压缩所有测试脚本，上传到 LA Server。利用 STAF 压缩文件的命令是：</p>
<table border="0" cellpadding="0" cellspacing="0" sizcache="2" sizset="7" summary="This table contains a code listing." width="100%">
	<tbody sizcache="1" sizset="7">
		<tr>
			<td class="code-outline">
				<pre class="displaycode">
staf local zip add zipfile &lt;filename&gt; directory &lt;directory name&gt; 
  RECURSE relativeto &lt;Directory&gt;</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　四、创建 Maseline(Cleartool)</p>
<p>
	　　编译成功之后，还有个任务是要创建 baseline，这样如果以后需要某个不同版本的代码，也可以顺利找回来，cleartool 命令是：</p>
<table border="0" cellpadding="0" cellspacing="0" sizcache="2" sizset="8" summary="This table contains a code listing." width="100%">
	<tbody sizcache="1" sizset="8">
		<tr>
			<td class="code-outline">
				<pre class="displaycode">
cleartool mkbl -view &lt;baseline name&gt;</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　五、找编译错误的文件和作者(Cleartool)</p>
<p>
	　　如果编译有错，则在日志文件中通过正则表达式匹配找到编译有错的脚本，然后通过如下 cleartool 命令找到最后在 ClearCase 里边更新脚本的 ID：</p>
<table border="0" cellpadding="0" cellspacing="0" sizcache="2" sizset="9" summary="This table contains a code listing." width="100%">
	<tbody sizcache="1" sizset="9">
		<tr>
			<td class="code-outline">
				<pre class="displaycode">
cleartool desc -fmt %u &lt;element&gt;</pre>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　六、发送邮件(STAF)</p>
<p>
	　　查到检入编译错误的 ID 之后，通过 ID 可以查到这个人的邮箱地址，然后用 STAF 的邮件服务给这个人以及 LA Admin 发送邮件通知：</p>
<table border="0" cellpadding="0" cellspacing="0" sizcache="2" sizset="10" summary="This table contains a code listing." width="100%">
	<tbody sizcache="1" sizset="10">
		<tr>
			<td class="code-outline">
				<pre class="displaycode">
Staf local email send to &lt;address&gt; subject &lt;subject&gt; message &lt;message&gt;</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　七、定时服务(STAF)</p>
<p>
	　　我们可以用 Java 或者 Perl 等脚本语言来自动化上述流程，这里还需要在 ClearCase Client 机器上设置定时服务，让这个脚本每天定时运行，这里我们就用到了 STAF Cron Service：</p>
<table border="0" cellpadding="0" cellspacing="0" sizcache="2" sizset="11" summary="This table contains a code listing." width="100%">
	<tbody sizcache="1" sizset="11">
		<tr>
			<td class="code-outline">
				<pre class="displaycode">
Staf local cron register Machine local Service process Request 
  &lt;request start command &gt; Hour &lt;hour&gt;</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　本文中是用 Java 写的脚本，于是 request start command 就是：</p>
<table border="0" cellpadding="0" cellspacing="0" sizcache="2" sizset="12" summary="This table contains a code listing." width="100%">
	<tbody sizcache="1" sizset="12">
		<tr>
			<td class="code-outline">
				<pre class="displaycode">
Start Shell Command java parms &lt;java file&gt; WORKDIR &lt;directory&gt; 
  RETURNSTDOUT RETURNSTDERR WAIT</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　我们可以用 STAF LOCAL CRON LIST 来查看当前机器上的所有定时任务，如图 4 可以看到 ID 19 就是我们刚刚加入的定时任务 :</p>
<table border="0" cellpadding="0" cellspacing="0" sizcache="2" sizset="13" summary="This table contains a code listing." width="100%">
	<tbody sizcache="1" sizset="13">
		<tr>
			<td class="code-outline">
				<pre class="displaycode">
Staf cron list</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　图 4. STAF 定时任务列表</p>
<center>
	<img alt="图 4. STAF 定时任务列表" border="1" height="291" src="/uploads/allimg/120319/1011494005-3.png" width="572" /></center>
<p>
	　　这样整个自动化流程就完成了。LA Admin 从此不用每天手动去更新和编译脚本了。</p>
<p>
	　　回页首</p>
<p>
	　　结束语</p>
<p>
	　　本文使用 Rational ClearCase、STAF、Ant、Lotus Automator 通过具体场景展示了自动化测试流程从人工到自动的改进过程。通过把这个流程自动化，不仅可以大大简化测试人员的工作量，减轻测试人员的工作负担，也能保证测试脚本的稳定性，使自动化开发人员开发人员尽早知道新版本的问题。</p>
<p>
	　　回页首</p>
<p>
	　　下载</p>
<table border="0" cellpadding="0" cellspacing="0" class="ibm-data-table" sizcache="25" sizset="107" summary="This table contains downloads for this document." width="100%">
	<tbody sizcache="25" sizset="107">
		<tr jquery1332121233312="4">
			<th scope="col">
				描述</th>
			<th scope="col">
				名字</th>
			<th scope="col">
				大小</th>
			<th scope="col">
				下载方法</th>
		</tr>
		<tr jquery1332121233312="5" sizcache="25" sizset="107">
			<td class="tb-row" scope="row">
				示例代码</td>
			<td nowrap="nowrap">
				CompileErrorAnalysisNotesFVT.java</td>
			<td nowrap="nowrap">
				9 KB</td>
			<td nowrap="nowrap" sizcache="25" sizset="107">
				HTTP</td>
		</tr>
	</tbody>
</table>
<p>
	　　关于下载方法的信息</p>
<p>
	　　参考资料</p>
<p>
	　　学习</p>
<p>
	　　STAF 官方网站</p>
<p>
	　　Ant 官方网站</p>
<p>
	　　访问 IBM developerWorks 中国网站 Rational 专区，获得关于 IBM Rational 软件交付平台(Rational Software Delivery Platform)产品的技术资源和最佳实践。</p>
<p>
	　　订阅 IBM developerWorks 时事通讯，一份关于 developerWorks 指南、文章、下载、社区活动、网络广播和技术讲座的电子周刊。</p>
<p>
	　　获得产品和技术</p>
<p>
	　　访问 Rational Functional Tester 产品专题，了解最新的 IBM Rational Functional Tester 产品文档和产品信息，获得相关的技术文档和参考资源，还可以查阅产品概览、产品手册、产品技术支持、试用版下载，以及相关文章、教程、多媒体课堂和产品演示等信息。</p>
<p>
	　　下载免费的 IBM Rational Functional Tester 试用版。</p>
<p>
	　　获取免费的 Rational 软件工具包系列，了解最新的 IBM Rational 软件开发工具技术文档和资源。</p>
<p>
	　　下载更多免费的 IBM Rational 试用版软件，了解 IBM Rational 软件的最新特性。</p>
<p>
	　　获取更多 IBM 试用版软件，并熟练掌握来自 DB2&reg;、Lotus&reg;、Tivoli&reg;，以及 WebSphere&reg; 的开发工具和中间件产品，用这些试用版软件开发您的下一个项目。这些试用版软件可以免费直接从 developerWorks 下载。</p>
<p>
	　　讨论</p>
<p>
	　　加入 developerWorks 中文社区，developerWorks 社区是一个面向全球 IT 专业人员，可以提供博客、书签、wiki、群组、联系、共享和协作等社区功能的专业社交网络社区。</p>
<p>
	　　加入 IBM 软件下载与技术交流群组，参与在线交流。</p>
]]></description>
    <pubDate>Mon, 19 Mar 2012 09:50:42 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/120319/1011493146-0-lp.png</subImagePath>
     <category>ClearCase</category>
    <author>张思思</author>
    <comments>IBM</comments>
</item>
<item>
    <title><![CDATA[Loadrunner常用的分析要点都有哪些?]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0301/204256.html</link>
    <description><![CDATA[<p>
	　　提供了生产负载的虚拟用户运行状态的相关信息，可以帮助我们了解负载生成的结果。</p>
<p>
	　　Rendezvous(负载过程中集合点下的虚拟用户)：</p>
<p>
	　　当设置集合点后会生成相关数据，反映了随着时间的推移各个时间点上并发用户的数目，方便我们了解并发用户的变化情况。</p>
<p>
	　　Errors(错误统计)：</p>
<p>
	　　通过错误信息可以了解错误产生的时间和错误类型，方便定位产生错误的原因。</p>
<p>
	　　Errors per Second(每秒错误)：</p>
<p>
	　　了解在每个时间点上错误产生的数目，数值越小越好。通过统计数据可以了解错误随负载的变化情况，定为何时系统在负载下开始不稳定甚至出错。</p>
<p>
	　　Average Transaction Response Time(平均事务响应时间)：</p>
<p>
	　　反映随着时间的变化事务响应时间的变化情况，时间越小说明处理的速度越快。如果和用户负载生成图合并，就可以发现用户负载增加对系统事务响应时间的影响规律。</p>
<p>
	　　Transactions per Second(每秒事务)：</p>
<p>
	　　TPS吞吐量，反映了系统在同一时间内能处理事务的最大能力，这个数据越高，说明系统处理能力越强。</p>
<p>
	　　Transactions Summary(事务概要说明)</p>
<p>
	　　统计事物的Pass数和Fail数，了解负载的事务完成情况。通过的事务数越多，说明系统的处理能力越强;失败的事务数越小说明系统越可靠。</p>
<p>
	　　Transaction performance Summary(事务性能概要)：</p>
<p>
	　　事务的平均时间、最大时间、最小时间柱状图，方便分析事务响应时间的情况。柱状图的落差越小说明响应时间的波动小，如果落差很大，说明系统不够稳定。</p>
<p>
	　　Transaction Response Time Under Load(用户负载下事务响应时间)：</p>
<p>
	　　负载用户增长的过程中响应时间的变化情况，该图的线条越平稳，说明系统越稳定。</p>
<p>
	　　Transactions Response time(事务响应时间百分比)：</p>
<p>
	　　不同百分比下的事务响应时间范围，可以了解有多少比例的事物发生在某个时间内，也可以发现响应时间的分布规律，数据越平稳说明响应时间变化越小。</p>
<p>
	　　Transaction Response Time(各时间段上的事务数)：</p>
<p>
	　　每个时间段上的事务个数，响应时间较小的分类下的是无数越多越好。</p>
<p>
	　　Hits per Second(每秒点击)：</p>
<p>
	　　当前负载重对系统所产生的点击量记录，每一次点击相当于对<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>发出了一次请求，数据越大越好。</p>
<p>
	　　Throughput(吞吐量)：</p>
<p>
	　　系统负载下所使用的带宽，该数据越小说明系统的带宽依赖就越小，通过这个数据可以确定是不是<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlzs/" target="_blank" >网络</A></STRONG>出现了瓶颈。</p>
<p>
	　　HTTP Responses per Second(每秒HTTP响应)：</p>
<p>
	　　每秒服务器返回各种状态的数目，一般和每秒点击量相同。点击量是客户端发出的请求数，而HTTP响应数是服务器返回的响应数。如果服务器的响应数小于点击量，那么说明服务器无法应答超出负载的连接请求。</p>
<p>
	　　Connections per Second(每秒连接)：</p>
<p>
	　　统计终端的连接和新建的连接数，方便了解每秒对服务器产生连接的数量。同时连接数越多，说明服务器的连接池越大，当连接数随着负载上升而停止时，说明系统的连接池已满，通常这时候服务器会返回504错误。需要修改服务器的最大连接来解决该问题。</p>
]]></description>
    <pubDate>Thu, 01 Mar 2012 12:20:19 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>LoadRunner</category>
    <author>不详</author>
    <comments>IT公司面试手册</comments>
</item>
<item>
    <title><![CDATA[对初学LoadRunner朋友的建意]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0227/204213.html</link>
    <description><![CDATA[<p>
	　　LoadRuner与性能测试的关系：</p>
<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LoadRunner</A></STRONG>初学者的误点：把LoadRunner神化了.很多初学LoadRunner的朋友认为掌握了使用LoadRunner这款性能<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>，就能够做性能测试了.常在网上看到好多人在学习怎么去使用这款优秀的性能测试工具,本来学习怎么去使用LoadRunner这个工具没有错，却把LoadRunner神化了,&rdquo;天真的&rdquo;以为它什么都能做，以为学会了LoadRunner的使用就能做性能测试了.尽管用了大量的时间学会了如何使用LoadRunner录制脚本，如何进行关联，如何进行参数化，如何设置集合点等等?可到头来，性能测试还是不会做.为什么?对于产生的性能报告不知道怎么去分析?不知道如何利用得到的分析报告分析出系统存在的瓶颈?不知道如何进行性能调优?像这些事光会使用 LoadRunner是做不到的?说白了LoadRunner只是我们做性能测试的一个工具，它并不是万能的，是死的，具体怎么做还得依靠人去操作与分析.会使用LoadRunner的人，并不一定会做性能测试，会做性能测试的人并不一定都会使用LoadRunner.LoadRunner只是一个性能测试工具而已.我们应该意识到，测试工具只是性能测试中的一部分，仅是为达到性能测试目的而采用的一种手段</p>
<p>
	　　性能测试与系统性能的关系：</p>
<p>
	　　高性能，高安全的系统，不是测试出来的，而是构架，设计，编写出来的.当然在这里我并不否认性能测试的重要性，甚至可以说没有经过性能测试的系统，一定不会是优秀的系统，软件是人<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>出来的，而人总是会出错的，所谓智者千虑，必有一失&hellip;&hellip;要想做好性能测试，在软件系统<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求</A></STRONG>，设计，编写代码的这些阶段就应该进行性能测试，而不仅仅是<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csgl/xtcs/" target="_blank" >系统测试</A></STRONG>这个阶段才去做性能测试，性能测试应该贯穿于整个软件开发周期中.</p>
<p>
	　　对初学LoadRunner朋友的建意：</p>
<p>
	　　常看到网上一些网友发贴子问，怎么对性能测试产生的结果进行分析?测试系统时怎么去选择合适的协议?对于发这些贴子的人我想请问你?你能够详细的说下 HTTP协议吗?TCP建立连接和释放连接的过程是怎样进行的?什么是协议?协议是用来做什么的?在OSI参考模型中各层的作用?<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>中产生并发的冲突的原因?不要太依赖于LoadRunner工具本身的学习，而去忽略计算机其它基础<STRONG><A href="http://www.ltesting.net/ask/" target="_blank" >知识</A></STRONG>的学习，我们更应该去掌握一门编程语言，良好的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlzs/" target="_blank" >网络</A></STRONG>基础知识，计算机原理与操作系统知识，数据库知识.这些是我们去学习怎么去使用LoadRunner前提与基础。.</p>
<p>
	　　1为什么要掌握一门编程语言其一,大家在使用LoadRunner时常会遇到一些不能录制脚本的情况发生，或者需要录制一些复杂的脚本，这时候我们就必须手动的开发脚本.其二 LoadRunner虽然强大,易于使用,可是它却属于商业软件,价格昂贵,并且代码不<STRONG><A href="http://www.ltesting.net/ceshi/open" target="_blank" >开源</A></STRONG>,我们无法了解LoadRunner具体的实现细节,甚至我们会怀疑LoadRunner收集的性能数据准确吗?它有是如何实现的等等,而这些我们通过LoadRunner的帮助文档无法得知.性能测试工具并不只有 LoadRunner,做性能测试还有许多优秀的性能测试工具可以选择,像<STRONG><A href="http://www.ltesting.net/ceshi/open/kyxncsgj/jmeter/" target="_blank" >JMeter</A></STRONG>,Curl- Loader等等这些非常优秀的开源工具,在全能上虽然并不上LoadRunner,但在某些方面却比LoadRunner还要强大.例如Curl- Loader这个工具,它虽然支持的协议不多,但是对于http协议它最高能产生10万的并发用户,这是LoadRunner远远所不及的.并且这些工具代码是公开的,我们能够从这些代码中去分析具体实现的细节,并且还可以自已编写代码,增强软件的功能,这也是成为性能测试高手的一条途径.LoadRunner好比我们的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/windows/" target="_blank" >Windows</A></STRONG>操作系统,易于使用,功能强大,代码封闭,论全能比<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/unix/linux/" target="_blank" >Linux</A></STRONG>要强大.我们的<STRONG><A href="http://www.ltesting.net/ceshi/open/kyxncsgj/" target="_blank" >开源性能测试</A></STRONG>工具好比Linux操作系统代码开源,不易于使用,但很多方面比我们的Windows要强大.也许这个时候有人会问对于初学者学哪门语言最好最有前途C,C++,<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/vb/" target="_blank" >VB</A></STRONG>,JAVA,C#?其实每一种语言能够生存下来,自有其生存的道理,每一种语言都有自已优势和缺点,并且编程语言具有相通信,学好了一门,再去学另外的编程语言,非常快就能上手.对于初学者我建意学习C语言,理由有很多,例如很多优秀的开源性能测试工具就是用C语言开发的&hellip;.当然不管选择什么编程语言,或者数据库,或者操作系统,我们不要去想学哪门最好,学哪方面最有前途.我们更应该结合自身的情况,选择最合适的,而不是选择最好的.</p>
<p>
	　　2为什么要掌握计算机原理和操作系统知识</p>
<p>
	　　<STRONG><A href="http://bbs.ltesting.net/" target="_blank" >论坛</A></STRONG>上常会看到这些问题?LoadRunner中线程与进程的关系?在什么时候用到它们,怎么区别用线程还是进程呢?LoadRunner录制产生了乱码怎么解决?怎么去发现内存泄漏?对那些发贴问这些问题的朋友,我依然想请问你你知道进程和线程的概念吗?知道进程有几种状态吗?知道进程间的通信是怎么进行的吗?死锁,进程与线程的区别这些概念你明白吗?如果你连内存的概念,内存的作用,内存泄露的概念都搞不清楚,你怎么去发现内存泄露?如果这些你都不知道,自然就不知道怎么去做性能测试分析?一些网友录制脚本常常会产生一些莫名奇妙的错误?还震震有词的说这是LoadRunner的原因.其实要说到底要解决这些问题就必需得有良好的计算机原理和操作系统知识.弄清了进程和线程的区别,你自然就明白了使用进程资源使用高,但安全性要强于线程,线程资源利用率少,使用线程能在一个负载生成器上运行更多的Vuser,但可能存在安全问题.LoadRunner录制产生了乱码怎么解决?为什么会产生乱码,你知道什么是字符集吗?什么是编码吗?字符串在我们内存中有是如何存放的?ASCII编码,ANSI编码,UNICODE编码它们的区别是什么?这些都是操作系统的基础基础.掌握好了这些你自然明白LoadRunner中产生乱码的原因.当然计算机原理和操作系统的基础知识还有很多得掌握的知识.像操作系统的体系架构、操作系统的重要基础概念,内存管理、存储/文件系统、驱动/硬件的管理.要做好性能测试计算机原理和操作系统知识必不可少.</p>
<p>
	　　3为什么要有良好的网络基础</p>
<p>
	　　经常在ltesting论坛中看到很多人发贴子.像LoadRuner中为什么要进行关联?,LoadRunner测试系统时如何选择协议?LoadRunner中的如何进行IP欺骗?等等.这些问题随便一搜就能发现大量的贴子,其实说到底这些问题和LoadRunner的关系并不是很大,要去解决这些问题并不在于你对LoadRunner这个工具使用是否熟练,而在于我们网络基础知识是否扎实.例如第一个问题LoadRunner中为什么要进行关联?相信很多朋友都知道HTTP协议知道它是超文本传输协议,但是对于一些新手往往不能够详细的说出HTTP具体的内容,像HTTP工作的原理,HTTP协议为什么要使用基于TCP的协议而不使用UDP的协议,HTTP工作在OSI参考模型的哪一层?在HTTP协议上数据是怎么传输的等等.而只有当我们明白了这一切,自然而然就会明白为什么要使用关联,到最后你会发现这些问题其实根LoadRunner关系并不是很大.HTTP协议本质上是无状态的;对页面的每个请求都将被视为新请求,而且默认情况下,来自一个请求的信息对下一个请求不可用.在传统的Web编程中,这通常意味着在每一次往返行程中,与该页及该页上的控件相关联的所有信息都会丢失.例如,如果用户将信息输入到文本框,该信息将在从浏览器或客户端设备到<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>的往返行程中丢失,为了使用浏览网页,页与页是相互联系不去丢失这些信息,于是了就从现了Cookie,Session,查询字符串等等保持状态的技术.什么是Cookie?什么是Session?Cookie 和Session 有是怎么工作的?当我们明白了这些,很多的问题就自然而然的明白了,像这些都是基础的知识和LoadRunner关系大吗?不大.Cookie 是一些少量的数据,这些数据存储在客户端文件系统的文本文件中,或者存储在客户端浏览器会话的内存中.Cookie 包含特定于站点的信息(像用户名密码以及我们在网站一些个性化的设置等等),这些信息是随页输出一起由服务器发送到客户端的.如果浏览器使用的是 cookie,那么所有的数据都保存在浏览器端,比如我们登录以后,服务器设置了cookie用户名,那么当你再次请求服务器的时候,浏览器会将用户名一块发送给服务器,这些变量有一定的特殊标记.服务器会解释为cookie变量,所以只要不关闭浏览器,那么cookie变量一直是有效的,所以能够保证长时间不掉线..如果设置了的有效时间,那么它会将 cookie保存在客户端的硬盘上,下次再访问该网站的时候浏览器先检查有没有 cookie,如果有的话,就读取该 cookie,然后发送给服务器.这些是Cookie的工作过程,常看到论坛上一些朋友发贴子问使用LoadRunner时录制到了一些Cookie的信息,它是用来做什么的,看起来很烦可不可以把它删除掉?明白了这些细节的知识,你自然能明白那个Cookie的信息能不能删除掉.如果web服务器端使用的是session,那么所有的数据都保存在服务器上,客户端每次请求服务器的时候会发送当前会话的SessionId,服务器根据当前 SessionId唯一地标识在服务器上包含会话数据的浏览器,以确定用户是否登录或具有某种权限.不同的用户发送请求Web服务器会随机发送一个唯一的 SessionID.而我们使用LoadRunner录制时它会把我们SessionID写死,所以导致出错.这时候就得使用关联了,这样不仅明白了 LoadRunner怎样使用关联,而且还明白了为什么要使用关联?对于LoadRunner测试系统时如何选择协议?这个问题也是网络论讨的比较多的问题.要解决这个问题同样得依靠我们的扎实的网络基础,而不是对LoadRunner使用的熟练程度,首先我们得了解LoadRunner录制时的工作原理了,LoadRunner的录制和<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/" target="_blank" >QTP</A></STRONG>不一样,它不关心你的对象识别什么的,不关心你的什么界面之类的,不关心你使用什么语言编写的,LoadRunner有一个Agent进程,来专门监控客户端和服务器之间的通信,然后用自己的函数进行录制.LoadRunner录制的时候关心的是通信包,是客户端和服务器之间的数据包.说到这里,大家就比较清楚了,为什么有的时候不能录制呢?因为,协议不认识,导致LoadRunner截获的数据包不能解析,所以录制下来是空的.所以我们得熟悉什么是协议, 熟悉OSI参考模型,OSI参考模型中各层的作用,TCP协议栈各层的作用,熟悉TCP,UDP,ICMP等等协议.当我们明白了这些网络的基础知识后我们自然会明白应该如何去选择协议.另外关于LoadRunner中的如何进行IP欺骗?要解决这个问题同样得有良好的网络基础知识.其实当我们理解了IP 地址的格式,IP地址的分类,子网掩码的概念,以及知道怎么去进行非标准子网的划分方法 ,掌握了这些原理的东西,那么具体怎么在LoadRunner中如何进行IP欺骗,就非常简单了. 当然网络基础知识并不只是上面的而已,还包括路由器,交换机,加密技术等等这些基础的网络知识,这些远远比我们去学习怎么去使用LoadRunner更重要.#p#分页标题#e#</p>
<p>
	　　4为什么要掌握数据库知识</p>
<p>
	　　数据库的重要性我想是不言而喻的,性能测试产生的一个非常大的原因是因为数据大集中的趋势,测试从某种意义来讲就是对数据测试,而我们企业的核心数据是放在数据库中的.现在大型的WEB应用程序,都采用多层结构,像典型三层,用户界面层,数据逻辑层,数据层.而数据层,而数据层对我们整个WEB应用程序的性能是非常大的,对数据库的基础知识不懂,我们怎么去进行性能测试分析?怎么知道确定性能产生的瓶颈是否是数据库的原因,如何对系统进行调优?例如数据库模型设计不合理,一条坏的SQL语句就能影响到整个WEB应用程序的性能,所以熟悉SQL语句,建表,索引,存储过程,事务,触发器,并发等这些基础知识是必需得掌握的.</p>
]]></description>
    <pubDate>Mon, 27 Feb 2012 16:10:09 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>LoadRunner</category>
    <author>xuyubotest</author>
    <comments>csdn</comments>
</item>
<item>
    <title><![CDATA[最新版 JIRA 5 正式发布]]></title>
    <link>http://www.ltesting.net/ceshi/open/kybugglgj/jira/2012/0223/204186.html</link>
    <description><![CDATA[<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/open/kybugglgj/jira/" target="_blank" >JIRA</A></STRONG>是集项目计划、任务分配、<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求管理</A></STRONG>、错误跟踪于一体的商业软件。JIRA创建的问题类型包括New Feature、Bug、Task和Improvement四种，还可以自己定义，所以它也一是过程管理系统。Jira融合了<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xmgl/" target="_blank" >项目管理</A></STRONG>、任务管理和<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/qxgl/" target="_blank" >缺陷管理</A></STRONG>，许多著名的<STRONG><A href="http://www.ltesting.net/ceshi/open" target="_blank" >开源</A></STRONG>项目都采用了JIRA。</p>
<center>
	<img alt="" border="1" height="300" src="/uploads/allimg/120223/1232062a3-0.png" width="490" /></center>
<p>
	　　JIRA 是目前比较流行的基于<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcskfyy/java/" target="_blank" >Java</A></STRONG>架构的管理系统，由于Atlassian公 司对很多开源项目实行免费提供缺陷跟踪服务，因此在开源领域，其认知度比其他的产品要高得多，而且易用性也好一些。同时，开源则是其另一特色，在用户购买 其软件的同时，也就将源代码也购置进来，方便做二次<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>。正因为其开放性，价格上自然也相当不菲，对于中小型的软件企业做项目管理，则又要另寻出路。</p>
<p>
	　　Atlassian 是一家专门为软件开发提供工具的公司。目前他们正在调试他们的新一代团队协作软件产品，JIRA。众所周知，JIRA是用来跟踪问题的。</p>
<center>
	<img alt="" border="1" height="153" src="/uploads/allimg/120223/12320AJ8-1.jpg" width="329" /></center>
<p>
	　　JIRA 5 将提供的社会化功能包括，@支持，分享，和实时活动流(Activity Stream)。其中@和分享能更加容易的将团队成员聚集到一个问题讨论中来。而活动流能让所有的团队成员获得最新的更新，有点像Facebook和Twitter的活动流。</p>
<p>
	　　除此之外JIRA 5还提供了更多的插件API和改进的REST API，可以让第三方开发者更容易的与JIRA集成。现在JIRA已经有了100多个商业的或者免费的插件了。</p>
<p>
	　　Atlassian 目前有20000个客户，有70%的世界100强公司使用他们的产品。他们在这个领域确实做的很成功。Atlassian去年的营收是一亿美元，涨了35%。而今年一月份他们就做了一千万美元。</p>
<p>
	　　译者注：Atlassian的雇员应该在200左右。他们没有销售人员!</p>
]]></description>
    <pubDate>Thu, 23 Feb 2012 12:27:50 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/120223/1232062a3-0-lp.png</subImagePath>
     <category>JIRA</category>
    <author>seanhe</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[Loadrunner相关问题]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0222/204170.html</link>
    <description><![CDATA[<p>
	　　1,action和init、end除了迭代的区别还有其他吗?</p>
<p>
	　　在init、end 中不能使用集合点、事务等。</p>
<p>
	　　2,HTTP的超时有哪三种?</p>
<p>
	　　HTTP-request connect timeout、HTTP-request receive timeout、step download timeout</p>
<p>
	　　3,在什么地方设置HTTP页面filter?</p>
<p>
	　　在runtime_settings中download filter里面进行设置。</p>
<p>
	　　4,pot mapping的原理是什么?</p>
<p>
	　　就是代理<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG></p>
<p>
	　　5,如何设置可以让一个虚拟IP对应到一个Vuser?</p>
<p>
	　　利用线程和进程做中介，逻辑上的对应。</p>
<p>
	　　选中Expert Mode，设置Options中的General</p>
<p>
	　　6,什么是contentcheck?如何来用?</p>
<p>
	　　ContentCheck的设置是为了让VuGen 检测何种页面为错误页面。如果被测的Web 应用没有使用自定义的错误页面，那么这里不用作更改;如果被测的Web 应用使用了自定义的错误页面，那么这里需要定义，以便让VuGen 在运行过程中检测，服务器返回的页面是否包含预定义的字符串，进而判断该页面是否为错误页</p>
<p>
	　　面。如果是，VuGen就停止运行，指示运行失败。</p>
<p>
	　　使用方法：点击在runtime settings中点击&ldquo;contentcheck&rdquo;，然后新建立一个符合要求的应用程序和规则，设定需要查找的文本和前缀后缀即可使用。</p>
<p>
	　　7,network中的speed simulation是模拟的什么带宽?</p>
<p>
	　　模拟用户访问速度的带宽。</p>
<p>
	　　8,进程和线程有什么区别?</p>
<p>
	　　程和线程的区别网上很多，不作过多讨论，重点说一下其在<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LR</A></STRONG>中选择的区别。最显著的区别是：线程有</p>
<p>
	　　自己的全局数据。线程存在于进程中,因此一个进程的全局变量由所有的线程共享。由于线程共享同样的系</p>
<p>
	　　统区域,操作系统分配给一个进程的资源对该进程的所有线程都是可用的,正如全局数据可供所有线程使用</p>
<p>
	　　一样。在Controller中将使用驱动程序(如mdrv.exe、r3vuser.exe)运行vuser。如果按进程运行每个</p>
<p>
	　　vuser，则对于每个vuser实例，都将反复启动同一驱动程序并将其加载到内存中。将同一驱动程序加载到</p>
<p>
	　　内存中会占用大量的RAM(随机存储器)及其他系统资源。这就限制了可以在任一负载生成器上运行的</p>
<p>
	　　vuser数量。如果按线程运行每个vuser，Controller为每50个vuser(默认情况下)仅启动驱动程序(如</p>
<p>
	　　mdrv.exe)的一个实例。该驱动程序将启动几个vuser，每个vuser都按线程运行。这些线程vuser将共享父</p>
<p>
	　　驱动进程的内存段。这就消除了多次重新加载驱动程序/进程的需要，节省了大量内存空间，从而可以在一</p>
<p>
	　　个负载生成器上运行更多的Vuser。</p>
<p>
	　　9,生成WEB性能图有什么意义?大概描述即可。</p>
<p>
	　　可以很直观的看到，在负载下系统的运行情况以及各种资源的使用情况，可以对系统的性能瓶颈定位、性</p>
<p>
	　　能调优等起到想要的辅助作用。</p>
<p>
	　　10,如果刷新controller里的脚本?</p>
<p>
	　　在controller中，点击detailis-Refresh-script即可。</p>
<p>
	　　11,WAN emulation是模拟什么的?</p>
<p>
	　　答：是模拟广域网环境的。模拟大量<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlzs/" target="_blank" >网络</A></STRONG>基础架构的行为。可以设置突出 WAN 效果的参数(如延迟、丢包、动态路由效果和链接故障)，并监控模拟设置对网络性能的影响。</p>
<p>
	　　12,如何把脚本和结果放到load generator的机器上?</p>
<p>
	　　在controller中，点击Results-Results settings,在里面进行相应的设置即可。</p>
<p>
	　　13,如何设置才能让集合点只对一半的用户生效?</p>
<p>
	　　对集合点策略进行相应的设置即可。即在controller中，点击Scenario-Rendezvous-policy进行相应的设</p>
<p>
	　　置即可，由于题目中&ldquo;一半的用户&rdquo;没有说明白具体指什么样的用户，现在不好确定具体对里面的哪个选项</p>
<p>
	　　进行设置。</p>
<p>
	　　14,在设置windows资源图监控的时候，用到的是什么端口和协议?在这一过程中，会有大概哪些问题?(大概描述)</p>
<p>
	　　这个比较容易看吧，连上去，netstat -nao就可以看了</p>
<p>
	　　microsoft-ds ：445 ;要有权限、开启服务。</p>
]]></description>
    <pubDate>Wed, 22 Feb 2012 10:44:21 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>LoadRunner</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[LoadRunner超时错误如何解决?]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0222/204169.html</link>
    <description><![CDATA[<p>
	　　在录制Web协议脚本回放时超时情况经常出现，产生错误的原因也有很多，解决的方法也不同。</p>
<p>
	　　错误现象1：Action.c(16): Error -27728: Step download timeout (120 seconds) has expired when downloading non-resource(s)。</p>
<p>
	　　错误分析：对于HTTP协议，默认的超时时间是120秒(可以在<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LoadRunner</A></STRONG>中修改)，客户端发送一个请求到<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>端，如果超过120秒服务器端还没有返回结果，则出现超时错误。</p>
<p>
	　　解决办法：首先在运行环境中对超时进行设置，默认的超时时间可以设置长一些，再设置多次迭代运行，如果还有超时现象，需要在&ldquo;Runtime Setting&rdquo;&gt;&ldquo;Internet Protocol：Preferences&rdquo;&gt;&ldquo;Advanced&rdquo;区域中设置一个&ldquo;winlnet replay instead of sockets&rdquo;选项，再回放是否成功。</p>
<p>
	　　错误现象2：Action.c(81):Continuing after Error -27498: Timed out while processing URL=http://172.18.20.70:7001/workflow/bjtel/leasedline/ querystat/ subOrderQuery.do</p>
<p>
	　　错误分析：这种错误常常是因为并发压力过大，服务器端太繁忙，无法及时响应客户端的请求而造成的，所以这个错误是正常现象，是压力过大造成的。</p>
<p>
	　　如果压力很小就出现这个问题，可能是脚本某个地方有错误，要仔细查看脚本，提示的错误信息会定位某个具体问题发生的位置。</p>
<p>
	　　解决办法：例如上面的错误现象问题定位在某个URL上，需要再次运行一下场景，同时在其他机器上访问此URL。如果不能访问或时间过长，可能是服务器或者此应用不能支撑如此之大的负载。分析一下服务器，最好对其性能进行优化。</p>
<p>
	　　如果再次运行场景后还有超时现象，就要在各种图形中分析一下原因，例如可以查看是否服务器、DNS、<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlzs/" target="_blank" >网络</A></STRONG>等方面存在问题。</p>
<p>
	　　最后，增加一下运行时的超时设置，在&ldquo;Run-Time Settings&rdquo;&gt;&ldquo;Internet Protocol:Preferences&rdquo;中，单击&ldquo;options&rdquo;，增加&ldquo;HTTP-request connect timeout&rdquo;或者&ldquo;HTTP-request receive&rdquo;的值。</p>
]]></description>
    <pubDate>Wed, 22 Feb 2012 10:36:42 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>LoadRunner</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[如何完全卸载LoadRunner?]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0222/204168.html</link>
    <description><![CDATA[<p>
	　　1.首先保证所有<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LoadRunner</A></STRONG>的相关进程(包括Controller、VuGen、Analysis和Agent Process)全部关闭。</p>
<p>
	　　2.备份好LoadRunner安装目录下测试脚本，一般存放在LoadRunner安装目录下的&ldquo;scrīpts&rdquo;子目录里。</p>
<p>
	　　3.在控制面板的&ldquo;删除与添加程序&rdquo;中运行LoadRunner的卸载程序。如果弹出提示信息关于共享文件的，都选择全部删除。</p>
<p>
	　　4.卸载向导完成后，重新启动电脑。完成整个LoadRunner卸载过程。</p>
<p>
	　　5.删除整个LoadRunner目录。(包括Agent Process)</p>
<p>
	　　6.在操作中查找下列文件，并且删除它们(如果有)</p>
<p>
	　　1) w<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >lr</A></STRONG>un.*</p>
<p>
	　　2) vugen.*7.运行注册表程序(开始- 运行- regedit)8.删除下列键值：</p>
<p>
	　　如果只安装了MI公司的LoadRunner这一个产品，请删除：</p>
<p>
	　　HKEY_LOCAL_MACHINESOFTWARE<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/" target="_blank" >Mercury</A></STRONG> Interactive.</p>
<p>
	　　HKEY_CURRENT_USERSOFTWAREMercury Interactive.</p>
<p>
	　　否则请删除：</p>
<p>
	　　HKEY_LOCAL_MACHINESOFTWAREMercury InteractiveLoadRunner.</p>
<p>
	　　HKEY_CURRENT_USERSOFTWAREMercury InteractiveLoadRunner.</p>
<p>
	　　9.最后清空回收站</p>
<p>
	　　完成了以上操作就可以正常的重新安装LoadRunner。安装LoadRunner时最好关闭所有的杀毒程序。</p>
]]></description>
    <pubDate>Wed, 22 Feb 2012 10:16:53 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>LoadRunner</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[软件开发转测试]]></title>
    <link>http://www.ltesting.net/plus/view.php?aid=204149</link>
    <description><![CDATA[]]></description>
    <pubDate>Mon, 20 Feb 2012 16:30:15 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>软件测试工具</category>
    <author>bxmeng</author>
    <comments>本站</comments>
</item>
<item>
    <title><![CDATA[对初学LoadRunner朋友的建议]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0215/204107.html</link>
    <description><![CDATA[<p>
	　　LoadRuner与性能测试的关系：</p>
<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LoadRunner</A></STRONG>初学者的误点：把LoadRunner神化了.很多初学LoadRunner的朋友认为掌握了使用LoadRunner这款性能<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>，就能够做性能测试了.常在网上看到好多人在学习怎么去使用这款优秀的性能测试工具,本来学习怎么去使用LoadRunner这个工具没有错，却把LoadRunner神化了,&rdquo;天真的&rdquo;以为它什么都能做，以为学会了LoadRunner的使用就能做性能测试了.尽管用了大量的时间学会了如何使用LoadRunner录制脚本，如何进行关联，如何进行参数化，如何设置集合点等等?可到头来，性能测试还是不会做.为什么?对于产生的性能报告不知道怎么去分析?不知道如何利用得到的分析报告分析出系统存在的瓶颈?不知道如何进行性能调优?像这些事光会使用 LoadRunner是做不到的?说白了LoadRunner只是我们做性能测试的一个工具，它并不是万能的，是死的，具体怎么做还得依靠人去操作与分析.会使用LoadRunner的人，并不一定会做性能测试，会做性能测试的人并不一定都会使用LoadRunner.LoadRunner只是一个性能测试工具而已.我们应该意识到，测试工具只是性能测试中的一部分，仅是为达到性能测试目的而采用的一种手段</p>
<p>
	　　性能测试与系统性能的关系：</p>
<p>
	　　高性能，高安全的系统，不是测试出来的，而是构架，设计，编写出来的.当然在这里我并不否认性能测试的重要性，甚至可以说没有经过性能测试的系统，一定不会是优秀的系统，软件是人<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>出来的，而人总是会出错的，所谓智者千虑，必有一失&hellip;&hellip;要想做好性能测试，在软件系统<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求</A></STRONG>，设计，编写代码的这些阶段就应该进行性能测试，而不仅仅是<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csgl/xtcs/" target="_blank" >系统测试</A></STRONG>这个阶段才去做性能测试，性能测试应该贯穿于整个软件开发周期中.</p>
<p>
	　　对初学LoadRunner朋友的建意：</p>
<p>
	　　常看到网上一些网友发贴子问，怎么对性能测试产生的结果进行分析?测试系统时怎么去选择合适的协议?对于发这些贴子的人我想请问你?你能够详细的说下 HTTP协议吗?TCP建立连接和释放连接的过程是怎样进行的?什么是协议?协议是用来做什么的?在OSI参考模型中各层的作用?<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>中产生并发的冲突的原因?不要太依赖于LoadRunner工具本身的学习，而去忽略计算机其它基础<STRONG><A href="http://www.ltesting.net/ask/" target="_blank" >知识</A></STRONG>的学习，我们更应该去掌握一门编程语言，良好的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlzs/" target="_blank" >网络</A></STRONG>基础知识，计算机原理与操作系统知识，数据库知识.这些是我们去学习怎么去使用LoadRunner前提与基础。.</p>
<p>
	　　1为什么要掌握一门编程语言其一,大家在使用LoadRunner时常会遇到一些不能录制脚本的情况发生，或者需要录制一些复杂的脚本，这时候我们就必须手动的开发脚本.其二 LoadRunner虽然强大,易于使用,可是它却属于商业软件,价格昂贵,并且代码不<STRONG><A href="http://www.ltesting.net/ceshi/open" target="_blank" >开源</A></STRONG>,我们无法了解LoadRunner具体的实现细节,甚至我们会怀疑LoadRunner收集的性能数据准确吗?它有是如何实现的等等,而这些我们通过LoadRunner的帮助文档无法得知.性能测试工具并不只有 LoadRunner,做性能测试还有许多优秀的性能测试工具可以选择,像<STRONG><A href="http://www.ltesting.net/ceshi/open/kyxncsgj/jmeter/" target="_blank" >JMeter</A></STRONG>,Curl- Loader等等这些非常优秀的开源工具,在全能上虽然并不上LoadRunner,但在某些方面却比LoadRunner还要强大.例如Curl- Loader这个工具,它虽然支持的协议不多,但是对于http协议它最高能产生10万的并发用户,这是LoadRunner远远所不及的.并且这些工具代码是公开的,我们能够从这些代码中去分析具体实现的细节,并且还可以自已编写代码,增强软件的功能,这也是成为性能测试高手的一条途径.LoadRunner好比我们的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/windows/" target="_blank" >Windows</A></STRONG>操作系统,易于使用,功能强大,代码封闭,论全能比<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/unix/linux/" target="_blank" >Linux</A></STRONG>要强大.我们的<STRONG><A href="http://www.ltesting.net/ceshi/open/kyxncsgj/" target="_blank" >开源性能测试</A></STRONG>工具好比Linux操作系统代码开源,不易于使用,但很多方面比我们的Windows要强大.也许这个时候有人会问对于初学者学哪门语言最好最有前途C,C++,<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/vb/" target="_blank" >VB</A></STRONG>,JAVA,C#?其实每一种语言能够生存下来,自有其生存的道理,每一种语言都有自已优势和缺点,并且编程语言具有相通信,学好了一门,再去学另外的编程语言,非常快就能上手.对于初学者我建意学习C语言,理由有很多,例如很多优秀的开源性能测试工具就是用C语言开发的&hellip;.当然不管选择什么编程语言,或者数据库,或者操作系统,我们不要去想学哪门最好,学哪方面最有前途.我们更应该结合自身的情况,选择最合适的,而不是选择最好的.</p>
<p>
	　　2为什么要掌握计算机原理和操作系统知识</p>
<p>
	　　<STRONG><A href="http://bbs.ltesting.net/" target="_blank" >论坛</A></STRONG>上常会看到这些问题?LoadRunner中线程与进程的关系?在什么时候用到它们,怎么区别用线程还是进程呢?LoadRunner录制产生了乱码怎么解决?怎么去发现内存泄漏?对那些发贴问这些问题的朋友,我依然想请问你你知道进程和线程的概念吗?知道进程有几种状态吗?知道进程间的通信是怎么进行的吗?死锁,进程与线程的区别这些概念你明白吗?如果你连内存的概念,内存的作用,内存泄露的概念都搞不清楚,你怎么去发现内存泄露?如果这些你都不知道,自然就不知道怎么去做性能测试分析?一些网友录制脚本常常会产生一些莫名奇妙的错误?还震震有词的说这是LoadRunner的原因.其实要说到底要解决这些问题就必需得有良好的计算机原理和操作系统知识.弄清了进程和线程的区别,你自然就明白了使用进程资源使用高,但安全性要强于线程,线程资源利用率少,使用线程能在一个负载生成器上运行更多的Vuser,但可能存在安全问题.LoadRunner录制产生了乱码怎么解决?为什么会产生乱码,你知道什么是字符集吗?什么是编码吗?字符串在我们内存中有是如何存放的?ASCII编码,ANSI编码,UNICODE编码它们的区别是什么?这些都是操作系统的基础基础.掌握好了这些你自然明白LoadRunner中产生乱码的原因.当然计算机原理和操作系统的基础知识还有很多得掌握的知识.像操作系统的体系架构、操作系统的重要基础概念,内存管理、存储/文件系统、驱动/硬件的管理.要做好性能测试计算机原理和操作系统知识必不可少.</p>
<p>
	　　3为什么要有良好的网络基础</p>
<p>
	　　经常在51testing论坛中看到很多人发贴子.像LoadRuner中为什么要进行关联?,LoadRunner测试系统时如何选择协议?LoadRunner中的如何进行IP欺骗?等等.这些问题随便一搜就能发现大量的贴子,其实说到底这些问题和LoadRunner的关系并不是很大,要去解决这些问题并不在于你对LoadRunner这个工具使用是否熟练,而在于我们网络基础知识是否扎实.例如第一个问题LoadRunner中为什么要进行关联?相信很多朋友都知道HTTP协议知道它是超文本传输协议,但是对于一些新手往往不能够详细的说出HTTP具体的内容,像HTTP工作的原理,HTTP协议为什么要使用基于TCP的协议而不使用UDP的协议,HTTP工作在OSI参考模型的哪一层?在HTTP协议上数据是怎么传输的等等.而只有当我们明白了这一切,自然而然就会明白为什么要使用关联,到最后你会发现这些问题其实根LoadRunner关系并不是很大.HTTP协议本质上是无状态的;对页面的每个请求都将被视为新请求,而且默认情况下,来自一个请求的信息对下一个请求不可用.在传统的Web编程中,这通常意味着在每一次往返行程中,与该页及该页上的控件相关联的所有信息都会丢失.例如,如果用户将信息输入到文本框,该信息将在从浏览器或客户端设备到<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>的往返行程中丢失,为了使用浏览网页,页与页是相互联系不去丢失这些信息,于是了就从现了Cookie,Session,查询字符串等等保持状态的技术.什么是Cookie?什么是Session?Cookie 和Session 有是怎么工作的?当我们明白了这些,很多的问题就自然而然的明白了,像这些都是基础的知识和LoadRunner关系大吗?不大.Cookie 是一些少量的数据,这些数据存储在客户端文件系统的文本文件中,或者存储在客户端浏览器会话的内存中.Cookie 包含特定于站点的信息(像用户名密码以及我们在网站一些个性化的设置等等),这些信息是随页输出一起由服务器发送到客户端的.如果浏览器使用的是 cookie,那么所有的数据都保存在浏览器端,比如我们登录以后,服务器设置了cookie用户名,那么当你再次请求服务器的时候,浏览器会将用户名一块发送给服务器,这些变量有一定的特殊标记.服务器会解释为cookie变量,所以只要不关闭浏览器,那么cookie变量一直是有效的,所以能够保证长时间不掉线..如果设置了的有效时间,那么它会将 cookie保存在客户端的硬盘上,下次再访问该网站的时候浏览器先检查有没有 cookie,如果有的话,就读取该 cookie,然后发送给服务器.这些是Cookie的工作过程,常看到论坛上一些朋友发贴子问使用LoadRunner时录制到了一些Cookie的信息,它是用来做什么的,看起来很烦可不可以把它删除掉?明白了这些细节的知识,你自然能明白那个Cookie的信息能不能删除掉.如果web服务器端使用的是session,那么所有的数据都保存在服务器上,客户端每次请求服务器的时候会发送当前会话的SessionId,服务器根据当前 SessionId唯一地标识在服务器上包含会话数据的浏览器,以确定用户是否登录或具有某种权限.不同的用户发送请求Web服务器会随机发送一个唯一的 SessionID.而我们使用LoadRunner录制时它会把我们SessionID写死,所以导致出错.这时候就得使用关联了,这样不仅明白了 LoadRunner怎样使用关联,而且还明白了为什么要使用关联?对于LoadRunner测试系统时如何选择协议?这个问题也是网络论讨的比较多的问题.要解决这个问题同样得依靠我们的扎实的网络基础,而不是对LoadRunner使用的熟练程度,首先我们得了解LoadRunner录制时的工作原理了,LoadRunner的录制和<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/" target="_blank" >QTP</A></STRONG>不一样,它不关心你的对象识别什么的,不关心你的什么界面之类的,不关心你使用什么语言编写的,LoadRunner有一个Agent进程,来专门监控客户端和服务器之间的通信,然后用自己的函数进行录制.LoadRunner录制的时候关心的是通信包,是客户端和服务器之间的数据包.说到这里,大家就比较清楚了,为什么有的时候不能录制呢?因为,协议不认识,导致LoadRunner截获的数据包不能解析,所以录制下来是空的.所以我们得熟悉什么是协议, 熟悉OSI参考模型,OSI参考模型中各层的作用,TCP协议栈各层的作用,熟悉TCP,UDP,ICMP等等协议.当我们明白了这些网络的基础知识后我们自然会明白应该如何去选择协议.另外关于LoadRunner中的如何进行IP欺骗?要解决这个问题同样得有良好的网络基础知识.其实当我们理解了IP 地址的格式,IP地址的分类,子网掩码的概念,以及知道怎么去进行非标准子网的划分方法 ,掌握了这些原理的东西,那么具体怎么在LoadRunner中如何进行IP欺骗,就非常简单了. 当然网络基础知识并不只是上面的而已,还包括路由器,交换机,加密技术等等这些基础的网络知识,这些远远比我们去学习怎么去使用LoadRunner更重要.#p#分页标题#e#</p>
<p>
	　　4为什么要掌握数据库知识</p>
<p>
	　　数据库的重要性我想是不言而喻的,性能测试产生的一个非常大的原因是因为数据大集中的趋势,测试从某种意义来讲就是对数据测试,而我们企业的核心数据是放在数据库中的.现在大型的WEB应用程序,都采用多层结构,像典型三层,用户界面层,数据逻辑层,数据层.而数据层,而数据层对我们整个WEB应用程序的性能是非常大的,对数据库的基础知识不懂,我们怎么去进行性能测试分析?怎么知道确定性能产生的瓶颈是否是数据库的原因,如何对系统进行调优?例如数据库模型设计不合理,一条坏的SQL语句就能影响到整个WEB应用程序的性能,所以熟悉SQL语句,建表,索引,存储过程,事务,触发器,并发等这些基础知识是必需得掌握的.</p>
]]></description>
    <pubDate>Wed, 15 Feb 2012 10:33:25 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>LoadRunner</category>
    <author>xuyubotest</author>
    <comments>csdn</comments>
</item>
<item>
    <title><![CDATA[微软SDL( Security Development Lifecycle)流程介绍]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/qita/vsts/2012/0208/204044.html</link>
    <description><![CDATA[<p>
	　　微软SDL( Security Development Lifecycle)流程，是一种专注于软件<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>安全保障的流程，为了实现保证最终的用户安全，在软件开发各阶段中引入安全和隐私问题。其中主要由以下7部分组成：</p>
<p>
	　　安全培训(training)：推广安全编程意识</p>
<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求分析</A></STRONG>(requirements)： 寻找安全嵌入的最优方式</p>
<p>
	　　系统设计(design): 威胁建模设计</p>
<p>
	　　实现(implementation)： 安全开发</p>
<p>
	　　验证(verification)： 黑/白盒测试</p>
<p>
	　　发布(release)： 最后检查确认</p>
<p>
	　　响应(response)：应急响应，bug跟踪解决</p>
<p>
	　　总结, 通过上面的介绍，我们发现微软SDL是将设计、代码和文档等与安全相关漏洞减到最少，在软件开发的生命周期中尽可能的早地发现解决相关漏洞建立的流程框架; 值得我们学习的地方是，我们可以借鉴微软SDL的流程框架建立符合公司自己的。</p>
<p>
	　　以下微软SDL流程框架图：</p>
<center>
	<img alt="" border="1" height="205" src="/uploads/allimg/120208/10040U1b-0.gif" width="814" /></center>
<p>
	　　微软SDL官方地址： http://www.microsoft.com/security/sdl/default.aspx</p>
<p>
	　　目前多数公司在安全方面都面临者诸多问题，如：</p>
<p>
	　　1 安全意识不足</p>
<p>
	　　2 缺少安全设计</p>
<p>
	　　3 缺少安全编程规范</p>
<p>
	　　4 频繁的迭代更新版本</p>
<p>
	　　5 压缩项目周期</p>
<p>
	　　。。。等，当然还有更多，在此就不在列举</p>
<p>
	　　所以借鉴微软SDL流程框架，本文作者构建符合自己公司的SDL流程框架：</p>
<p>
	　　1 <STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/aqcs/" target="_blank" >安全测试</A></STRONG>(通过黑/白盒测试，发现公司系统潜在的漏洞，构建漏洞库)</p>
<p>
	　　2 安全培训(通过对常见漏洞，尤其是对用户及公司造成危害性大的漏洞培训形成<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/jjfa/" target="_blank" >解决方案</A></STRONG>措施)</p>
<p>
	　　3 需求分析评估(确切的来讲，这个层次应属于信息安全范围，针对各层次进行安全信息识别和漏洞评估，制定相关安全目标等内容)</p>
<p>
	　　4 系统设计( 威胁模型建立，进行架构分析，分解各应用程序，识别风险，识别漏洞等)</p>
<p>
	　　5 编码实现(进行相关代码评审，漏洞扫描检查)</p>
<p>
	　　6 发布( 上线审核机制，安全监控(日志，网站，<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>等)，Bug管理，故障事件管理等)</p>
<p>
	　　通过上面大家可以发现微软SDL的&ldquo;响应&rdquo;环节去掉了，其实响应我个人理解将其融入以上6个环节中更有效，因为每个环节都需要应对;其中将安全测试和安全培训提至最前面，因为目前国内公司对安全其实了解甚少且比较偏面，所以最好的解决方法就是将问题摆出来，然后寻求解决之道!</p>
]]></description>
    <pubDate>Wed, 08 Feb 2012 10:35:36 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/120208/10040U1b-0-lp.gif</subImagePath>
     <category>VSTS</category>
    <author>卖烧烤的鱼</author>
    <comments>博客园</comments>
</item>
<item>
    <title><![CDATA[QTP自动化测试之VBScript基础(上)]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/2012/0207/204034.html</link>
    <description><![CDATA[<p>
	　　要想使用<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/" target="_blank" >QTP</A></STRONG>进行<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/zdcs/" target="_blank" >自动化测试</A></STRONG>，必须了解<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/vb/" target="_blank" >VB</A></STRONG>Script这门语言，对于使用过ASP或VB<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>的人来说，VBScript已经再熟悉不过了，但是没有接触过VBScript的同学也不要灰心，因为这门语言简单易学。</p>
<p>
	　　1. VBScript利器</p>
<p>
	　　2. Hello World</p>
<p>
	　　3. 数据类型</p>
<p>
	　　4. 变量</p>
<p>
	　　5. 常数</p>
<p>
	　　6. 运算符</p>
<p>
	　　1. VBScript利器</p>
<p>
	　　子曰：工欲善其事，必先利其器。学习一门语言自然是离不开工具及文档，有好的工具及文档在手，学习起来也会得心应手。在此，我推荐大家一个很不错的编辑工具&mdash;&mdash;VbsEdit，该工具既能编辑代码，又可调试代码，有不错的智能提示，还有很多示例代码。可惜不是免费使用，不过网上已经有绿色版，您可以搜索<STRONG><A href="http://www.ltesting.net/ceshi/down" target="_blank" >下载</A></STRONG>。若你已经安装了QTP，那么使用QTP工具也是一个不错的选择。参考文档可以使用在线版《Microsoft <STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/windows/" target="_blank" >Windows</A></STRONG>脚本技术》，也可以从网上搜索下载CHM文件。</p>
<p>
	　　2. Hello World</p>
<p>
	　　每种语言的入门都是一样，从简单的Hello World开始，我们也不例外。如何使用VBScript来弹出一个对话框显示Hello World问候语呢?很简单，代码如下：</p>
<p>
	　　?</p>
<table border="0" cellpadding="0" cellspacing="0">
	<tbody>
		<tr>
			<td class="gutter">
				<div class="line number1 index0 alt2">
					1</div>
				<div class="line number2 index1 alt1">
					2</div>
				<div class="line number3 index2 alt2">
					3</div>
				<div class="line number4 index3 alt1">
					4</div>
			</td>
			<td class="code">
				<div class="container">
					<div class="line number1 index0 alt2">
						<font face="新宋体"><code class="vb plain">MsgBox(</code><code class="vb string">&quot;Hello world!&quot;</code><code class="vb plain">) </code></font></div>
					<div class="line number2 index1 alt1">
						<font face="新宋体"><code class="vb plain">MsgBox </code><code class="vb string">&quot;Hello world!&quot;</code></font></div>
					<div class="line number3 index2 alt2">
						<font face="新宋体"><code class="vb plain">result = MsgBox(</code><code class="vb string">&quot;Hello World!&quot;</code><code class="vb plain">, vbOKOnly, </code><code class="vb string">&quot;Greeting&quot;</code><code class="vb plain">) </code></font></div>
					<div class="line number4 index3 alt1">
						<font face="新宋体"><code class="vb plain">MsgBox </code><code class="vb string">&quot;Hello World!&quot;</code><code class="vb plain">, vbOKOnly, </code><code class="vb string">&quot;Greeting&quot;</code></font></div>
				</div>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　既然在此出现的第一个函数是MsgBox，那么就简单介绍一下该函数，其签名如下:</p>
<p>
	　　?</p>
<table border="0" cellpadding="0" cellspacing="0">
	<tbody>
		<tr>
			<td class="gutter">
				<div class="line number1 index0 alt2">
					1</div>
			</td>
			<td class="code">
				<div class="container">
					<div class="line number1 index0 alt2">
						<code class="vb plain"><font face="新宋体">MsgBox(prompt[, buttons][, title][, helpfile, context])</font></code></div>
				</div>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　主要参数：</p>
<p>
	　　prompt：为要显示的消息，其他带[]参数为可选参数;</p>
<p>
	　　buttons：为显示对话框按钮及类型，默认值为0，即只显示&ldquo;确定&rdquo;按钮;</p>
<p>
	　　title：为对话框标题栏文字。</p>
<p>
	　　MsgBox函数也有返回值，当你点击确定或取消按钮时，其返回的值是不一样的。其他详细内容，大家可以去查阅参考文档，这里就不逐一说明。</p>
<p>
	　　3. 数据类型</p>
<p>
	　　VBScript只有一种数据类型&mdash;&mdash;Vari<STRONG><A href="http://www.ltesting.net/ceshi/open/qtkycsgj/ant/" target="_blank" >ant</A></STRONG>，它是根据上下文来判断是数字还是字符串。因为Variant是VBScript中唯一的数据类型，所以它也是VBScript中所有函数的返回值的数据类型。为了进一步区分数据类型，它包含如下数据子类型：</p>
<table class="grid">
	<tbody>
		<tr>
			<th width="15%">
				子类型</th>
			<th width="85%">
				描述</th>
		</tr>
		<tr>
			<td>
				Empty</td>
			<td>
				未初始化的<b>Variant</b>。对于数值变量，值为0；对于字符串变量，值为零长度字符串 (&quot;&quot;)。</td>
		</tr>
		<tr>
			<td>
				Null</td>
			<td>
				不包含任何有效数据的<b>Variant</b>。</td>
		</tr>
		<tr>
			<td>
				Boolean</td>
			<td>
				包含True或False。</td>
		</tr>
		<tr>
			<td>
				Byte</td>
			<td>
				包含0到255之间的整数。</td>
		</tr>
		<tr>
			<td>
				Integer</td>
			<td>
				包含-32,768到32,767之间的整数。</td>
		</tr>
		<tr>
			<td>
				Currency</td>
			<td>
				-922,337,203,685,477.5808到922,337,203,685,477.5807。</td>
		</tr>
		<tr>
			<td>
				Long</td>
			<td>
				包含-2,147,483,648到2,147,483,647之间的整数。</td>
		</tr>
		<tr>
			<td>
				Single</td>
			<td>
				包含单精度浮点数，负数范围从-3.402823E38到-1.401298E-45，正数范围从1.401298E-45到3.402823E38。</td>
		</tr>
		<tr>
			<td>
				Double</td>
			<td>
				包含双精度浮点数，负数范围从-1.79769313486232E308到-4.94065645841247E-324，正数范围从4.94065645841247E-324到1.79769313486232E308。</td>
		</tr>
		<tr>
			<td>
				Date (Time)</td>
			<td>
				包含表示日期的数字，日期范围从公元100年1月1日到公元9999年12月31日。</td>
		</tr>
		<tr>
			<td>
				String</td>
			<td>
				包含变长字符串，最大长度可为20亿个字符。</td>
		</tr>
		<tr>
			<td>
				Object</td>
			<td>
				包含对象。</td>
		</tr>
		<tr>
			<td>
				Error</td>
			<td>
				包含错误号。</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　您可以使用转换函数(CInt，CStr等等)来转换数据的子类型。另外，可使用VarType函数返回数据的Variant子类型。</p>
<p>
	　　4. 变量</p>
<p>
	　　4.1. 变量声明</p>
<p>
	　　变量声明有两种方式&mdash;&mdash;显式与隐式，显式使用Dim、Public、Private语句进行声明，隐式直接使用变量名。使用隐式声明方式的习惯不好，因为这样有时会由于变量名拼错而导致程序运行出现意外，因此，最好在每个脚本开始第一行使用Option Explicit语句强制显式声明所有变量。声明示例如下:</p>
<p>
	　　?</p>
<table border="0" cellpadding="0" cellspacing="0">
	<tbody>
		<tr>
			<td class="gutter">
				<div class="line number1 index0 alt2">
					1</div>
				<div class="line number2 index1 alt1">
					2</div>
				<div class="line number3 index2 alt2">
					3</div>
				<div class="line number4 index3 alt1">
					4</div>
			</td>
			<td class="code">
				<div class="container">
					<div class="line number1 index0 alt2">
						<code class="vb keyword"><font face="新宋体">Option</font></code> <code class="vb plain"><font face="新宋体">Explicit </font></code></div>
					<div class="line number2 index1 alt1">
						<code class="vb keyword"><font face="新宋体">Dim</font></code> <font face="新宋体"><code class="vb plain">i, conn&nbsp;&nbsp; </code><code class="vb comments">&#39;声明多个变量时用逗号隔开 </code></font></div>
					<div class="line number3 index2 alt2">
						<code class="vb keyword"><font face="新宋体">Public</font></code> <code class="vb plain"><font face="新宋体">UserName, Password </font></code></div>
					<div class="line number4 index3 alt1">
						<code class="vb keyword"><font face="新宋体">Private</font></code> <code class="vb plain"><font face="新宋体">m_id</font></code></div>
				</div>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　注意：在VBScript中，变量名是不区分大小写，即userName与UserName是指同一个变量。</p>
<p>
	　　4.2. 命名规则</p>
<p>
	　　VBScript中变量命名是有其规则标准的，变量命名必须遵循：</p>
<p>
	　　第一个字符必须是字母。</p>
<p>
	　　不能包含嵌入的句点。</p>
<p>
	　　长度不能超过255个字符。</p>
<p>
	　　在被声明的作用域内必须唯一。</p>
<p>
	　　4.3. 作用域与存活期</p>
<p>
	　　变量的作用域由声明它的位置所决定。如果在过程中声明的，则只有该过程可以使用，即过程级变量;如果在过程之外声明的，则该变量可以被脚本中所有过程所使用，即Script级变量。</p>
<p>
	　　变量所存在的时间为存活期。Script级变量的存活期为从被声明开始，直到脚本运行结束为止;过程级变量的存活期仅是过程被调用执行开始到结束的时间。不同的过程可以使用相同的变量名，因为局部变量只有声明它的过程才能识别。</p>
<p>
	　　4.4. 变量赋值</p>
<p>
	　　给变量赋值很简单，使用等号进行赋值，等号左边为变量名，右边为变量值。若该变量是对象引用级别的，则需使用Set语句。示例代码如下：</p>
<p>
	　　?</p>
<table border="0" cellpadding="0" cellspacing="0">
	<tbody>
		<tr>
			<td class="gutter">
				<div class="line number1 index0 alt2">
					1</div>
				<div class="line number2 index1 alt1">
					2</div>
				<div class="line number3 index2 alt2">
					3</div>
				<div class="line number4 index3 alt1">
					4</div>
			</td>
			<td class="code">
				<div class="container">
					<div class="line number1 index0 alt2">
						<code class="vb keyword"><font face="新宋体">Dim</font></code> <code class="vb plain"><font face="新宋体">i, conn, ui </font></code></div>
					<div class="line number2 index1 alt1">
						<code class="vb plain"><font face="新宋体">i = 0 </font></code></div>
					<div class="line number3 index2 alt2">
						<code class="vb keyword"><font face="新宋体">Set</font></code> <font face="新宋体"><code class="vb plain">conn = CreateObject(</code><code class="vb string">&quot;ADODB.Connection&quot;</code><code class="vb plain">) </code></font></div>
					<div class="line number4 index3 alt1">
						<code class="vb keyword"><font face="新宋体">Set</font></code> <font face="新宋体"><code class="vb plain">ui = </code><code class="vb keyword">New</code></font> <code class="vb plain"><font face="新宋体">UserInfo</font></code></div>
				</div>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　4.5. 标量与数组</p>
<p>
	　　只包含一个值的变量成为标量变量;有时候为了方便将一组相关值赋给一个变量,则成为数组变量。区别标量与数组的唯一方式是声明时数组变量名后面带有括号()。变量声明就不说了，前面已经提到，这里我们看看怎样声明一维数组及多维数组(最大60维&mdash;&mdash;:)只要您能够理解)。</p>
<p>
	　　?</p>
<table border="0" cellpadding="0" cellspacing="0">
	<tbody>
		<tr>
			<td class="gutter">
				<div class="line number1 index0 alt2">
					1</div>
				<div class="line number2 index1 alt1">
					2</div>
				<div class="line number3 index2 alt2">
					3</div>
				<div class="line number4 index3 alt1">
					4</div>
				<div class="line number5 index4 alt2">
					5</div>
				<div class="line number6 index5 alt1">
					6</div>
				<div class="line number7 index6 alt2">
					7</div>
				<div class="line number8 index7 alt1">
					8</div>
				<div class="line number9 index8 alt2">
					9</div>
			</td>
			<td class="code">
				<div class="container">
					<div class="line number1 index0 alt2">
						<code class="vb keyword"><font face="新宋体">Dim</font></code> <code class="vb plain"><font face="新宋体">a(9), table(2, 3) </font></code></div>
					<div class="line number2 index1 alt1">
						<code class="vb plain"><font face="新宋体">a(0) = 1 </font></code></div>
					<div class="line number3 index2 alt2">
						<code class="vb plain"><font face="新宋体">... </font></code></div>
					<div class="line number4 index3 alt1">
						<code class="vb plain"><font face="新宋体">a(9) = 11 </font></code></div>
					<div class="line number5 index4 alt2">
						<font face="新宋体"><code class="vb plain">MsgBox(a(1))&nbsp;&nbsp; </code><code class="vb comments">&#39;输出数组变量值 </code></font></div>
					<div class="line number6 index5 alt1">
						<code class="vb spaces"><font face="新宋体">&nbsp;</font></code></div>
					<div class="line number7 index6 alt2">
						<code class="vb plain"><font face="新宋体">table(0, 0) = 1 </font></code></div>
					<div class="line number8 index7 alt1">
						<code class="vb plain"><font face="新宋体">... </font></code></div>
					<div class="line number9 index8 alt2">
						<code class="vb plain"><font face="新宋体">table(2, 3) = 10</font></code></div>
				</div>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　我们也可以声明动态数组(在运行脚本时大小发生变化的数组)，使用Dim或ReDim语句，但括号中不包含任何数字。要使用动态数组，必须随后使用ReDim确定维数和每一维的大小。若同时使用Preserve关键字，则在重新调整大小时保留数组的内容。</p>
<p>
	　　?</p>
<table border="0" cellpadding="0" cellspacing="0">
	<tbody>
		<tr>
			<td class="gutter">
				<div class="line number1 index0 alt2">
					1</div>
				<div class="line number2 index1 alt1">
					2</div>
				<div class="line number3 index2 alt2">
					3</div>
				<div class="line number4 index3 alt1">
					4</div>
			</td>
			<td class="code">
				<div class="container">
					<div class="line number1 index0 alt2">
						<code class="vb keyword"><font face="新宋体">Dim</font></code> <code class="vb plain"><font face="新宋体">count, a() </font></code></div>
					<div class="line number2 index1 alt1">
						<code class="vb plain"><font face="新宋体">count = 9 </font></code></div>
					<div class="line number3 index2 alt2">
						<code class="vb keyword"><font face="新宋体">ReDim</font></code> <code class="vb plain"><font face="新宋体">a(count) </font></code></div>
					<div class="line number4 index3 alt1">
						<code class="vb keyword"><font face="新宋体">ReDim</font></code> <code class="vb keyword"><font face="新宋体">Preserve</font></code> <code class="vb plain"><font face="新宋体">a(10)</font></code></div>
				</div>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　5. 常数</p>
<p>
	　　常数在VBScript中是表示不变的值，用于代替数字或字符串。其内部定义了许多常数，都是以vb开头，例如在Hello World程序中涉及到的MsgBox常数&ldquo;vbOKOnly&rdquo;。除了MsgBox常数外，还有颜色常数、比较常数、日期和时间常数等等，详见参考文档。</p>
<p>
	　　内部自带常数，我们可以直接使用。当自带常数不能满足我们的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求</A></STRONG>时，我们也可以自定义常数，在VBScript中是使用Const语句来定义常数，该语句的签名如下：</p>
<p>
	　　?</p>
<table border="0" cellpadding="0" cellspacing="0">
	<tbody>
		<tr>
			<td class="gutter">
				<div class="line number1 index0 alt2">
					1</div>
			</td>
			<td class="code">
				<div class="container">
					<div class="line number1 index0 alt2">
						<font face="新宋体"><code class="vb plain">[</code><code class="vb keyword">Public</code></font> <font face="新宋体"><code class="vb plain">| </code><code class="vb keyword">Private</code><code class="vb plain">] </code><code class="vb keyword">Const</code></font> <code class="vb plain"><font face="新宋体">constname = expression</font></code></div>
				</div>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　主要参数：</p>
<p>
	　　constname：为常数名称，为了区分常数与变量，最好有一套自己的命名规则，这里推荐字母全大写，单词间用下划线分割;</p>
<p>
	　　expression：文字或其他常数，或包括除 Is 外的所有算术运算符和逻辑运算符的任意组合。</p>
<p>
	　　常数默认是Public级别，您也可以指定为Private级别，在同一行中声明多个常数需要用逗号分割，常数声明中不能使用变量、自定义函数及内部函数。下面是常数的一些示例代码：</p>
<p>
	　　?</p>
<table border="0" cellpadding="0" cellspacing="0">
	<tbody>
		<tr>
			<td class="gutter">
				<div class="line number1 index0 alt2">
					1</div>
				<div class="line number2 index1 alt1">
					2</div>
				<div class="line number3 index2 alt2">
					3</div>
			</td>
			<td class="code">
				<div class="container">
					<div class="line number1 index0 alt2">
						<code class="vb keyword"><font face="新宋体">Const</font></code> <font face="新宋体"><code class="vb plain">PI = 3.14&nbsp;&nbsp; </code><code class="vb comments">&#39;常数默认为公有。 </code></font></div>
					<div class="line number2 index1 alt1">
						<code class="vb keyword"><font face="新宋体">Private</font></code> <code class="vb keyword"><font face="新宋体">Const</font></code> <font face="新宋体"><code class="vb plain">STEP_APPLY = </code><code class="vb string">&quot;Apply&quot;</code></font>&nbsp;&nbsp; <code class="vb comments"><font face="新宋体">&#39;定义私有常数。 </font></code></div>
					<div class="line number3 index2 alt2">
						<code class="vb keyword"><font face="新宋体">Const</font></code> <font face="新宋体"><code class="vb plain">STEP_APPLY = </code><code class="vb string">&quot;Apply&quot;</code><code class="vb plain">, PI&nbsp; = 3.14&nbsp;&nbsp; </code><code class="vb comments">&#39;在一行上定义多个常数。</code></font></div>
				</div>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　6. 运算符</p>
<p>
	　　VBScript有一套完整的运算符，包括算术运算符、比较运算符、连接运算符和逻辑运算符。当表达式中含有多个运算符时，它们的运算优先级是：算术运算符 &gt; 比较运算符 &gt; 逻辑运算符。所有比较运算符的优先级相同，算术运算符和逻辑运算符的优先级如下所示：</p>
<p>
	　　6.1. 算术运算符</p>
<table class="grid">
	<tbody>
		<tr>
			<th width="50%">
				描述</th>
			<th width="50%">
				符号</th>
		</tr>
		<tr>
			<td>
				求幂</td>
			<td>
				^</td>
		</tr>
		<tr>
			<td>
				负号</td>
			<td>
				-</td>
		</tr>
		<tr>
			<td>
				乘</td>
			<td>
				*</td>
		</tr>
		<tr>
			<td>
				除</td>
			<td>
				/</td>
		</tr>
		<tr>
			<td>
				整除</td>
			<td>
				\</td>
		</tr>
		<tr>
			<td>
				求余</td>
			<td>
				Mod</td>
		</tr>
		<tr>
			<td>
				加</td>
			<td>
				+</td>
		</tr>
		<tr>
			<td>
				减</td>
			<td>
				-</td>
		</tr>
		<tr>
			<td>
				字符串连接</td>
			<td>
				&amp;</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　字符串连接 (&amp;) 运算符不是算术运算符，但是在优先级顺序中，它排在所有算术运算符之后和所有比较运算符之前。</p>
<p>
	　　6.2. 逻辑运算符</p>
<table class="grid">
	<tbody>
		<tr>
			<th width="50%">
				描述</th>
			<th width="50%">
				符号</th>
		</tr>
		<tr>
			<td>
				逻辑非</td>
			<td>
				Not</td>
		</tr>
		<tr>
			<td>
				逻辑与</td>
			<td>
				And</td>
		</tr>
		<tr>
			<td>
				逻辑或</td>
			<td>
				Or</td>
		</tr>
		<tr>
			<td>
				逻辑异或</td>
			<td>
				Xor</td>
		</tr>
		<tr>
			<td>
				逻辑等价</td>
			<td>
				Eqv</td>
		</tr>
		<tr>
			<td>
				逻辑隐含</td>
			<td>
				Imp</td>
		</tr>
	</tbody>
</table>
<p>
	　　6.3. 比较运算符</p>
<table class="grid">
	<tbody>
		<tr>
			<th width="50%">
				描述</th>
			<th width="50%">
				符号</th>
		</tr>
		<tr>
			<td>
				等于</td>
			<td>
				=</td>
		</tr>
		<tr>
			<td>
				不等于</td>
			<td>
				&lt;&gt;</td>
		</tr>
		<tr>
			<td>
				小于</td>
			<td>
				&lt;</td>
		</tr>
		<tr>
			<td>
				大于</td>
			<td>
				&gt;</td>
		</tr>
		<tr>
			<td>
				小于等于</td>
			<td>
				&lt;=</td>
		</tr>
		<tr>
			<td>
				大于等于</td>
			<td>
				&gt;=</td>
		</tr>
		<tr>
			<td>
				对象引用比较</td>
			<td>
				Is</td>
		</tr>
	</tbody>
</table>
<p>
	　　Is 运算符是对象引用比较运算符。它并不比较对象或对象的值，而只是进行检查，判断两个对象引用是否引用同一个对象。</p>
]]></description>
    <pubDate>Tue, 07 Feb 2012 10:27:40 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>QuickTestPro</category>
    <author>known</author>
    <comments>博客园</comments>
</item>
<item>
    <title><![CDATA[Loadrunner打不开WebTours的解决方法]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0202/203992.html</link>
    <description><![CDATA[<p>
	　　今天安装了Loadrunner9.0后，发现打开LR示例页面的时候会显示如下错误：</p>
<p>
	　　Internal error: your request was unsu<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>essful</p>
<p>
	　　Cannot create CGI process &ndash; program not found</p>
<p>
	　　解决方法：</p>
<p>
	　　打开WebTours文件夹下的run.bat，编辑其中的路径名</p>
<p>
	　　假如你的LR路径是：D:/LR/</p>
<p>
	　　你bat中的函数可能会是：</p>
<p>
	　　SET PATH=/bin</p>
<p>
	　　cd /WebTours</p>
<p>
	　　start xigui32.exe</p>
<p>
	　　更改一下，改成：</p>
<p>
	　　SET PATH=D:/LR/bin</p>
<p>
	　　cd D:/LR/WebTours</p>
<p>
	　　start xigui32.exe</p>
<p>
	　　保存文件，退出</p>
<p>
	　　关闭服务，然后运行run.bat，重新打开示例页面，搞定。</p>
<p>
	　　原理应该是xitami运行站点的时候需要调用<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >lr</A></STRONG> bin中的一些东西吧，不太清楚。</p>
<p>
	　　这个问题一般出现的原因是你在安装的时候没有选择默认的标准路径,也就是比如C:/Program Files/Mercury/LoadRunner/WebTours 这种标准路径，有可能你用的是D:/LR 等。</p>
<p>
	　　LR在安装的时候没有正确更改run.bat其中的参数，这应该算是LR的一个小小bug，呵呵。</p>
]]></description>
    <pubDate>Thu, 02 Feb 2012 09:59:39 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>LoadRunner</category>
    <author>刘永康</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[如何用好LoadRunner中的检查点]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0120/203946.html</link>
    <description><![CDATA[<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LR</A></STRONG>中检查点有两种：图片和文字。</p>
<p>
	　　常用检查点函数如下：</p>
<p>
	　　1)web_find()函数用于从 HTML 页中搜索指定的文本字符串;</p>
<p>
	　　2)web_reg_find()函数注册一个请求，以在下一个操作函数(如 web_url)检索到的HTML网页上搜索指定的文本字符串;</p>
<p>
	　　3)web_image_check()函数用于从HTML页面中查找指定的图片;</p>
<p>
	　　4)web_global_verfication()属于注册函数，注册一个在web页面中搜索文本字符串的请求，与web_reg_find只在下一个Action函数中执行搜索不同的是它在之后所有的Action类函数中执行搜索指定的文本字符串;</p>
<p>
	　　下面分别介绍以上函数的用法：</p>
<p>
	　　1、web_find()函数参数举例：</p>
<p>
	　　web_find(&quot;web_find&quot;,&quot;RighOf=a&quot;,&quot;LeftOf=b&quot;,&quot;What=name&quot;,LAST);</p>
<p>
	　　参数解释：&quot;web_find&quot;定义该查找函数的名称;&ldquo;LeftOf&rdquo;和&ldquo;RighOf=&rdquo;用来定义查找字符的左右边界;&ldquo;What=&rdquo;定义查找内容;</p>
<p>
	　　例如上述参数举例中的意思就是在页面中查找左边界为b，右边界为a，内容为name的信息;</p>
<p>
	　　使用该函数注意事项：该函数是在查找页面中的内容，所以要放在要查找的内容的后面;该函数只能在基于HTML模式录制的脚本中进行查找</p>
<p>
	　　注意事项：使用该函数时，要在Vuser-&gt;Run-Tme Settings中更改下设置</p>
<center>
	<img alt="" border="1" height="333" src="/uploads/allimg/120120/114G0F41-0.jpg" width="481" /></center>
<p>
	　　勾选Enable Image and text check</p>
<center>
	<img alt="" border="1" height="408" src="/uploads/allimg/120120/114G039D-1.jpg" width="555" /></center>
<p>
	　　系统默认是不勾选该选项的。</p>
<p>
	　　2、web_reg_find()函数参数举例：</p>
<p>
	　　web_reg_find(&quot;Search=Body&quot;,&quot;SaveCount=ddd&quot;,&quot;Test=aaa&quot;,LAST);</p>
<p>
	　　参数解释： Search用来定义查找范围，SaveCount定义查找计数变量名称，该参数可以记录在缓存中查找内容出现的次数，可以使用该值，来判断要查找的内容是否被找到;</p>
<p>
	　　例如上述参数举例中的意思就是Body中查找内容为aaa的信息，并将出现次数记录在变量ddd中;</p>
<p>
	　　【代码一：web_reg_find(&quot;Text=Payment Details&quot;,LAST);</p>
<p>
	　　代码思路：1.&ldquo;Payment Details&rdquo; 为你要检查的文本;</p>
<p>
	　　2. 脚本执行到此处，若在页面上找到了这几个字符串，那脚本继续执行下去;若没有找到，脚本将在此报错并且结束。】</p>
<p>
	　　【代码二：web_reg_find(&quot;Text=Payment Details&quot;, &quot;SaveCount=para_count&quot;, LAST); //check 的函数</p>
<p>
	　　web_submit_form(&quot;reservations.pl_2&quot;, //要check的页面的录制时的代码</p>
<p>
	　　&quot;Snapshot=t22.inf&quot;,</p>
<p>
	　　ITE<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/mda/" target="_blank" >MDA</A></STRONG>TA,</p>
<p>
	　　&quot;Name=outboundFlight&quot;, &quot;Value=003;0;06/23/2007&quot;, ENDITEM,</p>
<p>
	　　&quot;Name=reserveFlights.x&quot;, &quot;Value=61&quot;, ENDITEM,</p>
<p>
	　　&quot;Name=reserveFlights.y&quot;, &quot;Value=2&quot;, ENDITEM,</p>
<p>
	　　LAST);</p>
<p>
	　　if (atoi(lr_eval_string(&quot;{para_count}&quot;))&gt;0) //验证是否找到了页面上的要检查的字符串</p>
<p>
	　　lr_output_message(&quot;we find the string!&quot;);</p>
<p>
	　　else</p>
<p>
	　　lr_output_message(&quot;sorry,don&#39;t find the string!&quot;);</p>
<p>
	　　代码思路：1.&ldquo;Payment Details&rdquo; 为你要检查的文本;</p>
<p>
	　　2. 脚本执行到此处，不管页面上是否存在你要检查的字符串，脚本都不会报错，而是执行下去。</p>
<p>
	　　3. 此段代码将找到的你要检查的字符串的个数，存为一个参数。 然后在页面代码的后面，通过检查这个参数的值是否大于0，来判断是否找到了你所要检查的字符串。】</p>
<p>
	　　【代码三：</p>
<p>
	　　A. web_reg_find(&quot;Text=Payment De<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/testdirector/" target="_blank" >td</A></STRONG>ils&quot;, &quot;Fail=NotFound&quot;,LAST);或</p>
<p>
	　　B. web_reg_find(&quot;Text=Payment Detdils&quot;, &quot;Fail=Found&quot;,LAST);</p>
<p>
	　　代码思路：</p>
<p>
	　　1.&ldquo;Payment Details&rdquo; 为你要检查的文本;</p>
<p>
	　　2. 若是A代码：脚本执行到此处，若没有找到check的字符串，脚本将FAIL， 并且停止执行下去。反之，则一直执行下去。</p>
<p>
	　　3. 若是B代码：脚本执行到此处，若找到check的字符串，脚本将FAIL， 并且停止执行下去。反之，则一直执行下去】</p>
<p>
	　　使用该函数注意事项：该函数是在缓存中查找相应的内容，所以要放在查找内容之前;通常情况下写在如下六个函数之前：Web_castom_request(); web_image(); web_link(); web_submit_data(); web_submit_form(); web_url();</p>
<p>
	　　使用技巧：在该函数的参数中有个&ldquo;SaveCount&rdquo;，该参数可以记录在缓存中查找内容出现的次数，我们可以使用该值，来判断要查找的内容是否被找到，下面举个例子来说明：(引用LR的帮助中的例子)</p>
<p>
	　　// Run the Web Tours sample</p>
<p>
	　　web_url(&quot;MercuryWebTours&quot;,</p>
<p>
	　　&quot;URL=http://localhost/MercuryWebTours/&quot;,</p>
<p>
	　　&quot;Resource=0&quot;,</p>
<p>
	　　&quot;RecContentType=text/html&quot;,</p>
<p>
	　　&quot;Referer=&quot;,</p>
<p>
	　　&quot;Snapshot=t1.inf&quot;,</p>
<p>
	　　&quot;Mode=HTML&quot;,</p>
<p>
	　　LAST);</p>
<p>
	　　// Set up check for su<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>essful login by looking for &quot;Welcome&quot;</p>
<p>
	　　web_reg_find(&quot;Text=Welcome&quot;,</p>
<p>
	　　&quot;SaveCount=Welcome_Count&quot;,</p>
<p>
	　　LAST);</p>
<p>
	　　// Now log in</p>
<p>
	　　web_submit_form(&quot;login.pl&quot;,</p>
<p>
	　　&quot;Snapshot=t2.inf&quot;,#p#分页标题#e#</p>
<p>
	　　ITEMDATA,</p>
<p>
	　　&quot;Name=username&quot;, &quot;Value=jojo&quot;, ENDITEM,</p>
<p>
	　　Name=password&quot;, &quot;Value=bean&quot;, ENDITEM,</p>
<p>
	　　&quot;Name=login.x&quot;, &quot;Value=35&quot;, ENDITEM,</p>
<p>
	　　&quot;Name=login.y&quot;, &quot;Value=14&quot;, ENDITEM,</p>
<p>
	　　LAST);</p>
<p>
	　　// Check result</p>
<p>
	　　if (atoi(lr_eval_string(&quot;{Welcome_Count}&quot;)) &gt; 0){ //判断如果Welcome字符串出现次数大于0</p>
<p>
	　　lr_output_message(&quot;Log on successful.&quot;); }//在日志中输出Log on successful</p>
<p>
	　　else{ //如果出现次数小于等于</p>
<p>
	　　lr_error_message(&quot;Log on failed&quot;); //在日志中输出Log on failed</p>
<p>
	　　return(0); }</p>
<p>
	　　我觉得这个方法非常有用，我们可以举一反三，应用到我们实际的项目</p>
<p>
	　　注：在录制过程中添加的检查点，用到的函数是web_reg_find()，且参数只有&ldquo;Text=&rdquo;</p>
<p>
	　　3、web_image_check()函数参数说明：</p>
<p>
	　　web_image_check(&quot;web_image_check&quot;,&quot;Alt=&quot;,&quot;Src=&quot;,LAST);</p>
<p>
	　　参数解释：&ldquo;Alt&rdquo;和&ldquo;Src&rdquo;的值直接取该图片在网页源代码中相应参数的值;</p>
<p>
	　　注意事项：使用该函数时，要在Vuser-&gt;Run-Tme Settings中勾选Enable Image and text check，具体操作请看web_find()中的注意事项。</p>
<p>
	　　经过测试，该函数用到查找内容前面或后面，都不影响查找结果。</p>
<p>
	　　举例说明(脚本)</p>
<p>
	　　该脚本记录的是登陆系统后退出的操作，在脚本中用到atoi()函数和lr_eval_string(&rdquo;{SaveCount定义的变量}&rdquo;)两个函数结合使用，判断查找内容出现的次数是否大于0，若大于0，则输入登录成功的信息。</p>
<p>
	　　vuser_init()</p>
<p>
	　　{</p>
<p>
	　　web_url(&quot;xjcost&quot;,</p>
<p>
	　　&quot;URL=http://gczj-server8:9205/xjcost/&quot;,</p>
<p>
	　　&quot;Resource=0&quot;,</p>
<p>
	　　&quot;RecContentType=text/html&quot;,</p>
<p>
	　　&quot;Referer=&quot;,</p>
<p>
	　　&quot;Snapshot=t1.inf&quot;,</p>
<p>
	　　&quot;Mode=HTML&quot;,</p>
<p>
	　　EXTRARES,</p>
<p>
	　　&quot;Url=jsp/images/index/index.swf&quot;, ENDITEM,</p>
<p>
	　　&quot;Url=jsp/images/index/xxfb2.gif&quot;, ENDITEM,</p>
<p>
	　　&quot;Url=jsp/images/index/ywpt2.gif&quot;, ENDITEM,</p>
<p>
	　　LAST);</p>
<p>
	　　web_url(&quot;userAction.struts&quot;,</p>
<p>
	　　&quot;URL=http://gczj-server8:9205/xjcost/userAction.struts?actionType=reLogin&quot;,</p>
<p>
	　　&quot;Resource=0&quot;,</p>
<p>
	　　&quot;RecContentType=text/html&quot;,</p>
<p>
	　　&quot;Referer=&quot;,</p>
<p>
	　　&quot;Snapshot=t2.inf&quot;,</p>
<p>
	　　&quot;Mode=HTML&quot;,</p>
<p>
	　　LAST);</p>
<p>
	　　return 0;</p>
<p>
	　　}</p>
<p>
	　　Action()</p>
<p>
	　　{</p>
<p>
	　　lr_start_transaction(&quot;Log_on&quot;);</p>
<p>
	　　lr_rendezvous(&quot;Log_on&quot;);</p>
<p>
	　　web_add_cookie(&quot;userAccount=admin; DOMAIN=gczj-server8&quot;);</p>
<p>
	　　web_reg_find(&quot;Text=欢迎您&quot;,</p>
<p>
	　　&quot;SaveCount=欢迎您_Count&quot;,</p>
<p>
	　　LAST);</p>
<p>
	　　web_image_check(&quot;web_image_check&quot;,</p>
<p>
	　　&quot;Src=/xjcost/jsp/images/index1/edit_01.gif&quot;,</p>
<p>
	　　LAST);</p>
<p>
	　　web_submit_data(&quot;userLogin.struts&quot;,</p>
<p>
	　　&quot;Action=http://gczj-server8:9205/xjcost/userLogin.struts?actionType=userLogin&quot;,</p>
<p>
	　　&quot;Method=POST&quot;,</p>
<p>
	　　&quot;RecContentType=text/html&quot;,</p>
<p>
	　　&quot;Referer=http://gczj-server8:9205/xjcost/userAction.struts?actionType=reLogin&quot;,</p>
<p>
	　　&quot;Snapshot=t3.inf&quot;,</p>
<p>
	　　&quot;Mode=HTML&quot;,</p>
<p>
	　　ITEMDATA,</p>
<p>
	　　&quot;Name=userAccount&quot;, &quot;Value=admin&quot;, ENDITEM,</p>
<p>
	　　&quot;Name=pwd&quot;, &quot;Value=1111&quot;, ENDITEM,</p>
<p>
	　　EXTRARES,</p>
<p>
	　　&quot;Url=jsp/images/index1/edit_01a.gif&quot;, &quot;Referer=http://gczj-server8:9205/xjcost/userLogin.struts?actionType=userLogin&quot;, ENDITEM,</p>
<p>
	　　LAST);</p>
<p>
	　　web_find(&quot;web_find&quot;,</p>
<p>
	　　&quot;What=欢迎您&quot;,</p>
<p>
	　　LAST);</p>
<p>
	　　lr_end_transaction(&quot;Log_on&quot;,LR_AUTO);</p>
<p>
	　　//检查是否登录成功</p>
<p>
	　　//如果&ldquo;欢迎您&rdquo;这个字符出现次数大于0，输出&ldquo;Log on successfully!&rdquo;</p>
<p>
	　　if(atoi(lr_eval_string(&quot;{欢迎您_Count}&quot;))&gt;0)</p>
<p>
	　　lr_output_message(&quot;Log on successfully!&quot;);</p>
<p>
	　　else</p>
<p>
	　　lr_error_message(&quot;Log on failed!&quot;);</p>
<p>
	　　return 0;</p>
<p>
	　　return 0;</p>
<p>
	　　}</p>
<p>
	　　//atoi()函数的作用是将一个ASCII字符串转换为整型</p>
<p>
	　　//lr_eval_string()函数作用是取得参数值，将字符串变量中的参数值替换为当前的参数值并将这个字符串返回</p>
<p>
	　　vuser_end()</p>
<p>
	　　{</p>
<p>
	　　lr_think_time(4);</p>
<p>
	　　web_url(&quot;userAction.struts_2&quot;,</p>
<p>
	　　&quot;URL=http://gczj-server8:9205/xjcost/userAction.struts?actionType=reLogin&quot;,</p>
<p>
	　　&quot;Resource=0&quot;,</p>
<p>
	　　&quot;RecContentType=text/html&quot;,</p>
<p>
	　　&quot;Referer=&quot;,#p#分页标题#e#</p>
<p>
	　　&quot;Snapshot=t4.inf&quot;,</p>
<p>
	　　&quot;Mode=HTML&quot;,</p>
<p>
	　　LAST);</p>
<p>
	　　return 0;</p>
<p>
	　　}</p>
<p>
	　　Global.h：</p>
<p>
	　　#ifndef _GLOBALS_H</p>
<p>
	　　#define _GLOBALS_H</p>
<p>
	　　//--------------------------------------------------------------------</p>
<p>
	　　// Include Files</p>
<p>
	　　#include &quot;lrun.h&quot;</p>
<p>
	　　#include &quot;web_api.h&quot;</p>
<p>
	　　#include &quot;lrw_custom_body.h&quot;</p>
<p>
	　　//--------------------------------------------------------------------</p>
<p>
	　　// Global Variables</p>
<p>
	　　#endif // _GLOBALS_H</p>
<p>
	　　Replay Log常见信息说明</p>
<p>
	　　1、web_find()和web_image_check()函数的日志信息(这两个日志信息实际上是一样的，只是输出的函数名和参数不同)</p>
<p>
	　　1)信息1Action.c(22): Verification checks not enabled. web_image_check is skipped. See the &#39;Run-time settings/Preferences/Checks&#39;</p>
<p>
	　　[MsgId: MMSG-27197]</p>
<p>
	　　Action.c(22): web_image_check was successful</p>
<p>
	　　[MsgId: MMSG-26392]</p>
<p>
	　　出现该信息，说明没有勾选Enable Image and text check</p>
<p>
	　　2)信息2Action.c(22): &quot;web_image_check&quot; succeeded (1 occurrence(s) found. Alt=&quot;&quot;, Src=&quot;/xjcost/jsp/images/index1/edit_01.gif&quot;)</p>
<p>
	　　[MsgId: MMSG-27192]</p>
<p>
	　　Action.c(22): web_image_check was successful</p>
<p>
	　　[MsgId: MMSG-26392]</p>
<p>
	　　出现该信息，说明检查点设置成功，且已经查找到信息</p>
<p>
	　　3)信息3Action.c(22): Error -27191: &quot;web_image_check&quot; failed (0 occurrence(s) found. Alt=&quot;&quot;, Src=&quot;/xjcost/jsp/images/index1/edit_1.gif&quot;)</p>
<p>
	　　[MsgId: MERR-27191]</p>
<p>
	　　Action.c(22): web_image_check highest severity level was &quot;ERROR&quot;</p>
<p>
	　　[MsgId: MMSG-26391]</p>
<p>
	　　出现该信息，说明要查找的内容没有找到。这时依次尝试以下操作：</p>
<p>
	　　(1)检查参数的信息是否写错;</p>
<p>
	　　(2)如果是web_find(),检查函数的位置是否在要查找内容的后面;</p>
<p>
	　　(3)如果是web_image_check()，查看该图片的源代码，看其是否是这个页面上的图片，很可能是图片选择错误，即所选图片不属于该页面。</p>
<p>
	　　2、web_reg_find()函数的日志信息</p>
<p>
	　　1)信息1Action.c(15): Registering web_reg_find was successful</p>
<p>
	　　[MsgId: MMSG-26390]</p>
<p>
	　　出现该信息，说明内容已查找到</p>
<p>
	　　2)信息2Action.c(27): Error -26366: &quot;Text=ABC&quot; not found for web_reg_find</p>
<p>
	　　[MsgId: MERR-26366]</p>
<p>
	　　Action.c(27): web_submit_data(&quot;userLogin.struts&quot;) highest severity level was &quot;ERROR&quot;, 18364 body bytes, 918 header bytes, 13 chunking overhead bytes</p>
<p>
	　　[MsgId: MMSG-26387]</p>
<p>
	　　该信息在replay log页面是红色显示的，说明没有找到内容，出现此情况尝试以下两个操作：</p>
<p>
	　　(1)参数的信息是否正确;</p>
<p>
	　　(2)查看该函数是否在查找内容的前面。</p>
<p>
	　　插入函数的方法：</p>
<p>
	　　1、 手工写入，在需要插入函数的位置手工写入该函数;</p>
<p>
	　　2、 光标停留在要插入函数的位置，在INSERT菜单中，选择new step，在列表中选择或查找要插入的函数，根据提示填写必要的参数;</p>
<p>
	　　3、 在tree view模式下，在树状菜单中选中要插入函数的位置，右键，选择insert after或insert before，根据提示填写必要的参数;</p>
<p>
	　　总结：</p>
<p>
	　　1、 这两个函数函数类型不同，WEB_FIND是普通函数，WEB_REG_FIND是注册函数;</p>
<p>
	　　2、 WEB_FIND使用时必须开启内容检查选项，而WEB_REG_FIND则不没有此限制;</p>
<p>
	　　3、 WEB_FIND只能用在基于HTML模式录制的脚本中，而WEB_REG_FIND没有此限制;</p>
<p>
	　　4、 WEB_FIND是在返回的页面中进行内容查找，WEB_REG_FIND是在缓存中进行查找;</p>
<p>
	　　5、 WEB_FIND在执行效率上不如WEB_REG_FIND;</p>
]]></description>
    <pubDate>Fri, 20 Jan 2012 11:45:12 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/120120/114G0F41-0-lp.jpg</subImagePath>
     <category>LoadRunner</category>
    <author>xql00163com</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[QTP自动化测试之VBScript对象]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/2012/0118/203937.html</link>
    <description><![CDATA[<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/vb/" target="_blank" >VB</A></STRONG>Script作为<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/zdcsjbyy/" target="_blank" >脚本语言</A></STRONG>不仅能够编写简单的脚本，而且还能够创建及使用对象编写复杂的脚本，如Class对象，数据字典，操作文件夹及文件，错误处理，正则表达式等等。</p>
<p>
	　　1. Class对象</p>
<p>
	　　2. Dictionary对象</p>
<p>
	　　3. FileSystemObject对象</p>
<p>
	　　4. Err对象</p>
<p>
	　　5. RegExp对象</p>
<p>
	　　1. Class对象</p>
<p>
	　　使用Class语句可以创建一个对象，可以为它编写字段、属性及方法，它只有两个对象事件&mdash;&mdash;Initialize与Terminate。首先来看一个简单的Class示例：</p>
<p>
	　　?</p>
<table border="0" cellpadding="0" cellspacing="0">
	<tbody>
		<tr>
			<td class="gutter">
				<div class="line number1 index0 alt2">
					1</div>
				<div class="line number2 index1 alt1">
					2</div>
				<div class="line number3 index2 alt2">
					3</div>
				<div class="line number4 index3 alt1">
					4</div>
				<div class="line number5 index4 alt2">
					5</div>
				<div class="line number6 index5 alt1">
					6</div>
				<div class="line number7 index6 alt2">
					7</div>
				<div class="line number8 index7 alt1">
					8</div>
				<div class="line number9 index8 alt2">
					9</div>
				<div class="line number10 index9 alt1">
					10</div>
				<div class="line number11 index10 alt2">
					11</div>
				<div class="line number12 index11 alt1">
					12</div>
				<div class="line number13 index12 alt2">
					13</div>
				<div class="line number14 index13 alt1">
					14</div>
				<div class="line number15 index14 alt2">
					15</div>
				<div class="line number16 index15 alt1">
					16</div>
				<div class="line number17 index16 alt2">
					17</div>
				<div class="line number18 index17 alt1">
					18</div>
				<div class="line number19 index18 alt2">
					19</div>
				<div class="line number20 index19 alt1">
					20</div>
				<div class="line number21 index20 alt2">
					21</div>
				<div class="line number22 index21 alt1">
					22</div>
				<div class="line number23 index22 alt2">
					23</div>
				<div class="line number24 index23 alt1">
					24</div>
				<div class="line number25 index24 alt2">
					25</div>
				<div class="line number26 index25 alt1">
					26</div>
				<div class="line number27 index26 alt2">
					27</div>
				<div class="line number28 index27 alt1">
					28</div>
				<div class="line number29 index28 alt2">
					29</div>
				<div class="line number30 index29 alt1">
					30</div>
				<div class="line number31 index30 alt2">
					31</div>
				<div class="line number32 index31 alt1">
					32</div>
				<div class="line number33 index32 alt2">
					33</div>
				<div class="line number34 index33 alt1">
					34</div>
				<div class="line number35 index34 alt2">
					35</div>
				<div class="line number36 index35 alt1">
					36</div>
				<div class="line number37 index36 alt2">
					37</div>
			</td>
			<td class="code">
				<div class="container">
					<div class="line number1 index0 alt2">
						<code class="vb keyword"><font face="新宋体">Class</font></code> <code class="vb plain"><font face="新宋体">User </font></code></div>
					<div class="line number2 index1 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb comments">&#39;私有字段，也可以使用Public语句定义公有字段 </code></font></div>
					<div class="line number3 index2 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Private</code></font> <code class="vb plain"><font face="新宋体">m_UserName </font></code></div>
					<div class="line number4 index3 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Private</code></font> <code class="vb plain"><font face="新宋体">m_Profile </font></code></div>
					<div class="line number5 index4 alt2">
						<code class="vb spaces"><font face="新宋体">&nbsp;</font></code></div>
					<div class="line number6 index5 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb comments">&#39;Initialize事件相当于构造函数 </code></font></div>
					<div class="line number7 index6 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Private</code></font> <code class="vb keyword"><font face="新宋体">Sub</font></code> <code class="vb plain"><font face="新宋体">Class_Initialize </font></code></div>
					<div class="line number8 index7 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">m_UserName = Empty&nbsp;&nbsp; </code><code class="vb comments">&#39;设置UserName初始值为空字符串 </code></font></div>
					<div class="line number9 index8 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">End</code></font> <code class="vb keyword"><font face="新宋体">Sub</font></code></div>
					<div class="line number10 index9 alt1">
						<code class="vb spaces"><font face="新宋体">&nbsp;</font></code></div>
					<div class="line number11 index10 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb comments">&#39;Terminate事件相当于析构函数 </code></font></div>
					<div class="line number12 index11 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Private</code></font> <code class="vb keyword"><font face="新宋体">Sub</font></code> <code class="vb plain"><font face="新宋体">Class_Terminate </font></code></div>
					<div class="line number13 index12 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Set</code></font> <font face="新宋体"><code class="vb plain">m_Profile = </code><code class="vb keyword">Nothing</code></font>&nbsp;&nbsp; <code class="vb comments"><font face="新宋体">&#39;将对象设置为Nothing，销毁对象 </font></code></div>
					<div class="line number14 index13 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">End</code></font> <code class="vb keyword"><font face="新宋体">Sub</font></code></div>
					<div class="line number15 index14 alt2">
						<code class="vb spaces"><font face="新宋体">&nbsp;</font></code></div>
					<div class="line number16 index15 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb comments">&#39;Property Get语句，获取属性值或对象引用，Default只与Public一起使用，表示该属性为类的默认属性 </code></font></div>
					<div class="line number17 index16 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Public</code></font> <code class="vb keyword"><font face="新宋体">Default</font></code> <code class="vb keyword"><font face="新宋体">Property</font></code> <code class="vb keyword"><font face="新宋体">Get</font></code> <code class="vb plain"><font face="新宋体">UserName </font></code></div>
					<div class="line number18 index17 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">UserName = m_UserName </code></font></div>
					<div class="line number19 index18 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">End</code></font> <code class="vb keyword"><font face="新宋体">Property</font></code></div>
					<div class="line number20 index19 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb comments">&#39;Property Let语句，设置属性值 </code></font></div>
					<div class="line number21 index20 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Public</code></font> <code class="vb keyword"><font face="新宋体">Property</font></code> <code class="vb keyword"><font face="新宋体">Let</font></code> <code class="vb plain"><font face="新宋体">UserName(newUserName) </font></code></div>
					<div class="line number22 index21 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">m_UserName = newUserName </code></font></div>
					<div class="line number23 index22 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">End</code></font> <code class="vb keyword"><font face="新宋体">Property</font></code></div>
					<div class="line number24 index23 alt1">
						<code class="vb spaces"><font face="新宋体">&nbsp;</font></code></div>
					<div class="line number25 index24 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Public</code></font> <code class="vb keyword"><font face="新宋体">Property</font></code> <code class="vb keyword"><font face="新宋体">Get</font></code> <code class="vb plain"><font face="新宋体">Profile </font></code></div>
					<div class="line number26 index25 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Set</code></font> <code class="vb plain"><font face="新宋体">Profile = m_Profile </font></code></div>
					<div class="line number27 index26 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">End</code></font> <code class="vb keyword"><font face="新宋体">Property</font></code></div>
					<div class="line number28 index27 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb comments">&#39;Property Set语句，设置属性对象引用 </code></font></div>
					<div class="line number29 index28 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Public</code></font> <code class="vb keyword"><font face="新宋体">Property</font></code> <code class="vb keyword"><font face="新宋体">Set</font></code> <code class="vb plain"><font face="新宋体">Profile(newProfile) </font></code></div>
					<div class="line number30 index29 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Set</code></font> <code class="vb plain"><font face="新宋体">m_Profile = newProfile </font></code></div>
					<div class="line number31 index30 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">End</code></font> <code class="vb keyword"><font face="新宋体">Property</font></code></div>
					<div class="line number32 index31 alt1">
						<code class="vb spaces"><font face="新宋体">&nbsp;</font></code></div>
					<div class="line number33 index32 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb comments">&#39;ToString方法 </code></font></div>
					<div class="line number34 index33 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Public</code></font> <code class="vb keyword"><font face="新宋体">Function</font></code> <code class="vb plain"><font face="新宋体">ToString() </font></code></div>
					<div class="line number35 index34 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">ToString = </code><code class="vb string">&quot;Hello! &quot;</code></font> <font face="新宋体"><code class="vb plain">&amp; </code><code class="vb keyword">Me</code><code class="vb plain">.UserName&nbsp;&nbsp; </code><code class="vb comments">&#39;Me相当于C#中的this关键字 </code></font></div>
					<div class="line number36 index35 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">End</code></font> <code class="vb keyword"><font face="新宋体">Function</font></code></div>
					<div class="line number37 index36 alt2">
						<code class="vb keyword"><font face="新宋体">End</font></code> <code class="vb keyword"><font face="新宋体">Class</font></code></div>
				</div>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　用VBScript创建的对象并不是真正的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/mxdx/" target="_blank" >面向对象</A></STRONG>，它不能继承和实现多态，但是在<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/" target="_blank" >QTP</A></STRONG>对象模型Utility中，提供了一个RegisterUserFunc方法可以覆写对象的方法，但这也不是真正意义上的面向对象。Class及其成员如何创建，上面已经简单介绍过，若要对其中的一些语句进一步了解，还需要去仔细阅读一些参考文档。下面我们来看看如何调用对象，在《VBScript基础上》变量赋值中也已经提到过。</p>
<p>
	　　?</p>
<table border="0" cellpadding="0" cellspacing="0">
	<tbody>
		<tr>
			<td class="gutter">
				<div class="line number1 index0 alt2">
					1</div>
				<div class="line number2 index1 alt1">
					2</div>
				<div class="line number3 index2 alt2">
					3</div>
				<div class="line number4 index3 alt1">
					4</div>
			</td>
			<td class="code">
				<div class="container">
					<div class="line number1 index0 alt2">
						<code class="vb keyword"><font face="新宋体">Dim</font></code> <font face="新宋体"><code class="vb plain">u&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code><code class="vb comments">&#39;定义对象变量名，注意变量名不能与类名相同，即使是大小写不同 </code></font></div>
					<div class="line number2 index1 alt1">
						<code class="vb keyword"><font face="新宋体">Set</font></code> <font face="新宋体"><code class="vb plain">u = </code><code class="vb keyword">New</code></font> <font face="新宋体"><code class="vb plain">User&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code><code class="vb comments">&#39;创建对象用New语句 </code></font></div>
					<div class="line number3 index2 alt2">
						<font face="新宋体"><code class="vb plain">u.UserName = </code><code class="vb string">&quot;known&quot;</code></font>&nbsp;&nbsp; <code class="vb comments"><font face="新宋体">&#39;给属性赋值 </font></code></div>
					<div class="line number4 index3 alt1">
						<font face="新宋体"><code class="vb plain">MsgBox u.ToString()&nbsp;&nbsp;&nbsp; </code><code class="vb comments">&#39;调用方法</code></font></div>
				</div>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　2. Dictionary对象</p>
<p>
	　　Dictionary是存储数据键和项目对的对象，其主要属性有Count、Item、Key，主要方法有Add、Exists、Items、Keys、Remove、RemoveAll。下面是该对象的一个综合示例：</p>
<p>
	　　?</p>
<table border="0" cellpadding="0" cellspacing="0">
	<tbody>
		<tr>
			<td class="gutter">
				<div class="line number1 index0 alt2">
					1</div>
				<div class="line number2 index1 alt1">
					2</div>
				<div class="line number3 index2 alt2">
					3</div>
				<div class="line number4 index3 alt1">
					4</div>
				<div class="line number5 index4 alt2">
					5</div>
				<div class="line number6 index5 alt1">
					6</div>
				<div class="line number7 index6 alt2">
					7</div>
				<div class="line number8 index7 alt1">
					8</div>
				<div class="line number9 index8 alt2">
					9</div>
				<div class="line number10 index9 alt1">
					10</div>
				<div class="line number11 index10 alt2">
					11</div>
				<div class="line number12 index11 alt1">
					12</div>
				<div class="line number13 index12 alt2">
					13</div>
				<div class="line number14 index13 alt1">
					14</div>
				<div class="line number15 index14 alt2">
					15</div>
				<div class="line number16 index15 alt1">
					16</div>
				<div class="line number17 index16 alt2">
					17</div>
				<div class="line number18 index17 alt1">
					18</div>
				<div class="line number19 index18 alt2">
					19</div>
				<div class="line number20 index19 alt1">
					20</div>
				<div class="line number21 index20 alt2">
					21</div>
				<div class="line number22 index21 alt1">
					22</div>
				<div class="line number23 index22 alt2">
					23</div>
				<div class="line number24 index23 alt1">
					24</div>
				<div class="line number25 index24 alt2">
					25</div>
				<div class="line number26 index25 alt1">
					26</div>
				<div class="line number27 index26 alt2">
					27</div>
				<div class="line number28 index27 alt1">
					28</div>
				<div class="line number29 index28 alt2">
					29</div>
			</td>
			<td class="code">
				<div class="container">
					<div class="line number1 index0 alt2">
						<code class="vb comments"><font face="新宋体">&#39;定义并创建Dictionary对象，使用CreateObject创建并返回自动化对象的引用 </font></code></div>
					<div class="line number2 index1 alt1">
						<code class="vb keyword"><font face="新宋体">Dim</font></code> <code class="vb plain"><font face="新宋体">d </font></code></div>
					<div class="line number3 index2 alt2">
						<code class="vb keyword"><font face="新宋体">Set</font></code> <font face="新宋体"><code class="vb plain">d = CreateObject(</code><code class="vb string">&quot;Scripting.Dictionary&quot;</code><code class="vb plain">) </code></font></div>
					<div class="line number4 index3 alt1">
						<code class="vb spaces"><font face="新宋体">&nbsp;</font></code></div>
					<div class="line number5 index4 alt2">
						<code class="vb comments"><font face="新宋体">&#39;向Dictionary对象中添加键值对 </font></code></div>
					<div class="line number6 index5 alt1">
						<font face="新宋体"><code class="vb plain">d.Add </code><code class="vb string">&quot;a&quot;</code><code class="vb plain">, </code><code class="vb string">&quot;Known&quot;</code></font>&nbsp;&nbsp;&nbsp; <code class="vb comments"><font face="新宋体">&#39;Add方法第一个参数是Key值，第二个是Item值 </font></code></div>
					<div class="line number7 index6 alt2">
						<font face="新宋体"><code class="vb plain">d.Add </code><code class="vb string">&quot;b&quot;</code><code class="vb plain">, </code><code class="vb string">&quot;Christina&quot;</code></font></div>
					<div class="line number8 index7 alt1">
						<font face="新宋体"><code class="vb plain">d.Add </code><code class="vb string">&quot;c&quot;</code><code class="vb plain">, </code><code class="vb string">&quot;test&quot;</code></font></div>
					<div class="line number9 index8 alt2">
						<font face="新宋体"><code class="vb plain">d.Add </code><code class="vb string">&quot;d&quot;</code><code class="vb plain">, </code><code class="vb string">&quot;fuck&quot;</code></font></div>
					<div class="line number10 index9 alt1">
						<code class="vb keyword"><font face="新宋体">Call</font></code> <code class="vb plain"><font face="新宋体">ShowDictionary(d) </font></code></div>
					<div class="line number11 index10 alt2">
						<code class="vb spaces"><font face="新宋体">&nbsp;</font></code></div>
					<div class="line number12 index11 alt1">
						<code class="vb comments"><font face="新宋体">&#39;遍历Dictionary对象，更改Item值 </font></code></div>
					<div class="line number13 index12 alt2">
						<code class="vb keyword"><font face="新宋体">For</font></code> <font face="新宋体"><code class="vb plain">i = 0 </code><code class="vb keyword">To</code></font> <font face="新宋体"><code class="vb plain">d.Count - 1&nbsp;&nbsp;&nbsp;&nbsp; </code><code class="vb comments">&#39;Count返回Dictionary对象中的项目数 </code></font></div>
					<div class="line number14 index13 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">If</code></font> <font face="新宋体"><code class="vb plain">d.Exists(</code><code class="vb string">&quot;c&quot;</code><code class="vb plain">) </code><code class="vb keyword">Then</code></font>&nbsp;&nbsp;&nbsp; <code class="vb comments"><font face="新宋体">&#39;Exists判断Dictionary对象中是否存在指定关键字 </font></code></div>
					<div class="line number15 index14 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">d.Item(</code><code class="vb string">&quot;c&quot;</code><code class="vb plain">) = </code><code class="vb string">&quot;Test&quot;</code></font> <code class="vb comments"><font face="新宋体">&#39;Item返回Dictionary对象中指定Key的Item值 </font></code></div>
					<div class="line number16 index15 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">End</code></font> <code class="vb keyword"><font face="新宋体">If</font></code></div>
					<div class="line number17 index16 alt2">
						<code class="vb keyword"><font face="新宋体">Next</font></code></div>
					<div class="line number18 index17 alt1">
						<font face="新宋体"><code class="vb plain">d.Remove(</code><code class="vb string">&quot;d&quot;</code><code class="vb plain">)&nbsp; </code><code class="vb comments">&#39;Remove从Dictionary对象中删除一个关键字，项目对。 </code></font></div>
					<div class="line number19 index18 alt2">
						<code class="vb keyword"><font face="新宋体">Call</font></code> <code class="vb plain"><font face="新宋体">ShowDictionary(d) </font></code></div>
					<div class="line number20 index19 alt1">
						<code class="vb spaces"><font face="新宋体">&nbsp;</font></code></div>
					<div class="line number21 index20 alt2">
						<code class="vb comments"><font face="新宋体">&#39;输出Dictionary对象所有键值 </font></code></div>
					<div class="line number22 index21 alt1">
						<code class="vb keyword"><font face="新宋体">Sub</font></code> <code class="vb plain"><font face="新宋体">ShowDictionary(dic) </font></code></div>
					<div class="line number23 index22 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Dim</code></font> <code class="vb plain"><font face="新宋体">str, a </font></code></div>
					<div class="line number24 index23 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">a = dic.Items&nbsp; </code><code class="vb comments">&#39;Items返回一个包含所有Item值的数组 </code></font></div>
					<div class="line number25 index24 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">For</code></font> <font face="新宋体"><code class="vb plain">i = 0 </code><code class="vb keyword">To</code></font> <code class="vb plain"><font face="新宋体">dic.Count - 1 </font></code></div>
					<div class="line number26 index25 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">str = str &amp; a(i) &amp; vbCrlf </code></font></div>
					<div class="line number27 index26 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Next</code></font></div>
					<div class="line number28 index27 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">MsgBox(str) </code></font></div>
					<div class="line number29 index28 alt2">
						<code class="vb keyword"><font face="新宋体">End</font></code> <code class="vb keyword"><font face="新宋体">Sub</font></code></div>
				</div>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　3. FileSystemObject对象</p>
<p>
	　　FileSystemObject对象可以操作驱动器、文件夹及文件，其对象模型包含下面的对象和集合。</p>
<table class="grid">
	<tbody>
		<tr>
			<th width="20%">
				对象/集合</th>
			<th width="80%">
				描述</th>
		</tr>
		<tr>
			<td>
				FileSystemObject</td>
			<td>
				主对象。包含用来创建、删除和获得有关信息，以及通常用来操作驱动器、文件夹和文件的方法和属性。和该对象相关联的许多方法，与其他 FSO 对象中的方法完全相似；它们是为了方便才被提供的。</td>
		</tr>
		<tr>
			<td>
				Drive</td>
			<td>
				对象。包含用来收集信息的方法和属性，这些信息是关于连接在系统上的驱动器的，如驱动器的共享名和它有多少可用空间。请注意，&quot;drive&quot; 并非必须是硬盘，也可以是 CD-ROM 驱动器，RAM 磁盘等等。并非必须把驱动器实物地连接到系统上；它也可以通过<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlzs/" target="_blank" >网络</A></STRONG>在逻辑上被连接起来。</td>
		</tr>
		<tr>
			<td>
				Drives</td>
			<td>
				集合。提供驱动器的列表，这些驱动器实物地或在逻辑上与系统相连接。<b>Drives</b> 集合包括所有驱动器，与类型无关。要可移动的媒体驱动器在该集合中显现，不必把媒体插入到驱动器中。</td>
		</tr>
		<tr>
			<td>
				File</td>
			<td>
				对象。包含用来创建、删除或移动文件的方法和属性。也用来向系统询问文件名、路径和多种其他属性。</td>
		</tr>
		<tr>
			<td>
				Files</td>
			<td>
				集合。提供包含在文件夹内的所有文件的列表。</td>
		</tr>
		<tr>
			<td>
				Folder</td>
			<td>
				对象。包含用来创建、删除或移动文件夹的方法和属性。也用来向系统询问文件夹名、路径和多种其他属性。</td>
		</tr>
		<tr>
			<td>
				Folders</td>
			<td>
				集合。提供在 <b>Folder</b> 内的所有文件夹的列表。</td>
		</tr>
		<tr>
			<td>
				TextStream</td>
			<td>
				对象。用来读写文本文件。</td>
		</tr>
	</tbody>
</table>
<p>
	　　FileSystemObject对象所有属性、方法及对象和集合的详细说明，您可以查阅参考文档，因为内容比较多，我们就看一个简单的示例，直观地来了解一下该对象的使用，该示例是将一个文件复制到指定文件夹下。</p>
<p>
	　　?</p>
<table border="0" cellpadding="0" cellspacing="0">
	<tbody>
		<tr>
			<td class="gutter">
				<div class="line number1 index0 alt2">
					1</div>
				<div class="line number2 index1 alt1">
					2</div>
				<div class="line number3 index2 alt2">
					3</div>
				<div class="line number4 index3 alt1">
					4</div>
				<div class="line number5 index4 alt2">
					5</div>
				<div class="line number6 index5 alt1">
					6</div>
				<div class="line number7 index6 alt2">
					7</div>
				<div class="line number8 index7 alt1">
					8</div>
				<div class="line number9 index8 alt2">
					9</div>
				<div class="line number10 index9 alt1">
					10</div>
				<div class="line number11 index10 alt2">
					11</div>
				<div class="line number12 index11 alt1">
					12</div>
				<div class="line number13 index12 alt2">
					13</div>
				<div class="line number14 index13 alt1">
					14</div>
				<div class="line number15 index14 alt2">
					15</div>
				<div class="line number16 index15 alt1">
					16</div>
				<div class="line number17 index16 alt2">
					17</div>
				<div class="line number18 index17 alt1">
					18</div>
				<div class="line number19 index18 alt2">
					19</div>
			</td>
			<td class="code">
				<div class="container">
					<div class="line number1 index0 alt2">
						<code class="vb comments"><font face="新宋体">&#39;定义并创建对象 </font></code></div>
					<div class="line number2 index1 alt1">
						<code class="vb keyword"><font face="新宋体">Dim</font></code> <code class="vb plain"><font face="新宋体">fso, filePath, folderPath </font></code></div>
					<div class="line number3 index2 alt2">
						<code class="vb keyword"><font face="新宋体">Set</font></code> <font face="新宋体"><code class="vb plain">fso = CreateObject(</code><code class="vb string">&quot;Scripting.FileSystemObject&quot;</code><code class="vb plain">) </code></font></div>
					<div class="line number4 index3 alt1">
						<font face="新宋体"><code class="vb plain">filePath = </code><code class="vb string">&quot;C:\\Test.txt&quot;</code></font></div>
					<div class="line number5 index4 alt2">
						<font face="新宋体"><code class="vb plain">folderPath = </code><code class="vb string">&quot;D:\\Test&quot;</code></font></div>
					<div class="line number6 index5 alt1">
						<code class="vb keyword"><font face="新宋体">Call</font></code> <code class="vb plain"><font face="新宋体">MoveFile(filePath, folderPath) </font></code></div>
					<div class="line number7 index6 alt2">
						<code class="vb spaces"><font face="新宋体">&nbsp;</font></code></div>
					<div class="line number8 index7 alt1">
						<code class="vb comments"><font face="新宋体">&#39;将文件移动到指定文件夹 </font></code></div>
					<div class="line number9 index8 alt2">
						<code class="vb keyword"><font face="新宋体">Sub</font></code> <code class="vb plain"><font face="新宋体">MoveFile(sourceFile, targetFolder) </font></code></div>
					<div class="line number10 index9 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Dim</code></font> <code class="vb plain"><font face="新宋体">file, fileName </font></code></div>
					<div class="line number11 index10 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb comments">&#39;获取文件对象 </code></font></div>
					<div class="line number12 index11 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Set</code></font> <code class="vb plain"><font face="新宋体">file = fso.GetFile(sourceFile) </font></code></div>
					<div class="line number13 index12 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb comments">&#39;判断目标文件夹是否存在 </code></font></div>
					<div class="line number14 index13 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">If</code></font> <code class="vb keyword"><font face="新宋体">Not</font></code> <font face="新宋体"><code class="vb plain">fso.FolderExists(targetFolder) </code><code class="vb keyword">Then</code></font></div>
					<div class="line number15 index14 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">fso.CreateFolder(targetFolder) </code></font></div>
					<div class="line number16 index15 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">End</code></font> <code class="vb keyword"><font face="新宋体">If</font></code></div>
					<div class="line number17 index16 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb comments">&#39;将文件移动到目标位置 </code></font></div>
					<div class="line number18 index17 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">file.Move(targetFolder &amp; </code><code class="vb string">&quot;\\&quot;</code></font> <code class="vb plain"><font face="新宋体">&amp; file.Name) </font></code></div>
					<div class="line number19 index18 alt2">
						<code class="vb keyword"><font face="新宋体">End</font></code> <code class="vb keyword"><font face="新宋体">Sub</font></code></div>
				</div>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　4. Err对象</p>
<p>
	　　Err对象是一个具有全局范围的内部对象，不必在代码中创建它的实例，含有关于运行时错误的信息。主要属性有Description、HelpContext、HelpFile、Number、Source，主要方法有Clear、Raise，其属性及方法的详细说明详见参考文档。下面的示例说明了Err对象的用法：</p>
<p>
	　　?</p>
<table border="0" cellpadding="0" cellspacing="0">
	<tbody>
		<tr>
			<td class="gutter">
				<div class="line number1 index0 alt2">
					1</div>
				<div class="line number2 index1 alt1">
					2</div>
				<div class="line number3 index2 alt2">
					3</div>
				<div class="line number4 index3 alt1">
					4</div>
				<div class="line number5 index4 alt2">
					5</div>
				<div class="line number6 index5 alt1">
					6</div>
				<div class="line number7 index6 alt2">
					7</div>
				<div class="line number8 index7 alt1">
					8</div>
				<div class="line number9 index8 alt2">
					9</div>
				<div class="line number10 index9 alt1">
					10</div>
				<div class="line number11 index10 alt2">
					11</div>
				<div class="line number12 index11 alt1">
					12</div>
				<div class="line number13 index12 alt2">
					13</div>
				<div class="line number14 index13 alt1">
					14</div>
				<div class="line number15 index14 alt2">
					15</div>
				<div class="line number16 index15 alt1">
					16</div>
				<div class="line number17 index16 alt2">
					17</div>
				<div class="line number18 index17 alt1">
					18</div>
				<div class="line number19 index18 alt2">
					19</div>
				<div class="line number20 index19 alt1">
					20</div>
				<div class="line number21 index20 alt2">
					21</div>
				<div class="line number22 index21 alt1">
					22</div>
			</td>
			<td class="code">
				<div class="container">
					<div class="line number1 index0 alt2">
						<code class="vb comments"><font face="新宋体">&#39;示例1： </font></code></div>
					<div class="line number2 index1 alt1">
						<code class="vb keyword"><font face="新宋体">On</font></code> <code class="vb keyword"><font face="新宋体">Error</font></code> <code class="vb keyword"><font face="新宋体">Resume</font></code> <code class="vb keyword"><font face="新宋体">Next</font></code></div>
					<div class="line number3 index2 alt2">
						<font face="新宋体"><code class="vb plain">Err.Raise 6&nbsp; </code><code class="vb comments">&#39;产生溢出错误 </code></font></div>
					<div class="line number4 index3 alt1">
						<font face="新宋体"><code class="vb plain">MsgBox(</code><code class="vb string">&quot;Error #&quot;</code></font> <font face="新宋体"><code class="vb plain">&amp; </code><code class="vb keyword">CStr</code><code class="vb plain">(Err.Number) &amp; </code><code class="vb string">&quot; &quot;</code></font> <code class="vb plain"><font face="新宋体">&amp; Err.Description) </font></code></div>
					<div class="line number5 index4 alt2">
						<code class="vb plain"><font face="新宋体">Err.Clear </font></code></div>
					<div class="line number6 index5 alt1">
						<code class="vb spaces"><font face="新宋体">&nbsp;</font></code></div>
					<div class="line number7 index6 alt2">
						<code class="vb comments"><font face="新宋体">&#39;示例2： </font></code></div>
					<div class="line number8 index7 alt1">
						<code class="vb comments"><font face="新宋体">&#39;定义<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>连接 </font></code></div>
					<div class="line number9 index8 alt2">
						<code class="vb keyword"><font face="新宋体">Dim</font></code> <code class="vb plain"><font face="新宋体">conn </font></code></div>
					<div class="line number10 index9 alt1">
						<code class="vb keyword"><font face="新宋体">Set</font></code> <font face="新宋体"><code class="vb plain">conn = CreateObject(</code><code class="vb string">&quot;ADODB.Connection&quot;</code><code class="vb plain">) </code></font></div>
					<div class="line number11 index10 alt2">
						<font face="新宋体"><code class="vb plain">conn.BeginTrans&nbsp; </code><code class="vb comments">&#39;开始事务 </code></font></div>
					<div class="line number12 index11 alt1">
						<code class="vb spaces"><font face="新宋体">&nbsp;</font></code></div>
					<div class="line number13 index12 alt2">
						<code class="vb plain"><font face="新宋体">... </font></code></div>
					<div class="line number14 index13 alt1">
						<code class="vb spaces"><font face="新宋体">&nbsp;</font></code></div>
					<div class="line number15 index14 alt2">
						<code class="vb comments"><font face="新宋体">&#39;提交数据库事务错误处理 </font></code></div>
					<div class="line number16 index15 alt1">
						<code class="vb keyword"><font face="新宋体">On</font></code> <code class="vb keyword"><font face="新宋体">Error</font></code> <code class="vb keyword"><font face="新宋体">Resume</font></code> <code class="vb keyword"><font face="新宋体">Next</font></code></div>
					<div class="line number17 index16 alt2">
						<code class="vb keyword"><font face="新宋体">If</font></code> <font face="新宋体"><code class="vb plain">conn.Errors.Count &gt; 0 </code><code class="vb keyword">Then</code></font></div>
					<div class="line number18 index17 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">conn.RollbackTrans&nbsp; </code><code class="vb comments">&#39;回滚事务 </code></font></div>
					<div class="line number19 index18 alt2">
						<code class="vb keyword"><font face="新宋体">Else</font></code></div>
					<div class="line number20 index19 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">conn.CommitTrans&nbsp;&nbsp;&nbsp; </code><code class="vb comments">&#39;提交事务 </code></font></div>
					<div class="line number21 index20 alt2">
						<code class="vb keyword"><font face="新宋体">End</font></code> <code class="vb keyword"><font face="新宋体">If</font></code></div>
					<div class="line number22 index21 alt1">
						<code class="vb plain"><font face="新宋体">Err.Clear</font></code></div>
				</div>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　5. RegExp对象</p>
<p>
	　　RegExp是正则表达式对象，提供简单的正则表达式支持功能。主要属性有Global、IgnoreCase、Pattern，主要方法有Execute、Replace、Test，其属性及方法的详细说明详见参考文档。下面的示例说明了RegExp对象的用法：</p>
<p>
	　　?</p>
<table border="0" cellpadding="0" cellspacing="0">
	<tbody>
		<tr>
			<td class="gutter">
				<div class="line number1 index0 alt2">
					1</div>
				<div class="line number2 index1 alt1">
					2</div>
				<div class="line number3 index2 alt2">
					3</div>
				<div class="line number4 index3 alt1">
					4</div>
				<div class="line number5 index4 alt2">
					5</div>
				<div class="line number6 index5 alt1">
					6</div>
				<div class="line number7 index6 alt2">
					7</div>
				<div class="line number8 index7 alt1">
					8</div>
				<div class="line number9 index8 alt2">
					9</div>
				<div class="line number10 index9 alt1">
					10</div>
				<div class="line number11 index10 alt2">
					11</div>
				<div class="line number12 index11 alt1">
					12</div>
				<div class="line number13 index12 alt2">
					13</div>
				<div class="line number14 index13 alt1">
					14</div>
				<div class="line number15 index14 alt2">
					15</div>
				<div class="line number16 index15 alt1">
					16</div>
			</td>
			<td class="code">
				<div class="container">
					<div class="line number1 index0 alt2">
						<code class="vb keyword"><font face="新宋体">Function</font></code> <code class="vb plain"><font face="新宋体">RegExpTest(patrn, strng) </font></code></div>
					<div class="line number2 index1 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Dim</code></font> <font face="新宋体"><code class="vb plain">regEx, match, matches&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code><code class="vb comments">&#39;建立变量。 </code></font></div>
					<div class="line number3 index2 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Set</code></font> <font face="新宋体"><code class="vb plain">regEx = </code><code class="vb keyword">New</code></font> <font face="新宋体"><code class="vb plain">RegExp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code><code class="vb comments">&#39;建立正则表达式。 </code></font></div>
					<div class="line number4 index3 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">regEx.Pattern = patrn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code><code class="vb comments">&#39;设置模式。 </code></font></div>
					<div class="line number5 index4 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">regEx.IgnoreCase = </code><code class="vb keyword">True</code></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <code class="vb comments"><font face="新宋体">&#39;设置是否区分字符大小写。 </font></code></div>
					<div class="line number6 index5 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">regEx.Global = </code><code class="vb keyword">True</code></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <code class="vb comments"><font face="新宋体">&#39;设置全局可用性。 </font></code></div>
					<div class="line number7 index6 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Set</code></font> <font face="新宋体"><code class="vb plain">matches = regEx.Execute(strng)&nbsp;&nbsp; </code><code class="vb comments">&#39;执行搜索。 </code></font></div>
					<div class="line number8 index7 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">For</code></font> <code class="vb keyword"><font face="新宋体">Each</font></code> <font face="新宋体"><code class="vb plain">match in matches&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code><code class="vb comments">&#39;遍历匹配集合。 </code></font></div>
					<div class="line number9 index8 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">retStr = retStr &amp; </code><code class="vb string">&quot;Match found at position &quot;</code></font></div>
					<div class="line number10 index9 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">retStr = retStr &amp; match.FirstIndex &amp; </code><code class="vb string">&quot;. Match Value is &#39;&quot;</code></font></div>
					<div class="line number11 index10 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">retStr = retStr &amp; match.Value &amp; </code><code class="vb string">&quot;&#39;.&quot;</code></font> <code class="vb plain"><font face="新宋体">&amp; vbCRLF </font></code></div>
					<div class="line number12 index11 alt1">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb keyword">Next</code></font></div>
					<div class="line number13 index12 alt2">
						<font face="新宋体"><code class="vb spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="vb plain">RegExpTest = retStr </code></font></div>
					<div class="line number14 index13 alt1">
						<code class="vb keyword"><font face="新宋体">End</font></code> <code class="vb keyword"><font face="新宋体">Function</font></code></div>
					<div class="line number15 index14 alt2">
						<code class="vb spaces"><font face="新宋体">&nbsp;</font></code></div>
					<div class="line number16 index15 alt1">
						<font face="新宋体"><code class="vb plain">MsgBox(RegExpTest(</code><code class="vb string">&quot;is.&quot;</code><code class="vb plain">, </code><code class="vb string">&quot;IS1 is2 IS3 is4&quot;</code><code class="vb plain">))</code></font></div>
				</div>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#]]></description>
    <pubDate>Wed, 18 Jan 2012 09:35:18 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>QuickTestPro</category>
    <author>　　known</author>
    <comments>博客园</comments>
</item>
<item>
    <title><![CDATA[使用Visual Studio Profiler测试host在本地IIS上的WCF服务性能]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/qita/vsts/2012/0109/203882.html</link>
    <description><![CDATA[<p>
	　　http://www.cnblogs.com/telnet_mike/archive/2011/11/07/2240351.html</p>
<p>
	　　读过上篇bolg的现在应该知道怎么样来Profile一个WCF项目了，今天我们来看一下怎样Profile一个host到本地IIS上的WCF服务，我们还是使用Visual Studio 2010还有上篇blog中的测试项目。</p>
<p>
	　　使用Administrator账户启动Visual Studio 2010!</p>
<p>
	　　How to: Host a WCF Service in IIS</p>
<p>
	　　Deploying an Internet Information Services-Hosted WCF Service</p>
<p>
	　　Using Visual Studio 2010 to Host a WCF Service on the Local IIS Instance</p>
<p>
	　　Open or create a WCF Service Application project. Right click the project in the solution explorer and select Properties. In the project properties window select the Web tab on the left hand side of the window. On the right hand side of the window, under Servers, select the Use Local IIS Web Server and type in a URL. Next, click the Create Virtual Directory button and build the solution. This will create the virtual directory in IIS and map it to your project directory. The service will then be hosted on the local IIS server for building and debugging purposes. To verify the service has been hosted, open Internet Explorer and type the service&rsquo;s URL in the address box. You must type in the complete URL path to the .svc file. For example, with a default WCF Service Application project hosted under http://localhost/MyFirstService the complete URL would be http://localhost/MyFirstService/Service1.svc. This will display the default WCF Service page.</p>
<center>
	<img alt="hostWCF2LocalIIS" border="1" height="838" src="/uploads/allimg/120109/100500J54-0.png" width="894" /></center>
<p>
	　　使用同样的步骤将我们的WebApplication1 asp.net应用程序项目也host到本地IIS上。</p>
<p>
	　　WcfService1地址: http://localhost/WcfService1/Service1.svc</p>
<p>
	　　WebApplication1地址: http://localhost/WebApplication1</p>
<center>
	<img alt="proformancewizard1_4" border="1" height="559" src="/uploads/allimg/120109/1005005391-1.png" width="651" /></center>
<center>
	<img alt="proformancewizard2_4" border="1" height="560" src="/uploads/allimg/120109/1005001D0-2.png" width="651" /></center>
<center>
	<img alt="proformancewizard3_4" border="1" height="560" src="/uploads/allimg/120109/10050014N-3.png" width="651" /></center>
<center>
	<img alt="proformancewizard4_4" border="1" height="560" src="/uploads/allimg/120109/1005003139-4.png" width="651" /></center>
<p>
	　　IE会直接打开WCF服务的页面:</p>
<center>
	<img alt="WcfService1" border="1" height="650" src="/uploads/allimg/120109/1005005155-5.png" width="921" /></center>
<p>
	　　现在我们可以用WebApplication1地址来替换WcfService1地址，并让IE浏览它，这样我们可以使用我们的asp.net应用来调用WcfService1中的函数，从而达到测试性能的目标。</p>
<center>
	<img alt="testpage" border="1" height="650" src="/uploads/allimg/120109/10050053L-6.png" width="921" /></center>
<p>
	　　报表会在你关闭IE的时候，Visual Studio Profiler工具停止后，自动打开。</p>
<center>
	<img alt="report1" border="1" height="764" src="/uploads/allimg/120109/1005002M2-7.png" width="834" /></center>
<p>
	　　你可以看到所有的函数调用，但你点击WcfService1.Service1.Abc(int32)函数后，它会为你打开一个详细页面和你的函数源代码。</p>
<center>
	<img alt="sourcecode" border="1" height="832" src="/uploads/allimg/120109/100500CU-8.png" width="713" /></center>
<p>
	　　My English Blog: http://mikedoszhang.blogspot.com/2011/11/profile-wcf-which-hosted-in-local-iis.html</p>
]]></description>
    <pubDate>Mon, 09 Jan 2012 09:56:09 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/120109/100500J54-0-lp.png</subImagePath>
     <category>VSTS</category>
    <author>Mike Dos Zhang</author>
    <comments>博客园</comments>
</item>
<item>
    <title><![CDATA[LoadRunner11设置场景百分比模式完成多台客户端负载测试]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2011/1231/203856.html</link>
    <description><![CDATA[<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LoadRunner</A></STRONG>11用的不多，之前大部分的时候是用LoadRunner9.5，主要原因是由于担心新版本的稳定性，不过在<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/windows/" target="_blank" >Windows</A></STRONG>7系统下就不得不用LoadRunner11了，不过稳定不稳定，还是得用了之后才了解～</p>
<p>
	　　关于<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LR</A></STRONG>11场景中设置多台负载进行测试，发现一个问题，可能平时不太注意，或者不太关注。在LR11中我们添加一台负载测试机时发现不能手动更改虚拟用户数，如图所示:</p>
<center>
	<img alt="" border="1" height="139" src="/uploads/allimg/111231/094632H03-0.jpg" width="805" /></center>
<p>
	　　上面的模式，只能在添加的时候修改用户数，添加之后就只能更改总的Vusers，所以这里我们需要转换一下场景模式，当前模式为Vuser组模式，我们看下图如何转换成其他模式：</p>
<center>
	<img alt="" border="1" height="360" src="/uploads/allimg/111231/094632O56-1.jpg" width="810" /></center>
<p>
	　　通过上面的场景模式更改为百分比模式，我们就可以随意调整各个负载机器的Vusers了，毕竟不是所有的负载机配置都是一样的，更改之后的设置如下所示：</p>
<center>
	<img alt="" border="1" height="97" src="/uploads/allimg/111231/0946325221-2.jpg" width="764" /></center>
<p>
	　　这样通过百分比显示之后，我们就可以随意调整了，而且据参考一些老版本的资料，为了更好的响应多台负载机器进行压测，将场景模式转换成百分比模式是最优的，不过之前在使用9.0～9.5的版本时，通常都是默认的以Vuser组模式，也没有发现有什么异常的地方，此处有待进一步验证。其实，LoadRunner有很多功能我们平时可能都很难有机会用到，待用到时，却可能就再查找资料等等可能需要一些调整和设置，但对于这些设置的缘由，那就需要去实践对比了，是否真正能够为项目压测过程带来优化的效果，测试结果才能证明一切!</p>
]]></description>
    <pubDate>Sat, 31 Dec 2011 09:44:41 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111231/094632H03-0-lp.jpg</subImagePath>
     <category>LoadRunner</category>
    <author>一米阳光学测试</author>
    <comments>博客园</comments>
</item>
<item>
    <title><![CDATA[QTP之WinMenu对象的测试]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/2011/1231/203855.html</link>
    <description><![CDATA[<p>
	　　WinMenu对象是指菜单控件，常用的测试操作是Select方法，用来模拟用户选择某个菜单项。可以使用BuildMenuPath方法构建菜单路径</p>
<p>
	　　如：MenuPath = object.WinMenu(&quot;Menu&quot;).BulidMenuPath(&quot;<item1>;<item12>&quot;)</item12></item1></p>
<item1><item12>
<p>
	　　object.WinMenu(&quot;Menu&quot;).Select MenuPath</p>
<p>
	　　也可以使用Index来指定菜单项：</p>
<p>
	　　MenuPath =object.WinMenu(&quot;Menu&quot;).BulidMenuPath(1,2)</p>
<p>
	　　object.WinMenu(&quot;Menu&quot;).Select MenuPath</p>
<p>
	　　以下脚本通过BuildMenuPath(1,1)构建计数器程序中的【编辑】菜单项下的【复制】，通过BuildMenuPath(1,2)构建计数器程序中的【编辑】菜单项下的【粘贴】。</p>
<p>
	　　SystemUtil.CloseProcessByName &quot;calc.exe&quot;Systemutil.Run &quot;calc.exe&quot;, &quot;&quot;,&quot;&quot;,&quot;&quot;,&quot;1&quot;rem 创建描述Set WinDescription = Description.Create WinDescription(&quot;regexpwndtitle&quot;).value =&quot;计算器&quot;Set MenuDescription = Description.Create MenuDescription(&quot;menuobjtype&quot;).value =&quot;2&quot;Call calc(&quot;1&quot;)Call calc(&quot;2&quot;)rem 使用BuildMenuPath方法构建菜单路径MenuPath=Window(WinDescription).WinMenu(MenuDescription).BuildMenuPath(1,1)Window(WinDescription).WinMenu(MenuDescription).Select MenuPathCall calc(&quot;\+&quot;)MenuPath2=Window(WinDescription).WinMenu(MenuDescription).BuildMenuPath(1,2)Window(WinDescription).WinMenu(MenuDescription).Select MenuPath2Call calc(&quot;\=&quot;)rem 定义输入函数function calc(input) Set WinDescription = Description.Create WinDescription(&quot;regexpwndtitle&quot;).value =&quot;计算器&quot; Set inputDescription = Description.Create inputDescription(&quot;text&quot;).value =input Window(WinDescription).WinButton(inputDescription).ClickEnd function</p>
<p>
	　　复制代码</p>
<p>
	　　以上脚本可以适应计算器程序中的各种计算，注意：calc() 函数的入参,如执行【+】操作，需要进行正则表达式转换。</p>
</item12></item1>]]></description>
    <pubDate>Sat, 31 Dec 2011 09:28:47 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>QuickTestPro</category>
    <author>娃娃</author>
    <comments>博客园</comments>
</item>
<item>
    <title><![CDATA[Mercury“最佳功能测试实践”-第三部分]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/2011/1226/203817.html</link>
    <description><![CDATA[<p>
	　　1.1 测试准备</p>
<p>
	　　测试的准备是一个独立的、分离的阶段，测试员在这个阶段中基于<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求</A></STRONG>文档准备测试(业务设计图)。测试的准备要依据标准的方法，并应基于本阶段的工作生成标准化的文档。</p>
<p>
	　　1.1.1 业务<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/" target="_blank" >功能测试</A></STRONG></p>
<p>
	　　基于风险评估，针对每个业务功能的不同风险级别都应有一个对应的测试过程和方法组合：</p>
<p>
	　　1)A级风险</p>
<p>
	　　利用等价类和组合进行系统性的测试完全自动化</p>
<p>
	　　2) B级风险</p>
<p>
	　　利用等价类进行系统性的测试完全自动化</p>
<p>
	　　3) C级风险</p>
<p>
	　　随意性测试手工执行，在<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/testdirector/" target="_blank" >TestDirector</A></STRONG>中提供文档化的执行过程</p>
<p>
	　　对于每个测试过程和方法组合，要提供一个标准的文档进行方法论级的阐述和规定，每个测试人员依据这些标准的测试过程和方法组合进行测试。</p>
<p>
	　　在TestDirector中要将<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csyl/" target="_blank" >测试用例</A></STRONG>的准备结果作为业务功能的附件。</p>
<p>
	　　1.1.2 业务流程测试</p>
<p>
	　　业务流程测试是将所有的业务功能组合在一起，使用同一组数据进行工作。</p>
<p>
	　　测试员的任务就是要确定每个业务功能的组合是否能连贯的执行。</p>
<p>
	　　判断的结果使用矩阵来表示，例如下图：</p>
<p>
	　　注：yes(+);no(-)</p>
<p>
	　　业务流程矩阵</p>
<p>
	　　12345</p>
<p>
	　　登陆</p>
<p>
	　　航班</p>
<p>
	　　查询</p>
<p>
	　　航班</p>
<p>
	　　预定</p>
<p>
	　　退出</p>
<p>
	　　注册</p>
<p>
	　　后功能</p>
<p>
	　　前功能</p>
<p>
	　　1登陆-+-++</p>
<p>
	　　2航班查询-+++-</p>
<p>
	　　3航班预定-+-+-</p>
<p>
	　　4退出+----</p>
<p>
	　　5注册+---+</p>
<p>
	　　从上面的表中我们能获得三个业务流程测试案例：</p>
<p>
	　　1) 1，2，2，3，2，4，1，1</p>
<p>
	　　2) 1，5，4</p>
<p>
	　　3) 1，2，3，4</p>
<p>
	　　1.1.3 业务<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csgl/jccs/" target="_blank" >集成测试</A></STRONG></p>
<p>
	　　使用现有的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csgl/hgcs/" target="_blank" >回归测试</A></STRONG>案例进行业务集成测试。</p>
<p>
	　　在第一个阶段，测试案例仅被自动化，而不考虑测试的覆盖率。</p>
<p>
	　　在第二阶段，测试案例将被改进，以提高测试的覆盖率。</p>
<p>
	　　对于所有的新项目，回归测试应该在业务功能测试阶段和业务流程测试阶段的测试结果的基础上进行建设。</p>
<p>
	　　依据业务流程矩阵创建测试案例集，这个测试案例集应该能覆盖被测系统的所有外部接口。</p>
<p>
	　　假定我们的被测系统是<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/" target="_blank" >Mercury</A></STRONG>的机票预定系统，它的架构图如下：</p>
<center>
	<img alt="" border="1" height="240" src="/uploads/allimg/111226/10430C604-0.jpg" width="400" /></center>
<p>
	　　业务流程矩阵的设计如下图：</p>
<p>
	　　在业务集成测试阶段中的测试案例<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG></p>
<p>
	　　1234</p>
<p>
	　　预定一个航班</p>
<p>
	　　打印机票</p>
]]></description>
    <pubDate>Mon, 26 Dec 2011 10:31:25 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111226/10430C604-0-lp.jpg</subImagePath>
     <category>Mercury软件测试工具</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[主流测试工具介绍]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/winrunner/2011/1219/203780.html</link>
    <description><![CDATA[<table align="center" border="0" cellpadding="0" cellspacing="0" width="95%">
	<tbody>
		<tr>
			<td class="content">
				<font color="#000000"><STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/winrunner/" target="_blank" >WinRunner</A></STRONG>:强大的企业级自动化<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG> </font>
				<p>
					<font color="#000000">　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/" target="_blank" >Mercury</A></STRONG>&nbsp;Interactive公司的WinRunner是一种企业级的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/" target="_blank" >功能测试</A></STRONG>工具，用于检测应用程序是否能够达到预期的功能及正常运行。通过自动录制、检测和回放用户的应用操作，WinRunner能够有效地帮助测试人员对复杂的企业级应用的不同发布版进行测试，提高测试人员的工作效率和质量，确保跨平台的、复杂的企业级应用无故障发布及长期稳定运行。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　企业级应用可能包括Web应用系统，ERP系统，CRM系统等等。这些系统在发布之前，升级之后都要经过测试，确保所有功能都能正常运行，没有任何错误。如何有效地测试不断升级更新且不同环境的应用系统，是每个公司都会面临的问题。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　如果时间或资源有限，这个问题会更加棘手。人工测试的工作量太大，还要额外的时间来培训新的测试人员等等。为了确保那些复杂的企业级应用在不同环境下都能正常可靠地运行，你需要一个能简单操作的测试工具来自动完成应用程序的功能性测试。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">轻松创建测试&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　用WinRuuner创建一个测试，只需点击鼠标和键盘，完成一个标准的业务操作流程，WinRunner自动记录你的操作并生成所需的脚本代码。这样，即使计算机技术<STRONG><A href="http://www.ltesting.net/ask/" target="_blank" >知识</A></STRONG>有限的业务用户轻松创建完整的测试。你还可以直接修改测试脚本以满足各种复杂测试的需求。WinRunner提供这两种测试创建方式，满足测试团队中业务用户和专业技术人员的不同需求。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">插入检查点&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　在记录一个测试的过程中，可以插入检查点，检查在某个时刻/状态下，应用程序是否运行正常。在插入检查点后，WinRunner会收集一套数据指标，在测试运行时对其一一验证。WinRunner提供几种不同类型的检查点，包括文本的、GUI、位图和<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>。例如，用一个位图检查点，你可以检查公司的图标是否出现于指定位置。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">检验数据&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　除了创建并运行测试，WinRunner还能验证数据库的数值，从而确保业务交易的准确性。例如，在创建测试时，可以设定哪些数据库表和记录需要检测；在测试运行时，测试程序就会自动核对数据库内的实际数值和预期的数值。WinRunner自动显示检测结果，在有更新/删除/插入的记录上突出显示以引起注意。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">增强测试&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　为了彻底全面地测试一个应用程序，需要使用不同类型的数据来测试。WinRunner的数据驱动向导(&nbsp;Data&nbsp;Driver&nbsp;Wizard)可以让你简单地点击几下鼠标，就可以把一个业务流程测试转化为数据驱动测试，从而反映多个用户各自独特且真实的行为。</font></p>
				<p>
					<br />
					<font color="#000000">　　以一个订单输入的流程为例，你可能希望把订单号或客户名称作为可变栏，用多套数据进行测试。使用Data&nbsp;Driver&nbsp;Wizard，你可以选择订单号或客户名称用数据表格文件中的哪个栏目的数据替换。你可以把订单号或客户名称输入数据表格文件，或从其它表格和数据库中导入。数据驱动测试不仅节省了时间和资源，又提高了应用的测试覆盖率。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　WinRunner还可以通过Function&nbsp;Generator增加测试的功能。使用Function&nbsp;Generator可以从目录列表中选择一个功能增加到你的测试中以提高测试能力。例如，你可以选择&rdquo;calendar&rdquo;，然后从日历功能的下属目录中选择，如Calendar_select_date(),然后你可以直观地输入参数，把这个功能插入到你的测试中。</font></p>
				<p>
					<br />
					<font color="#000000">　　针对相当数量的企业应用里非标准对象，WinRunner提供了Virtual&nbsp;Object&nbsp;Wizard来识别以前未知的对象。使用Virtual&nbsp;Object&nbsp;Wizard，你可以选择未知对象的类型，设定标识和命名。在录制使用该对象的测试时，WinRunner会自动对应它的名字，从而提高测试脚本的可读性和测试质量。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">运行测试&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　创建好测试脚本，并插入检查点和必要的添加功能后，你就可以开始运行测试。运行测试时，WinRunner会自动操作应用程序，就象一个真实的用户根据业务流程执行着每一步的操作。测试运行过程中，如有<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlzs/" target="_blank" >网络</A></STRONG>消息窗口出现或其它意外事件出现，WinRunner也会根据预先的设定排除这些干扰。</font></p>
				<p>
					<br />
					<font color="#000000">分析结果</font></p>
				<p>
					<br />
					<font color="#000000">　　测试运行结束后，你需要分析测试结果。WinRunner通过交互式的报告工具来提供详尽的、易读的报告。报告中会列出测试中发现的错误内容、位置、检查点和其它重要事件，帮助你对测试结果进行分析。这些测试结果还可以通过Mercury&nbsp;Interactive的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csgl/" target="_blank" >测试管理</A></STRONG>工具<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/testdirector/" target="_blank" >TestDirector</A></STRONG>来查阅。</font></p>
				<p>
					<br />
					<font color="#000000">维护测试&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　随着时间的推移，<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>人员会对应用程序做进一步的修改，并需要增加另外的测试。使用WinRunner，你不必对程序的每一次改动都重新创建你的测试。WinRunner可以创建在整个应用程序生命周期内都可以重复使用的测试，从而大大地节省时间和资源，充分利用你的测试投资。</font></p>
				<p>
					<br />
					<font color="#000000">　　每次记录测试时，WinRunner会自动创建一个GUI&nbsp;Map文件以保存应用对象。这些对象分层次组织，既可以总览所有的对象，也可以查询某个对象的详细信息。一般而言，对应用程序的任何改动都会影响到成百上千个测试。通过修改一个GUI&nbsp;Map文件而非无数个测试，WinRunner可以方便地实现测试重用。</font></p>
				<p>
					<br />
					<font color="#000000">帮助你的应用程序为无线应用作准备&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　随着无线设备种类和数量的增加，你的应用程序<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csmb/csjh/" target="_blank" >测试计划</A></STRONG>需要同时满足传统的基于浏览器的用户和无线浏览设备，如移动电话、传呼机和个人数字助理(PDA)。</font></p>
				<p>
					<br />
					<font color="#000000">　　无线应用协议是一种公开的、全球性的网络协议，用来支持标准数据格式化和无线设备信号的传输。<br />
					使用WinRunner，测试人员可以利用微型浏览模拟器来记录业务流程操作，然后回放和检查这些业务流程功能的正确性。&nbsp;</font></p>
				<p>
					<font color="#000000">工业标准级负载测试工具</font></p>
				<p>
					<font color="#000000">　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LoadRunner</A></STRONG>&nbsp;是一种预测系统行为和性能的负载测试工具。通过以模拟上千万用户实施并发负载及实时性能监测的方式来确认和查找问题，LoadRunner&nbsp;能够对整个企业架构进行测试。通过使用LoadRunner&nbsp;，企业能最大限度地缩短测试时间，优化性能和加速应用系统的发布周期。</font></p>
				<p>
					<br />
					<font color="#000000">　　目前企业的网络应用环境都必须支持大量用户，网络体系架构中含各类应用环境且由不同供应商提供软件和硬件产品。难以预知的用户负载和愈来愈复杂的应用环境使公司时时担心会发生用户响应速度过慢，系统崩溃等问题。这些都不可避免地导致公司收益的损失。Mercury&nbsp;Interactive&nbsp;的&nbsp;LoadRunner&nbsp;能让企业保护自己的收入来源，无需购置额外硬件而最大限度地利用现有的IT&nbsp;资源，并确保终端用户在应用系统的各个环节中对其测试应用的质量，可靠性和可扩展性都有良好的评价。</font></p>
				<p>
					<br />
					<font color="#000000">　　LoadRunner&nbsp;是一种适用于各种体系架构的自动负载测试工具，它能预测系统行为并优化系统性能。LoadRunner&nbsp;的测试对象是整个企业的系统，它通过模拟实际用户的操作行为和实行实时性能监测，来帮助您更快的查找和发现问题。此外，LoadRunner&nbsp;能支持广范的协议和技术，为您的特殊环境提供特殊的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/jjfa/" target="_blank" >解决方案</A></STRONG>。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">轻松创建虚拟用户</font></p>
				<p>
					<br />
					<font color="#000000">　　使用LoadRunner&nbsp;的Virtual&nbsp;User&nbsp;Generator，您能很简便地创立起系统负载。该引擎能够生成虚拟用户，以虚拟用户的方式模拟真实用户的业务操作行为。它先记录下业务流程(如下订单或机票预定)，然后将其转化为测试脚本。利用虚拟用户，您可以在<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/windows/" target="_blank" >Windows</A></STRONG>&nbsp;，UNIX&nbsp;或<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/unix/linux/" target="_blank" >Linux</A></STRONG>&nbsp;机器上同时产生成千上万个用户访问。所以LoadRunner能极大的减少负载测试所需的硬件和人力资源。另外，LoadRunner&nbsp;的TurboLoad&nbsp;专利技术能。</font></p>
				<p>
					<br />
					<font color="#000000">　　提供很高的适应性。TurboLoad&nbsp;使您可以产生每天几十万名在线用户和数以百万计的点击数的负载。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　用Virtual&nbsp;User&nbsp;Generator&nbsp;建立测试脚本后，您可以对其进行参数化操作，这一操作能让您利用几套不同的实际发生数据来测试您的应用程序，从而反映出本系统的负载能力。以一个订单输入过程为例，参数化操作可将记录中的固定数据，如订单号和客户名称，由可变值来代替。在这些变量内随意输入可能的订单号和客户名，来匹配多个实际用户的操作行为。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　LoadRunner&nbsp;通过它的Data&nbsp;Wizard&nbsp;来自动实现其测试数据的参数化。Data&nbsp;Wizard&nbsp;直接连于数据库<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>，从中您可以获取所需的数据（如定单号和用户名）并直接将其输入到测试脚本。这样避免了人工处理数据的需要，Data&nbsp;Wizard&nbsp;为您节省了大量的时间。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　为了进一步确定您的Virtual&nbsp;user&nbsp;能够模拟真实用户，您可利用LoadRunner&nbsp;控制某些行为特性。例如，只需要点击一下鼠标，您就能轻易控制交易的数量，交易频率，用户的思考时间和连接速度等。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">创建真实的负载</font></p>
				<p>
					<br />
					<font color="#000000">　　Virtual&nbsp;users&nbsp;建立起后，您需要设定您的负载方案，业务流程组合和虚拟用户数量。用LoadRunner&nbsp;的Controller，您能很快组织起多用户的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csmb/csfa/" target="_blank" >测试方案</A></STRONG>。Controller&nbsp;的Rendezvous&nbsp;功能提供一个互动的环境，在其中您既能建立起持续且循环的负载，又能管理和驱动负载测试方案。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　而且，您可以利用它的日程计划服务来定义用户在什么时候访问系统以产生负载。这样，您就能将测试过程自动化。同样您还可以用Controller&nbsp;来限定您的负载方案，在这个方案中所有的用户同时执行一个动作---如登陆到一个库存应用程序----来模拟峰值负载的情况。另外，您还能监测系统架构中各个组件的性能----&nbsp;包括服务器，数据库，网络设备等----来帮助客户决定系统的配置。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　LoadRunner&nbsp;通过它的AutoLoad&nbsp;技术，为您提供更多的测试灵活性。使用AutoLoad&nbsp;，您可以根据目前的用户人数事先设定测试目标，优化测试流程。例如，您的目标可以是确定您的应用系统承受的每秒点击数或每秒的交易量。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">定位性能问题</font></p>
				<p>
					<br />
					<font color="#000000">　　LoadRunner&nbsp;内含集成的实时监测器，在负载测试过程的任何时候，您都可以观察到应用系统的运行性能。这些性能监测器为您实时显示交易性能数据（如响应时间）和其它系统组件包括application&nbsp;server,&nbsp;web&nbsp;server，网路设备和数据库等的实时性能。这样，您就可以在测试过程中从客户和服务器的双方面评估这些系统组件的运行性能，从而更快地发现问题。</font></p>
				<p>
					<br />
					<font color="#000000">　　再者，利用LoadRunner&nbsp;的ContentCheck&nbsp;TM&nbsp;，您可以判断负载下的应用程序功能正常与否。ContentCheck&nbsp;在Virtual&nbsp;users&nbsp;运行时，检测应用程序的网络数据包内容，从中确定是否有错误内容传送出去。它的实时浏览器帮助您从终端用户角度观察程序性能状况。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">分析结果以精确定位问题所在</font></p>
				<p>
					<br />
					<font color="#000000">　　一旦测试完毕后，LoadRunner&nbsp;收集汇总所有的测试数据，并为您提供高级的分析和报告工具，以便迅速查找到性能问题并追溯原由。使用LoadRunner&nbsp;的Web&nbsp;交易细节监测器，您可以了解到将所有的图象、框架和文本<STRONG><A href="http://www.ltesting.net/ceshi/down" target="_blank" >下载</A></STRONG>到每一网页上所需的时间。例如，这个交易细节分析机制能</font></p>
				<p>
					<br />
					<font color="#000000">　　够分析是否因为一个大尺寸的图形文件或是第三方的数据组件造成应用系统运行速度减慢。另外，Web&nbsp;交易细节监测器分解用于客户端、网络和服务器上端到端的反应时间，便于确认问题，定位查找真正出错的组件。例如，您可以将网络延时进行分解，以判断DNS&nbsp;解析时间，连接服务器或SSL&nbsp;认证所花费的时间。通过使用LoadRunner&nbsp;的分析工具，您能很快地查找到出错的位置和原因并作出相应的调整。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">重复测试保证系统发布的高性能</font></p>
				<p>
					<br />
					<font color="#000000">　　负载测试是一个重复过程。每次处理完一个出错情况，您都需要对您的应用程序在相同的方案下，再进行一次负载测试。以此检验您所做的修正是否改善了运行性能。</font></p>
				<p>
					<br />
					<font color="#000000">Enterprise&nbsp;<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcskfyy/java/" target="_blank" >Java</A></STRONG>&nbsp;Beans的测试</font></p>
				<p>
					<br />
					<font color="#000000">　　LoadRunner&nbsp;完全支持EJB&nbsp;的负载测试。这些基于Java&nbsp;的组件运行在应用服务器上，提供广泛的应用服务。通过测试这些组件，您可以在应用程序开发的早期就确认并解决可能产生的问题。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　利用LoadRunner,&nbsp;您可以很方便地了解系统的性能。&nbsp;它的Controller&nbsp;允许您重复执行与出错修改前相同的测试方案。它的基于HTML&nbsp;的报告为您提供一个比较性能结果所需的基准，以此衡量在一段时间内，有多大程度的改进并确保应用成功。由于这些报告是基于HTML&nbsp;的文本，您可以将其公布于您公司的内部网上，便于随时查阅。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">最大化投资回报&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　所有Mercury&nbsp;Interactive&nbsp;的产品和服务都是集成设计的,&nbsp;能完全相容地一起运作。由于它们具有相同的核心技术，来自于LoadRunner和ActiveTest&nbsp;TM&nbsp;的测试脚本，在Mercury&nbsp;Interactive&nbsp;的负载测试服务项目中，可以被重复用于性能监测。借助Mercury&nbsp;Interactive的监测功能－－Topaz&nbsp;TM&nbsp;和ActiveWatch&nbsp;TM&nbsp;，测试脚本可重复使用从而平衡投资收益。更重要的是，您能为测试的前期布署和生产系统的监测提供一个完整的应用性能管理解决方案。</font></p>
				<p>
					<br />
					<font color="#000000">支持无线应用协议</font></p>
				<p>
					<br />
					<font color="#000000">　　随着无线设备数量和种类的增多，您的测试计划需要同时满足传统的基于浏览器的用户和无线互联网设备，如手机和PDA。LoadRunner&nbsp;支持2&nbsp;项最广泛使用的协议：WAP和I-mode。此外，通过负载测试系统整体架构，LoadRunner&nbsp;能让您只需要通过记录一次脚本，就可完全检测上述这些无线互联网系统。</font></p>
				<p>
					<br />
					<font color="#000000">支持Media&nbsp;Stream应用</font></p>
				<p>
					<br />
					<font color="#000000">　　LoadRunner&nbsp;还能支持Media&nbsp;Stream应用。为了保证终端用户得到良好的操作体验和高质量Media&nbsp;Stream，您需要检测您的Media&nbsp;Stream应用程序。使用LoadRunner&nbsp;，您可以记录和重放任何流行的多媒体数据流格式来诊断系统的性能问题，查找原由，分析数据的质量。</font></p>
				<p>
					<br />
					<font color="#000000">完整的企业应用环境的支持</font></p>
				<p>
					<br />
					<font color="#000000">　　LoadRunner&nbsp;支持广泛的协议，可以测试各种IT&nbsp;基础架构。&nbsp;</font></p>
				<p>
					<font color="#000000">全球测试管理系统</font></p>
				<p>
					<font color="#000000">　　TestDirector&nbsp;是业界第一个基于Web的测试管理系统,它可以在您公司内部或外部进行全球范围内测试的管理。通过在一个整体的应用系统中集成了测试管理的各个部分，包括<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求管理</A></STRONG>，测试计划，测试执行以及错误跟踪等功能，TestDirector极大地加速了测试过程。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　电子商务正影响着许多公司制定计划和建立自己的IT系统。很快，一个Web应用软件就能被创建，开发并立即展现在您的客户、供应商或合作伙伴的面前。然而，由于紧凑的开发计划和复杂的系统基构，Web应用软件的测试经常是被忽视的。为了与新经济同步，&nbsp;您必须开发经过<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csgl/xtcs/" target="_blank" >系统测试</A></STRONG>的高品质的网络应用软件。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　您需要设立一个中央点来管理测试过程。一套基于Web的测试管理系统提供了一个协同合作的环境和一个中央数据仓库。由于测试人员分布在各地，您需要一个集中的测试管理系统能让测试人员不管在何时何地都能参与整个测试过程。IT部门增长地会非常快，人员也会不断流动。您必须以最快的速度培训新的测试人员，教会他们所有与测试有关的知识技术。重点在于管理复杂的开发和测试过程，改善部门间的沟通，&nbsp;加速您测试的成功。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　TestDirector能消除组织机构间、地域间的障碍。它能让测试人员、开发人员或其它的IT人员通过一个中央数据仓库，在不同地方就能交互测试信息。TestDirector将测试过程流水化&mdash;&mdash;从测试需求管理，到测试计划，测试日程安排，测试执行到出错后的错误跟踪&mdash;&mdash;仅在一个基于浏览器的应用中便可完成，而不需要每个客户端都安装一套客户端程序。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">需求管理&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　程序的需求驱动整个测试过程。TestDirector&nbsp;的Web&nbsp;界面简化了这些需求管理过程，以此您可以验证应用软件的每一个特性或功能是否正常。通过提供一个比较直观的机制将需求和<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csyl/" target="_blank" >测试用例</A></STRONG>、测试结果和报告的错误联系起来，从而确保能达到最高的测试覆盖率。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　一般有2&nbsp;种方式可将需求和测试联系起来。其一，TestDirector&nbsp;捕获并跟踪所有首次发生的的应用需求。您可以在这些需求基础上生成一份测试计划，并将测试计划(?)对应与您的需求。例如，您或许有25&nbsp;个测试计划(?)可对应同一个应用需求。您一定能方便地管理需求和测试计划(?)之间可能存在的一种多配多的关系，确保每一个需求都经过测试。其二，由于Web&nbsp;应用是不断更新和变化的，需求管理允许测试人员加减或修改需求，并确定目前的应用需求已拥有了一定的测试覆盖率。它们帮助决定一个应用软件的哪些部分需要测试，哪些测试需要开发，是否完成的应用软件满足了用户的要求。对于任何动态地改变Web&nbsp;应用，必须审阅您的测试计划是否准确，确保其符合最当前的应用要求。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">计划测试&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　测试计划的制定是测试过程中至关重要的环节。它为整个测试提供了一个结构框架。TestDirector的Test&nbsp;Plan&nbsp;Manager&nbsp;在测试计划期尖，为测试小组提供一个关键要点和Web&nbsp;界面来协调团队间的沟通。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　Test&nbsp;Plan&nbsp;Manager&nbsp;指导测试人员如何将应用需求转化为具体的测试计划。这种直观的结构能帮助您定义如何测试您的应用软件，从而您能组织起明确的任务和责任。Test&nbsp;Plan&nbsp;Manager提供了多种方式来建立完整的测试计划。您可以从草图上建立一份计划，或根据您用Require-ments&nbsp;Manager所定义下的应用需求，通过Test&nbsp;Plan&nbsp;Wizard&nbsp;快捷地生成一份测试计划。如果您已经将计划信息以文字处理文件形式，如Microsoft&nbsp;Word&nbsp;方式储存，您可以再利用这些信息，并将它导入到Test&nbsp;Plan&nbsp;Manager。它把各种类型的测试汇总在一个可折叠式目录树内，您可以在一个目录下查询到所有的测试计划(?)。例如，你可以将人工和<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/zdcs/" target="_blank" >自动测试</A></STRONG>，如功能性的，还原和负载测试方案结合在同一位置。&nbsp;<br />
					Test&nbsp;Plan&nbsp;Manager&nbsp;还能进一步的帮助您完善<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csyl/" target="_blank" >测试设计</A></STRONG>和以文件形式描述每一个测试步骤，包括对每一项测试，用户反应的顺序，检查点和预期的结果TestDirector&nbsp;还能为每一项测试连加附属文件，如Word&nbsp;，Excel&nbsp;，HTML&nbsp;，用于更详尽的记录每次测试计划。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　Web&nbsp;网络应用日新月异，您的应用需求也随之不断改变。您需要相应地更新您的测试计划，优化测试内容。即使频繁的更新，TestDirector&nbsp;仍能简单地将应用需求与相关的测试对应起来。TestDirector&nbsp;还可支持不同的测试方式来适应您公司特殊的测试流程。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　多数的测试项目需要一个有人工与自动测试的结合，包括健全，还原和系统测试。但即使符合自动测试要求的工具，在大部分情况下也需要人工的操作。启用一个演变性的而非革新性的自动化切换机制，能让测试人员决定哪些重复的人工测试可转变为自动脚本以提高测试速度。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　TestDirector&nbsp;还能简化将人工测试切换到自动测试脚本的转化，并可立即启动测试设计过程。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">安排和执行测试&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　一旦测试计划建立后，TestDirector&nbsp;的测试实验室管理为测试日程制订提供一个基于Web&nbsp;的框架。它的Smart&nbsp;Scheduler根据测试计划中创立的指标对运行着的测试执行监控。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　当网络上任何一台主机空闲，测试可以彻夜执行于其上。Smart&nbsp;Scheduler&nbsp;能自动分辨是系统还是应用错误，然后将测试重新安排到网络上的其他机器。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　对于不断改变的Web&nbsp;应用，经常性的执行测试对于追查出错发生的环节和评估应用质量都是至关重要的。然而，这些测试的运行都要消耗测试资源和时间。使用Graphic&nbsp;Designer&nbsp;图表设计，您可以很快地将测试分类以满足不同的测试目的，如功能性测试，负载测试，完整性测试等。它的拖动功能可简化设计和排列在多个机器上运行的测试，最终根据设定好的时间、路径或其它测试的成功与否，为序列测试制订执行日程。Smart&nbsp;Scheduler&nbsp;能让您在更短的时间内，在更少的机器上完成更多的测试。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　用WinRunner&nbsp;,&nbsp;Astra&nbsp;QuickTest&nbsp;,Astra&nbsp;LoadTest&nbsp;或LoadRunner&nbsp;来自动运行功能性或负载测试，无论成功与否，测试信息都会被自动汇集传送到TestDirector&nbsp;的数据储存中心。同样，人工测试也以此方式运行。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000"><STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/qxgl/" target="_blank" >缺陷管理</A></STRONG>&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　当测试完成后，项目经理必须解读这些测试数据并将这些信息用于工作中。当有出错发现时，他们还要指定相关人员及时纠正。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　TestDirector&nbsp;的出错管理直接贯穿作用于测试的全过程，以提供管理系统终端-终端的出错跟踪&mdash;从最初的问题发现到修改错误再到检验修改结果。由于同一项目组中的成员经常分布于不同的地方，TestDirector&nbsp;基于浏览器的特征，使出错管理能让多个用户何时何地都可通过Web&nbsp;查询出错跟踪情况。利用出错管理，测试人员只需进入一个URL&nbsp;，就可汇报和更新错误，过滤整理错误列表并作趋势分析。在进入一个出错案例前，测试人员还可自动执行一次错误数据库的搜寻，确定是否已有类似的案例记录。这一查寻功能可避免重复劳动。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">图形化和报表输出&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　测试过程的最后一步是分析测试结果，确定应用软件是否已布属成功或需要再次的测试。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　TestDirector&nbsp;常规化的图表和报告和在测试的任一环节帮助您对数据信息进行分析。&nbsp;</font></p>
				<p>
					<br />
					<font color="#000000">　　TestDirector&nbsp;还以标准的HTML&nbsp;或Word&nbsp;形式提供一种生成和发送正式测试报告的一种简单方式。测试分析数据还可简便地输入到一种工业标准化的报告工具，如Excel&nbsp;，ReportSmith&nbsp;，CrystalReports&nbsp;，和其它类型的第三方工具。&nbsp;</font></p>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#]]></description>
    <pubDate>Mon, 19 Dec 2011 10:02:40 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>WinRunner</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[WinRunner使用经验介绍]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/winrunner/2011/1219/203779.html</link>
    <description><![CDATA[<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/winrunner/" target="_blank" >WinRunner</A></STRONG>在项目中的作用</p>
<p>
	　　可以用WinRunner为所测试应用程序的GUI，功能和<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csgl/hgcs/" target="_blank" >回归测试</A></STRONG>创建自动化脚本。</p>
<p>
	　　WinRunner的测试过程</p>
<p>
	　　主要包括如下6个阶段：</p>
<p>
	　　1). 创建GUI Map文件：WinRunner可以通过它来识别被测试应用程序中的GUI对象。</p>
<p>
	　　2). 创建测试脚本：通过录制，编程，或两者的组合创建。在录制测试脚本时，在你想检查被测试应用程序响应的地方插入验证点。</p>
<p>
	　　3). 调试脚本：用调试(Debug)的模式运行测试脚本以确保它们可以平稳地运行。还可以使用WinRunner提供的Step, Step Into, Step out功能来调试脚本。</p>
<p>
	　　4). 运行测试：用验证(Verify)的模式运行测试脚本来测试你的应用程序。当WinRunner在运行中碰到验证点时，它会将被测应用程序中的当前数据和以前捕捉的期望数据进行比较，如果发现了任何不匹配，WinRunner将会把目前的情况捕捉下来作为真实的结果。</p>
<p>
	　　5). 检查结果：确定测试脚本的成功或是失败。在每次测试脚本运行结束之后，WinRunner会将结果显示在报告中。它描述了所有在运行中碰到的重要的事件，例如验证点，错误信息，系统信息或是用户信息。如果发现在运行中有任何不匹配的验证点，你可以在测试结果窗口中查看期望的和实际的结果。</p>
<p>
	　　6). 提交缺陷：如果一个测试脚本是由于所测试应用程序中的缺陷而导致失败的，你可以直接从测试结果窗口中提取缺陷的相关信息。</p>
<p>
	　　WinRunner 的GUI Map文件</p>
<p>
	　　WinRunner利用GUI Map文件来识别应用程序中的对象。它将学习到的窗口或对象信息储存在GUI Map文件中。当WinRunner运行测试脚本时，它利用GUI Map来定位对象。它从GUI Map文件中读取对象的描述并且在被测应用程序中寻找具有相同属性的对象。</p>
<p>
	　　在GUI Map文件中的每一个对象都有一个逻辑名称(logical name)和一个物理描述(physical description)。对象的逻辑名称是由其类决定的。在大多数情况下，我们可以将逻辑名称看成是显示在对象上的标签。你可以修改已分配的逻辑名称当它不是十分具有描述性或太长的时候。当对象的属性发生改变时，你必须要修改其物理描述。</p>
<p>
	　　GUI Map文件的扩展名是&quot;.gui&quot;。</p>
<p>
	　　GUI Map文件分为两种类型：</p>
<p>
	　　&middot;全局GUI Map文件：一个为整个应用程序使用的GUI Map文件</p>
<p>
	　　&middot;每个测试脚本的GUI Map文件：在每个测试脚本创建之后，WinRunner会自动为其创建一个GUI Map文件。</p>
<p>
	　　我们可以通过工具菜单中GUI Map Editor来查看当前载入的GUI Map文件及其内容。GUI Map Editor 显示多个已创建的GUI Map文件和认识到的带有逻辑名和物理描述的窗口和对象。</p>
<p>
	　　在录制脚本时，WinRunner会自已学习对象和窗口，并将它们储存在临时的GUI Map文件中。我们可以在General选项中指定是否需要每次都载入这种临时GUI Map。</p>
<p>
	　　当我们载入一个GUI Map文件时，关于窗口和对象的信息连同其逻辑名称和物理描述都载入到内存中。因此当WinRunner在一个特定的窗口上运行脚本时，它可以用这些在内存中的信息识别对象。</p>
<p>
	　　WinRunner的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/zdcsjbyy/" target="_blank" >脚本语言</A></STRONG></p>
<p>
	　　WinRunner的脚本语言是<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/" target="_blank" >Mercury</A></STRONG> Interactive&rsquo;s Test Script Language (TSL)，这是一种类C的脚本语言。你可以通过增加另外的TSL函数和编程元素(例如<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/windows/" target="_blank" >Windows</A></STRONG> API)或WinRunner的虚拟编程工具(函数生成器(Function Generator))来增强你录制的脚本。</p>
<p>
	　　WinRunner的录制模式</p>
<p>
	　　在WinRunner中，有两种不同的录制模式：</p>
<p>
	　　&middot;环境判断录制(Context Sensitive recording)：通过识别GUI对象录制你在被测应用程序中执行的操作。</p>
<p>
	　　&middot;模拟录制(Analog recording)：录制键盘的输入，鼠标的点击，和鼠标指针在屏幕上精确的x，y轴</p>
<p>
	　　WinRunner的运行模式</p>
<p>
	　　在WinRunner中，有三种不同的运行模式：</p>
<p>
	　　&middot;验证Verify：使用这种方式来检查你的应用程序</p>
<p>
	　　&middot;调试Debug：使用这种方式来帮助你识别测试脚本中的bug</p>
<p>
	　　&middot;更新Update：使用这种方式来更新测试脚本的期望结果或创建一个新的期望结果文件夹</p>
<p>
	　　WinRunner的Add-In</p>
<p>
	　　载入Add-Ins实际上是将在Add-In中的特殊的函数装载到内存中。当创建测试脚本时，只有这些选中的Add-In中的函数会列在函数生成器中，在运行脚本时，只有那些在载入的Add-In中的函数可以被执行，否则WinRunner将会给出一个不能识别函数的错误信息。</p>
<p>
	　　WinRunner的验证点(Checkpoint)</p>
<p>
	　　验证点可以把被测应用程序的当前行为和早前版本的行为进行比较。</p>
<p>
	　　在WinRunner中有4种验证点：</p>
<p>
	　　&middot; GUI checkpoints：验证GUI对象的信息。例如，你可以检查一个按钮是否可用或查看在一个列表中哪一个选项被选中。</p>
<p>
	　　&middot; Bitmap checkpoints：给窗口或所测试应用程序的部分做快照，并把它和早先版本中捕捉的图像做比较。</p>
<p>
	　　&middot; Text checkpoints ：在GUI对象或位图中读取文字，使你可以验证它们的内容。</p>
<p>
	　　&middot; Database checkpoints：基于你创建在<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>的查询，检查一个结果集的内容和列、行的数量</p>
<p>
	　　Checklist文件包含了我们正在验证的对象的属性和相关信息 。gui*.chk文件包含了期望的结果，并储存在exp文件夹中。</p>
<p>
	　　同步点(synchronization points)</p>
<p>
	　　同步点使你可以解决预期的在测试脚本和你应用程序之间的时间问题。例如，如果你创建一个打开数据库应用程序的测试脚本，你可以增加一个同步点以让测试脚本等待直到数据库中的记录载入到屏幕上。</p>
<p>
	　　对于模拟测试(Analog testing)，你也可以使用一个同步点来确保WinRunner在一个指定的位置重新放置窗口。当你运行一个测试脚本时，鼠标指针沿着准确的坐标行进。重新放置窗口使鼠标指针接触到窗口中正确的元素。</p>
<p>
	　　编译模块(compile module)</p>
<p>
	　　编译模块实际上也是一种脚本，只不过它包含了一个可以被其它的测试脚本频繁地调用，用户自定义函数集的库文件。当你载入一个编译模块时，它的函数将自动的被编译并保存在内存中。其它的测试脚本可以直接调用它们。#p#分页标题#e#</p>
<p>
	　　编译模块可以改进脚本的组织和性能。由于你在使用它们之前已经调试过编译模块，因此你的测试脚本只需要少量的错误检查。另外，调用一个已经编译的函数明显地比解释测试脚本中的函数快得多。</p>
<p>
	　　当编译模块用来储存可重用的函数时，测试脚本包含了在WinRunner中的可执行文件。编译模块是不可执行的。</p>
<p>
	　　在保存为编译模块时，WinRunner会自动执行一次预编译。</p>
默认情况下，包含TSL代码的模块的属性是&ldquo;main&rdquo;。主模块可以在其他的模块中被调用执行。除了当WinRunner识别到一个&ldquo;call&rdquo;语句时，主模块会被动态地被编译为机器代码。例如：
<table width="100%">
	<tbody>
		<tr>
			<td bgcolor="#<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>cccc" class="content">
				<p>
					call cso_init();</p>
				<p>
					call( &quot;C:\\MyAppFolder\\&quot; &amp; &quot;app_init&quot; );</p>
			</td>
		</tr>
	</tbody>
</table>
编译模块被载入到内存中以便其他模块引用。
<table width="100%">
	<tbody>
		<tr>
			<td bgcolor="#cccccc" class="content">
				reload (&quot;C:\\MyAppFolder\\&quot; &amp; &quot;flt_lib&quot;) 或load (&quot;C:\\MyAppFolder\\&quot; &amp; &quot;flt_lib&quot;);</td>
		</tr>
	</tbody>
</table>
<p>
	　　数据驱动测试(data driven tests)</p>
<p>
	　　当你测试你的应用程序时，你或许想检查它如何执行有着大量数据集的相同操作。你可以用一个运行10次的循环来创建一个数据驱动测试：每次循环运行时，它由不同的数据集驱动。为了使WinRunner 能够使用数据来驱动测试，你必须将数据连接到所要驱动的测试脚本。这就叫参数化(parameterizing)你的测试。数据存储在一个数据表格(data table)中。你可以手工执行这些操作，或使用DataDriver Wizard来参数化你的测试脚本并储存数据在数据表格中。</p>
<p>
	　　数据驱动测试的步骤如下：</p>
<p>
	　　&middot; 创建一测试脚本</p>
<p>
	　　&middot; 转换为数据驱动的测试脚本并准备一个数据库</p>
<p>
	　　&middot; 运行测试脚本</p>
<p>
	　　&middot; 分析测试结果</p>
<p>
	　　无法识别GUI对象的原因</p>
<p>
	　　WinRunner会由于以下多种原因导致不能识别GUI对象。</p>
<p>
	　　&middot;不是标准的Windows对象</p>
<p>
	　　&middot;没有安装所需的Add-In</p>
<p>
	　　&middot;如果所使用的浏览器和WinRunner的版本不兼容，GUI Map编辑器将不能认识在浏览器窗口中显示的任何对象</p>
<p>
	　　启动文件(start up file)</p>
<p>
	　　在General Options -&gt;Environment-&gt; Startup文本框中，选择或输入你希望作为启动文件的 测试脚本</p>
<p>
	　　输入测试脚本的相关信息</p>
<p>
	　　在创建一个测试脚本之前，你可以在Test Properties-&gt; General和 Description中输入和脚本相关的信息，如被测功能的类型，测试脚本的详细描述，引用的相关功能说明书文档</p>
<p>
	　　如何处理定制对象(custom objects)</p>
<p>
	　　定制对象是不属于WinRunner所使用的标准类之一的任何GUI 对象。WinRunner学习此类的对象为generic &quot;object&quot;类。WinRunner利用obj_mouse_语句来记录在定制对象的操作。</p>
<p>
	　　如果定制对象和一个标准的对象很相似，你可以映射它为标准类别之一。你也可以在环境判断测试(Context Sensitive testing)时配置WinRunner用于识别定制对象的属性。</p>
<p>
	　　什么是虚拟对象(virtual object)并且如何使用它们?</p>
<p>
	　　应用程序可能会含有一些外观和行为和GUI对象相似的位图。WinRunner利用win_mouse_click 语句来记录操作。通过定义一个位图对象为虚拟对象，当你录制并运行测试时，你可以教WinRunner将它象一个GUI对象一样对待。</p>
]]></description>
    <pubDate>Mon, 19 Dec 2011 09:59:22 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>WinRunner</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[WinRunner脚本标准格式]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/winrunner/2011/1219/203778.html</link>
    <description><![CDATA[<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/winrunner/" target="_blank" >WinRunner</A></STRONG> 脚本标准格式</p>
<p>
	　　目录结构</p>
<p>
	　　存放目录要求：</p>
<p>
	　　1、根目录与项目名称相同，如江西移动BOSS 测试目录为JXBOSS</p>
<p>
	　　2、根目录下应该是按子项目存放，如SALES、ACCOUNT。如果有公共脚本，存放在Share 目录下面</p>
<p>
	　　3、子项目下面应该根据功能/TestCase 来存放，如果有公共脚本也应该存放在Share 目录下</p>
<p>
	　　4、为存取及备份方便，目录不能使用中文。使用的名称应该尽量与<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>保持一致</p>
<p>
	　　5、GUI 文件应该存放在脚本的同一目录，并且名称相同</p>
<p>
	　　6、正确性测试(使用完全正确数据来检查程序功能是否完成)目录名称规定为validity</p>
<p>
	　　以下是一个目录例子</p>
<p>
	　　JxBoss</p>
<p>
	　　-Sales</p>
<p>
	　　--ChangeSimCard</p>
<p>
	　　--validity</p>
<p>
	　　--CheckSimNoExistAnIdError</p>
<p>
	　　--Share</p>
<p>
	　　--Share</p>
<p>
	　　-A<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>ount</p>
<p>
	　　脚本要求</p>
<p>
	　　注释要求</p>
<p>
	　　脚本创建及修改说明注释</p>
<p>
	　　每个脚本的开头注释格式如下：</p>
<p>
	　　#脚本名称：文件名称</p>
<p>
	　　#创建人：创建人</p>
<p>
	　　#创建日期：格式为YYYY/MM/DD</p>
<p>
	　　#功能：脚本完成的功能描述</p>
<p>
	　　#运行前要求：运行前的要打开的窗口及状态要求、<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>中的数据要求、被测试程序运行目录等</p>
<p>
	　　#参考文档：描述录制代码是参考的有关设计测试文档</p>
<p>
	　　#修改历史：</p>
<p>
	　　# 修改人：</p>
<p>
	　　# 修改时间：格式为YYYY/MM/DD</p>
<p>
	　　# 主要修改内容：</p>
注意创建人及修改人必须是中文完整姓名，不允许使用其它任何名称。运行前的要求一定要描述清楚子功能注释在各小段功能前应该加入功能注释，注意不能只是WinRunner 自己产生的注释如：
<table width="70%">
	<tbody>
		<tr>
			<td bgcolor="#cccccc" class="content">
				&nbsp;&nbsp;&nbsp; # insert a record<br />
				&nbsp;&nbsp;&nbsp; # Flight Reservation<br />
				&nbsp;&nbsp;&nbsp; set_window (&quot;Flight Reservation&quot;, 1);<br />
				&nbsp;&nbsp;&nbsp; obj_mouse_click (&quot;Button&quot;, 13, 16, LEFT);<br />
				&nbsp;&nbsp;&nbsp; obj_type (&quot;MSMaskWndClass&quot;,&quot;101002&quot;);<br />
				&nbsp;&nbsp;&nbsp; list_select_item (&quot;Fly From:&quot;, &quot;London&quot;); # Item Number 2;<br />
				&nbsp;&nbsp;&nbsp; list_select_item (&quot;Fly To:&quot;, &quot;Paris&quot;); # Item Number 3;<br />
				&nbsp;&nbsp;&nbsp; obj_mouse_click (&quot;FLIGHT&quot;, 56, 22, LEFT);</td>
		</tr>
	</tbody>
</table>
<p>
	　　注释可以使用英文或中文。</p>
<p>
	　　修改代码说明注释</p>
<p>
	　　在具体修改的代码附近应该加入如下注释</p>
<p>
	　　#修改人</p>
<p>
	　　#修改日期</p>
<p>
	　　#修改原因/增加功能</p>
<p>
	　　注释可以放在一行中，简单修改可以忽略&ldquo;修改原因/增加功能&rdquo;，复杂修改应该不能忽略(简单及复杂标准待定)</p>
<p>
	　　代码要求</p>
<p>
	　　路径要求</p>
<p>
	　　代码中使用的路径都应该使用相对路径，不允许出现类似&ldquo;d:\\&rdquo;、&ldquo;\\&rdquo;下的代码，应该使用类似&ldquo;..\\..\\&rdquo;的代码。</p>
在Script 里面打开和关闭GUI各Script 的GUI 的文件应该分开保存在与Script 保存在同一个目录，应该使用用GUI_load 在SCRIPT 开始以前就装载GUI，在SCRIPT 开始增加：
<table width="70%">
	<tbody>
		<tr>
			<td bgcolor="#cccccc" class="content">
				<br />
				&nbsp;&nbsp;&nbsp; if (GUI_load(&quot;.\\login.gui&quot;)!=0)<br />
				&nbsp;&nbsp;&nbsp; {<br />
				&nbsp;&nbsp;&nbsp; pause (&quot;Can&#39;t load login.gui&quot;);<br />
				&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; texit;<br />
				&nbsp;&nbsp;&nbsp; }</td>
		</tr>
	</tbody>
</table>
<p>
	　　在SCRIPT 完毕的时候加入</p>
<p>
	　　GUI_close(&quot;.\\login.gui&quot;);</p>
<p>
	　　关闭GUI，注意代码中的路径一定要使用相对路径。</p>
<p>
	　　错误报告</p>
在使用错误报告的时候，应该注意包括出错的脚本文件名称，这样当脚本文件被其他脚本调用时候，也能很清楚在什么地方没有通过。Report_msg 的参数格式定义为&ldquo;文件名称:错误描述&rdquo;。同时鉴于WinRunner 的Check 函数不能提供清楚的错误报告，要求错误报告使用以方式
<table width="70%">
	<tbody>
		<tr>
			<td bgcolor="#cccccc" class="content">
				if ( win_check_bitmap(&quot;Flight Reservations&quot;, &quot;Img1&quot;, 1)!=E_OK)<br />
				&nbsp;&nbsp;&nbsp; {<br />
				&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; report_msg(&quot;DateCheck:月份输入错误提示不对!&quot;);<br />
				&nbsp;&nbsp;&nbsp; }</td>
		</tr>
	</tbody>
</table>
<p>
	　　附件：一个完整的例子</p>
<p>
	　　#脚本名称：DateCheck</p>
<p>
	　　#创建人：谢慧强</p>
<p>
	　　#创建日期：2002/09/08</p>
<p>
	　　#功能：检查FLIGHTA 程序在输入错误月份的时候提示是否正确</p>
<p>
	　　#运行前要求：要求FLIGHA 进入定票窗口(New_Order 状态)且无任何数据输入</p>
<p>
	　　# 或者FLIGHTA 没有运行，这时候要求FLIGHTA。EXE 位</p>
<p>
	　　# 于E:\\Program Files\\<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/" target="_blank" >Mercury</A></STRONG>Interactive\\WinRunner\\samples\\flight\\app\\flight1a.exe</p>
<p>
	　　#参考文档：无</p>
<p>
	　　#修改历史：</p>
<p>
	　　# 修改人：谢慧强</p>
<p>
	　　# 修改时间：2002/09/09</p>
# 主要修改内容：不采用位图方式，改为直接判断字符串内容
<table width="70%">
	<tbody>
		<tr>
			<td bgcolor="#cccccc" class="content">
				#load gui file<br />
				&nbsp;&nbsp;&nbsp; #Flight Reservation<br />
				&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (GUI_load(&quot;.\\DateCheck.gui&quot;)!=0)<br />
				&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
				&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; report_msg (&quot;DataCheck:Can&#39;t load .\\DateCheck.gui&quot;);<br />
				&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; texit;<br />
				&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
				&nbsp;&nbsp;&nbsp; #Check windows exists ,if don&#39;t exist ,call login to open it.<br />
				&nbsp;&nbsp;&nbsp; # Flight Reservation<br />
				&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (win_exists(&quot;Flight Reservation&quot;)!=E_OK){<br />
				&nbsp;&nbsp;&nbsp; #pause (&quot;<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/windows/" target="_blank" >Windows</A></STRONG> Flight Reservation don&#39;t exist&quot;);<br />
				&nbsp;&nbsp;&nbsp; #texit;<br />
				&nbsp;&nbsp;&nbsp; call &quot;..\\login\\login&quot;();<br />
				&nbsp;&nbsp;&nbsp; }<br />
				&nbsp;&nbsp;&nbsp; #input error month<br />
				&nbsp;&nbsp;&nbsp; win_activate (&quot;Flight Reservation&quot;);<br />
				&nbsp;&nbsp;&nbsp; set_window (&quot;Flight Reservation&quot;, 3);<br />
				&nbsp;&nbsp;&nbsp; obj_mouse_drag (&quot;Button_4&quot;, 17, 6, 17, 7, LEFT);<br />
				&nbsp;&nbsp;&nbsp; obj_type (&quot;MSMaskWndClass&quot;,&quot;301212&quot;);<br />
				&nbsp;&nbsp;&nbsp; list_select_item (&quot;Fly From:&quot;, &quot;Denver&quot;); # Item Number 0;<br />
				&nbsp;&nbsp;&nbsp; #check message bitmap<br />
				&nbsp;&nbsp;&nbsp; # Flight Reservations_1<br />
				&nbsp;&nbsp;&nbsp; set_window (&quot;Flight Reservations&quot;, 3);<br />
				&nbsp;&nbsp;&nbsp; #2002/09/09 谢慧强<br />
				&nbsp;&nbsp;&nbsp; #if ( win_check_bitmap(&quot;Flight Reservations&quot;, &quot;Img1&quot;, 1)!=E_OK)<br />
				&nbsp;&nbsp;&nbsp; #static_check_info(&quot;Invalid month Entered.The month must be greater than 01 and&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; less than<br />
				&nbsp;&nbsp;&nbsp; 12.(static)&quot;,&quot;enabled&quot;,1);<br />
				&nbsp;&nbsp;&nbsp; if (static_check_info(&quot;CheckMessage&quot;,&quot;label&quot;,&quot;Invalid month Entered.The month must&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; be<br />
				&nbsp;&nbsp;&nbsp; greater than 01 and less than 12.&quot;)!=E_OK)<br />
				&nbsp;&nbsp;&nbsp; #2002/09/09 谢慧强修改结束<br />
				&nbsp;&nbsp;&nbsp; {<br />
				&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; report_msg(&quot;DateCheck:月份输入错误提示不对!&quot;);<br />
				&nbsp;&nbsp;&nbsp; }<br />
				&nbsp;&nbsp;&nbsp; button_press (&quot;确定&quot;);<br />
				&nbsp;&nbsp;&nbsp; #close gui file<br />
				&nbsp;&nbsp;&nbsp; GUI_close(&quot;.\\DateCheck.gui&quot;);&nbsp;</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#]]></description>
    <pubDate>Mon, 19 Dec 2011 09:55:40 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>WinRunner</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[利用loadrunner测试ORACLE存储过程的性能]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2011/1219/203777.html</link>
    <description><![CDATA[<p>
	　　首先需要安装 <STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LR</A></STRONG>的.NET ADD-IN ，在<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>环境编写代码，做<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>连接，然后调用执行存储过程。</p>
<p>
	　　装好以后，打开程序，应该看到菜单栏里多了一个：</p>
<p>
	　　然后添加一个LR项目：</p>
<center>
	<img alt="" border="1" height="356" src="/uploads/allimg/111219/0954232R3-0.jpg" width="525" /></center>
<p>
	　　之后就可以编码了，我写了个代码，如下：</p>
<table width="70%">
	<tbody>
		<tr>
			<td bgcolor="#<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>cccc" class="content">
				<span class="content">using System;<br />
				using System.Runtime.InteropServices;<br />
				using System.ComponentModel;<br />
				using System.Data;<br />
				using System.Data.<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/oracle/" target="_blank" >Oracle</A></STRONG>Client;<br />
				using ShangXin.Data;<br />
				using System.Collections;<br />
				using System.Web;</span><br />
				<p class="content">
					namespace LoadRunnerUser<br />
					{<br />
					/// &lt;summary&gt;<br />
					/// Summary description for VuserClass.<br />
					/// &lt;/summary&gt;<br />
					[ClassInterface(ClassInterfaceType.AutoDual)]<br />
					public class VuserClass<br />
					{<br />
					LoadRunner.LrApi <STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >lr</A></STRONG>;<br />
					protected System.Data.OracleClient.OracleDataAdapter oracleDA;<br />
					protected System.Data.OracleClient.OracleCommand loadCommand;<br />
					protected System.Data.OracleClient.OracleConnection oracleConnection;</p>
				<p>
					<br />
					<span class="content">public VuserClass()<br />
					{<br />
					// LoadRunner Standard API Interface :: DO NOT REMOVE!!!<br />
					lr = new LoadRunner.LrApi();<br />
					}</span></p>
				<p class="content">
					protected System.Data.OracleClient.OracleConnection GetOracleConnection()////sqlConnection<br />
					{<br />
					if (oracleConnection==null)<br />
					oracleConnection=new System.Data.OracleClient.OracleConnection();<br />
					oracleConnection.ConnectionString=&quot;User Id=test;Password=write;Data Source=escalade&quot;;<br />
					return oracleConnection;<br />
					}</p>
				<p class="content">
					<br />
					// &#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;<br />
					public int Initialize()<br />
					{<br />
					// TO DO: Add virtual user&#39;s initialization routines</p>
				<p class="content">
					return lr.PASS;<br />
					}</p>
				<p class="content">
					// &#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;<br />
					public int Actions()<br />
					{<br />
					try<br />
					{<br />
					<br />
					lr.start_transaction(&quot;TestGetWithDrawOrderByCode&quot;);<br />
					System.Data.OracleClient.OracleConnection conn = new OracleConnection(&quot;User Id=test;Password=write;Data Source=escalade&quot;);<br />
					System.Data.OracleClient.OracleCommand comm = new OracleCommand();<br />
					comm.Connection = conn;<br />
					comm.CommandText = &quot;BILL.GetWithDrawOrderByCode&quot;;<br />
					comm.CommandType = CommandType.StoredProcedure;<br />
					//输入参数<br />
					System.Data.OracleClient.OracleParameter param1=comm.Parameters.Add(&quot;V_CODE&quot;,OracleType.VarChar,20);<br />
					param1.Direction = ParameterDirection.Input;<br />
					param1.Value =&quot;TH15&quot;;<br />
					//输出参数<br />
					System.Data.OracleClient.OracleParameter param2=comm.Parameters.Add(&quot;RETCURSOR&quot;,OracleType.Cursor);<br />
					param2.Direction = ParameterDirection.Output;<br />
					<br />
					DataTable dt = new DataTable();<br />
					oracleDA = new System.Data.OracleClient.OracleDataAdapter();<br />
					oracleDA.SelectCommand = comm;<br />
					oracleDA.Fill(dt);<br />
					int iCount=Convert.ToInt32(dt.Rows.Count.ToString());<br />
					if(iCount&gt;0)<br />
					lr.end_transaction(&quot;TestGetWithDrawOrderByCode&quot;,lr.PASS);<br />
					else<br />
					lr.end_transaction(&quot;TestGetWithDrawOrderByCode&quot;,lr.FAIL);<br />
					<br />
					}</p>
				<p class="content">
					catch(Exception ex)<br />
					{<br />
					string error = ex.Message;<br />
					}</p>
				<p class="content">
					return lr.PASS;<br />
					}</p>
				<p class="content">
					// &#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;<br />
					public int Terminate()<br />
					{<br />
					// TO DO: Add virtual user&#39;s termination routines</p>
				<p class="content">
					return lr.PASS;<br />
					}</p>
				<p class="content">
					}<br />
					}</p>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#]]></description>
    <pubDate>Mon, 19 Dec 2011 09:37:41 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111219/0954232R3-0-lp.jpg</subImagePath>
     <category>LoadRunner</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[LoadRunner函数小全]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2011/1216/203774.html</link>
    <description><![CDATA[<table align="center" border="0" width="86%">
	<tbody>
		<tr>
			<td class="content">
				　&nbsp;给出一部分常用的LoadRunner函数，供大家参考。
				<p>
					<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LR</A></STRONG>函数：</p>
				<p>
					<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >lr</A></STRONG>_start_transaction</p>
				<p>
					为性能分析标记事务的开始</p>
				<p>
					lr_end_transaction</p>
				<p>
					为性能分析标记事务的结束</p>
				<p>
					lr_rendezvous</p>
				<p>
					在 Vuser 脚本中设置集合点</p>
				<p>
					lr_think_time</p>
				<p>
					暂停 Vuser 脚本中命令之间的执行</p>
				<p>
					lr_end_sub_transaction</p>
				<p>
					标记子事务的结束以便进行性能分析</p>
				<p>
					lr_end_transaction</p>
				<p>
					标记 LoadRunner 事务的结束</p>
				<p>
					Lr_end_transaction(&quot;trans1&quot;,Lr_auto);</p>
				<p>
					lr_end_transaction_instance</p>
				<p>
					标记事务实例的结束以便进行性能分析</p>
				<p>
					lr_fail_trans_with_error</p>
				<p>
					将打开事务的状态设置为 LR_FAIL 并发送错误消息</p>
				<p>
					lr_get_trans_instance_duration</p>
				<p>
					获取事务实例的持续时间（由它的句柄指定）</p>
				<p>
					lr_get_trans_instance_wasted_time</p>
				<p>
					获取事务实例浪费的时间（由它的句柄指定）</p>
				<p>
					lr_get_transaction_duration</p>
				<p>
					获取事务的持续时间（按事务的名称）</p>
				<p>
					lr_get_transaction_think_time</p>
				<p>
					获取事务的思考时间（按事务的名称）</p>
				<p>
					lr_get_transaction_wasted_time</p>
				<p>
					获取事务浪费的时间（按事务的名称）</p>
				<p>
					lr_resume_transaction</p>
				<p>
					继续收集事务数据以便进行性能分析</p>
				<p>
					lr_resume_transaction_instance</p>
				<p>
					继续收集事务实例数据以便进行性能分析</p>
				<p>
					lr_set_transaction_instance_status</p>
				<p>
					设置事务实例的状态</p>
				<p>
					lr_set_transaction_status</p>
				<p>
					设置打开事务的状态</p>
				<p>
					lr_set_transaction_status_by_name</p>
				<p>
					设置事务的状态</p>
				<p>
					lr_start_sub_transaction</p>
				<p>
					标记子事务的开始</p>
				<p>
					lr_start_transaction</p>
				<p>
					标记事务的开始</p>
				<p>
					Lr_start_transaction(&quot;trans1&quot;);</p>
				<p>
					lr_start_transaction_instance</p>
				<p>
					启动嵌套事务（由它的父事务的句柄指定）</p>
				<p>
					lr_stop_transaction</p>
				<p>
					停止事务数据的收集</p>
				<p>
					lr_stop_transaction_instance</p>
				<p>
					停止事务（由它的句柄指定）数据的收集</p>
				<p>
					lr_wasted_time</p>
				<p>
					消除所有打开事务浪费的时间</p>
				<p>
					lr_get_attrib_double</p>
				<p>
					检索脚本命令行中使用的 double 类型变量</p>
				<p>
					lr_get_attrib_long</p>
				<p>
					检索脚本命令行中使用的 long 类型变量</p>
				<p>
					lr_get_attrib_string</p>
				<p>
					检索脚本命令行中使用的字符串</p>
				<p>
					lr_user_data_point</p>
				<p>
					记录用户定义的数据示例</p>
				<p>
					lr_whoami</p>
				<p>
					将有关 Vuser 脚本的信息返回给 Vuser 脚本</p>
				<p>
					lr_get_host_name</p>
				<p>
					返回执行 Vuser 脚本的主机名</p>
				<p>
					lr_get_master_host_name</p>
				<p>
					返回运行 LoadRunner Controller 的计算机名</p>
				<p>
					lr_eval_string</p>
				<p>
					用参数的当前值替换参数</p>
				<p>
					lr_save_string</p>
				<p>
					将以 NULL 结尾的字符串保存到参数中</p>
				<p>
					lr_save_var</p>
				<p>
					将变长字符串保存到参数中</p>
				<p>
					lr_save_datetime</p>
				<p>
					将当前日期和时间保存到参数中</p>
				<p>
					lr _advance_param</p>
				<p>
					前进到下一个可用参数</p>
				<p>
					lr _decrypt</p>
				<p>
					解密已编码的字符串</p>
				<p>
					lr_eval_string_ext</p>
				<p>
					检索指向包含参数数据的缓冲区的指针</p>
				<p>
					lr_eval_string_ext_free</p>
				<p>
					释放由 lr_eval_string_ext 分配的指针</p>
				<p>
					lr_save_searched_string</p>
				<p>
					在缓冲区中搜索字符串实例，并相对于该字符串实例，将该缓冲区的一部分保存到参数中</p>
				<p>
					lr_debug_message</p>
				<p>
					将调试信息发送到输出窗口</p>
				<p>
					lr_error_message</p>
				<p>
					将错误消息发送到输出窗口</p>
				<p>
					lr_get_debug_message</p>
				<p>
					检索当前消息类</p>
				<p>
					lr_log_message</p>
				<p>
					将消息发送到日志文件</p>
				<p>
					lr_output_message</p>
				<p>
					将消息发送到输出窗口</p>
				<p>
					lr_set_debug_message</p>
				<p>
					设置调试消息类</p>
				<p>
					lr_vuser_status_message</p>
				<p>
					生成带格式的输出，并将其写到 ControllerVuser 状态区域</p>
				<p>
					lr_message</p>
				<p>
					将消息发送到 Vuser 日志和输出窗口</p>
				<p>
					lr_load_dll</p>
				<p>
					加载外部 DLL</p>
				<p>
					lr_peek_events</p>
				<p>
					指明可以暂停 Vuser 脚本执行的位置</p>
				<p>
					lr_think_time</p>
				<p>
					暂停脚本的执行，以模拟思考时间（实际用户在操作之间暂停以进行思考的时间）</p>
				<p>
					lr_continue_on_error</p>
				<p>
					指定处理错误的方法</p>
				<p>
					lr_continue_on_error (0）；lr_continue_on_error （1）；</p>
				<p>
					lr_rendezvous</p>
				<p>
					在 Vuser 脚本中设置集合点</p>
				<p>
					TE_wait_cursor</p>
				<p>
					等待光标出现在终端窗口的指定位置</p>
				<p>
					TE_wait_silent</p>
				<p>
					等待客户端应用程序在指定秒数内处于静默状态</p>
				<p>
					TE_wait_sync</p>
				<p>
					等待系统从 X-SYSTEM 或输入禁止模式返回</p>
				<p>
					TE_wait_text</p>
				<p>
					等待字符串出现在指定位置</p>
				<p>
					TE_wait_sync_transaction</p>
				<p>
					记录系统在最近的 X SYSTEM 模式下保持的时间</p>
				<p>
					&nbsp;</p>
				<p>
					WEB函数列表：</p>
				<p>
					web_custom_request</p>
				<p>
					允许您使用 HTTP 支持的任何方法来创建自定义 HTTP 请求</p>
				<p>
					web_image</p>
				<p>
					在定义的图像上模拟鼠标单击</p>
				<p>
					web_link</p>
				<p>
					在定义的文本链接上模拟鼠标单击</p>
				<p>
					web_submit_data</p>
				<p>
					执行&ldquo;无条件&rdquo;或&ldquo;无上下文&rdquo;的表单</p>
				<p>
					web_submit_form</p>
				<p>
					模拟表单的提交</p>
				<p>
					web_url</p>
				<p>
					加载由&ldquo;URL&rdquo;属性指定的 URL</p>
				<p>
					web_set_certificate</p>
				<p>
					使 Vuser 使用在 Internet Explorer 注册表中列出的特定证书</p>
				<p>
					web_set_certificate_ex</p>
				<p>
					指定证书和密钥文件的位置和格式信息</p>
				<p>
					web_set_user</p>
				<p>
					指定 Web <STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>的登录字符串和密码，用于 Web 服务器上已验证用户身份的区域</p>
				<p>
					web_cache_cleanup</p>
				<p>
					清除缓存模拟程序的内容</p>
				<p>
					web_find</p>
				<p>
					在 HTML 页内搜索指定的文本字符串</p>
				<p>
					web_global_verification</p>
				<p>
					在所有后面的 HTTP 请求中搜索文本字符串</p>
				<p>
					web_image_check</p>
				<p>
					验证指定的图像是否存在于 HTML页内</p>
				<p>
					web_reg_find</p>
				<p>
					在后面的 HTTP 请求中注册对 HTML源或原始缓冲区中文本字符串的搜索</p>
				<p>
					web_disable_keep_alive</p>
				<p>
					禁用 Keep-Alive HTTP 连接</p>
				<p>
					web_enable_keep_alive</p>
				<p>
					启用 Keep-Alive HTTP 连接</p>
				<p>
					web_set_connections_limit</p>
				<p>
					设置 Vuser 在运行脚本时可以同时打开连接的最大数目</p>
				<p>
					web_concurrent_end</p>
				<p>
					标记并发组的结束</p>
				<p>
					web_concurrent_start</p>
				<p>
					标记并发组的开始</p>
				<p>
					web_add_cookie</p>
				<p>
					添加新的 Cookie 或修改现有的 Cookie</p>
				<p>
					web_cleanup_cookies</p>
				<p>
					删除当前由 Vuser 存储的所有 Cookie</p>
				<p>
					web_remove_cookie</p>
				<p>
					删除指定的 Cookie</p>
				<p>
					web_create_html_param</p>
				<p>
					将 HTML 页上的动态信息保存到参数中。（LR 6.5 及更低版本）</p>
				<p>
					web_create_html_param_ex</p>
				<p>
					基于包含在 HTML 页内的动态信息创建参数（使用嵌入边界）（LR 6.5 及更低版本）。</p>
				<p>
					web_reg_save_param</p>
				<p>
					基于包含在 HTML 页内的动态信息创建参数（不使用嵌入边界）</p>
				<p>
					web_set_max_html_param_len</p>
				<p>
					设置已检索的动态 HTML 信息的最大长度</p>
				<p>
					web_add_filter</p>
				<p>
					设置在<STRONG><A href="http://www.ltesting.net/ceshi/down" target="_blank" >下载</A></STRONG>时包括或排除 URL 的条件</p>
				<p>
					web_add_auto_filter</p>
				<p>
					设置在下载时包括或排除 URL 的条件</p>
				<p>
					web_remove_auto_filter</p>
				<p>
					禁用对下载内容的筛选</p>
				<p>
					web_add_auto_header</p>
				<p>
					向所有后面的 HTTP 请求中添加自定义标头</p>
				<p>
					web_add_header</p>
				<p>
					向下一个 HTTP 请求中添加自定义标头</p>
				<p>
					web_cleanup_auto_headers</p>
				<p>
					停止向后面的 HTTP 请求中添加自定义标头</p>
				<p>
					web_remove_auto_header</p>
				<p>
					停止向后面的 HTTP 请求中添加特定的标头</p>
				<p>
					web_revert_auto_header</p>
				<p>
					停止向后面的 HTTP 请求中添加特定的标头，但是生成隐性标头</p>
				<p>
					web_save_header</p>
				<p>
					将请求和响应标头保存到变量中</p>
				<p>
					web_set_proxy</p>
				<p>
					指定将所有后面的 HTTP 请求定向到指定的代理服务器</p>
				<p>
					web_set_proxy_bypass</p>
				<p>
					指定 Vuser 直接访问（即不通过指定的代理服务器访问）的服务器列表</p>
				<p>
					web_set_proxy_bypass_local</p>
				<p>
					指定 Vuser 对于本地 (Intranet) 地址是否应该避开代理服务器</p>
				<p>
					web_set_secure_proxy</p>
				<p>
					指定将所有后面的 HTTP 请求定向到服务器</p>
				<p>
					web_set_max_retries</p>
				<p>
					设置操作步骤的最大重试次数</p>
				<p>
					web_set_timeout</p>
				<p>
					指定 Vuser 等待执行指定任务的最长时间</p>
				<p>
					web_convert_param</p>
				<p>
					将 HTML 参数转换成 URL 或纯文本</p>
				<p>
					web_get_int_property</p>
				<p>
					返回有关上一个 HTTP 请求的特定信息</p>
				<p>
					web_report_data_point</p>
				<p>
					指定数据点并将其添加到测试结果中</p>
				<p>
					web_set_option</p>
				<p>
					在非 HTML 资源的编码、重定向和下载区域中设置 Web 选项</p>
				<p>
					web_set_sockets_option</p>
				<p>
					设置套接字的选项</p>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#]]></description>
    <pubDate>Fri, 16 Dec 2011 09:34:04 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>LoadRunner</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[Loadrunner中参数设置详细分析]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2011/1216/203773.html</link>
    <description><![CDATA[<p>
	　　相信对大家会有用的，这个版本是基于7.8的。</p>
<p>
	　　做负载或者<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/xncs/" target="_blank" >压力测试</A></STRONG>时，很多人选择使用了Loadrunner<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>。该工具的基本流程是先将用户的实际操作录制成脚本，然后产生数千个虚拟用户运行脚本(虚拟用户可以分布在局域网中不同的PC机上)，最后生成相关的报告以及分析图。但是在录制脚本的过程中会遇到很多实际的问题，比如不同的用户有不同的使用数据，这就牵涉到参数的设置问题。本文就Loadrunner中参数的设置进行说明，希望对大家有所帮助。</p>
<p>
	　　在录制程序运行的过程中，VuGen(脚本生成器) 自动生成了包含录制过程中实际用到的数值的脚本。如果你企图在录制的脚本中使用不同的数值执行脚本的活动(如查询、提交等等)，那么你必须用参数值取代录制的数值。这个过程称为参数化脚本。</p>
<p>
	　　本文主要包括如下内容：理解参数的局限性、建立参数、定义参数的属性、理解参数的类型、为局部数据类型设置参数的属性、为数据文件设置参数的属性、从已经存在的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>中引入数据。</p>
<p>
	　　除了GUI，以下的内容适合于各种类型的用户脚本。</p>
<p>
	　　一、关于参数的定义</p>
<p>
	　　在你录制程序运行的过程中，脚本生成器自动生成由函数组成的用户脚本。函数中参数的值就是在录制过程中输入的实际值。</p>
<p>
	　　例如，你录制了一个Web应用程序的脚本。脚本生成器生成了一个声明，该声明搜索名称为&ldquo;UNIX&rdquo;的图书的数据库。当你用多个虚拟用户和迭代回放脚本时，也许你不想重复使用相同的值&ldquo;UNIX&rdquo;。那么，你就可以用参数来取代这个常量。结果就是你可以用指定的数据源的数值来取代参数值。数据源可以是一个文件，也可以是内部产生的变量。</p>
<p>
	　　用参数表示用户的脚本有两个优点：</p>
<p>
	　　① 可以使脚本的长度变短。</p>
<p>
	　　② 可以使用不同的数值来测试你的脚本。例如，如果你企图搜索不同名称的图书，你仅仅需要写提交函数一次。在回放的过程中，你可以使用不同的参数值，而不只搜索一个特定名称的值。</p>
<p>
	　　参数化包含以下两项任务：</p>
<p>
	　　① 在脚本中用参数取代常量值。</p>
<p>
	　　② 设置参数的属性以及数据源。</p>
<p>
	　　参数化仅可以用于一个函数中的参量。你不能用参数表示非函数参数的字符串。另外，不是所有的函数都可以参数化的。</p>
<p>
	　　二、参数的创建</p>
<p>
	　　可以指定名称和类型来创建参数。不存在对脚本中参数个数的限制。在Web程序的用户脚本中，你可以使用如下过程在基于文本的脚本视图中创建参数。或者，也可以在基于图标的树形视图中创建参数。</p>
<p>
	　　在基于文本的脚本视图中创建一个参数：</p>
<p>
	　　将光标定位在要参数化的字符上，点击右键。打开弹出菜单。</p>
<p>
	　　在弹出菜单中，选择&ldquo;Replace with a Parameter&rdquo;。选择或者创建参数的对话框弹出。</p>
<p>
	　　在&ldquo;Parameter name&rdquo;中输入参数的名称，或者选择一个在参数列表中已经存在的参数。</p>
<p>
	　　在&ldquo;Parameter type&rdquo;下拉列表中选择参数类型。</p>
<p>
	　　点击&ldquo;OK&rdquo;，关闭该对话框。脚本生成器便会用参数中的值来取代脚本中被参数化的字符，参数用一对&ldquo;{}&rdquo;括住。</p>
<p>
	　　注意：在参数化CORBA或者General-<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcskfyy/java/" target="_blank" >Java</A></STRONG> 用户脚本的时候，必须参数化整个字符串，而不是其中的部分。另外注意：除了Web或者WAP，缺省的参数括号对于任何脚本都是 &ldquo;{}&rdquo;。你可以在&ldquo;General Options&rdquo;对话框中的&ldquo;Parameterization&rdquo;标签(Tools&gt;General Options)中定义参数括号种类。</p>
<p>
	　　用同样的参数替换字符的其余情况，选中参数，点击右键，弹出菜单。从弹出的菜单中，选择&ldquo;Replace More O<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>urrences&rdquo;。搜索和替换对话框弹出。&ldquo;Find What&rdquo;中显示了你企图替换的值。&ldquo;Replace With&rdquo;中显示了括号中参数的名称。选择适当的检验框来匹配整个字符或者大小写。如果要搜索规则的表达式(.，!，?等等)，选中&ldquo;Regular Expression&rdquo;检验框，然后点击&ldquo;Replace&rdquo;或者&ldquo;Replace All&rdquo;。</p>
<p>
	　　注意：小心使用&ldquo;Replace All&rdquo;，尤其替换数字字符串的时候。脚本生成器将会替换字符出现的所有情况。</p>
<p>
	　　如果想用以前定义过的参数来替换常量字符串的话，选中该字符串，点击右键，然后选择&ldquo;Use Existing Parameter&rdquo;，子菜单&ldquo;Use Existing Parameters&rdquo;弹出。从子菜单&ldquo;Use Existing Parameters&rdquo;选择参数，或者用&ldquo;Select from Parameter List&rdquo;来打开参数列表对话框。</p>
<p>
	　　注意：如果用以前定义过的参数来替换常量字符串的话，那么，使用&ldquo;Parameter List&rdquo;非常方便。同时，还可以查看和修改该参数的属性。</p>
<p>
	　　对于已经用参数替换过的地方，如果想取回原来的值，那么，就在参数上点击右键，然后选择&ldquo;Restore Original value&rdquo;。</p>
<p>
	　　在Web用户脚本的树形视图中创建参数：</p>
<p>
	　　将光标定位在企图参数化的地方，点击右键，从弹出的菜单中选择&ldquo;Properties&rdquo;。则相关的属性对话框打开。</p>
<p>
	　　点击在要参数化的参量的旁边的&ldquo;ABC&rdquo;形状的图标。&ldquo;Select or Create Parameter&rdquo;对话框打开。</p>
<p>
	　　在&ldquo;Parameter name&rdquo;中输入参数的名称，或者从列表中选择一个已经存在的参数。</p>
<p>
	　　在&ldquo;Parameter type&rdquo;中输入参数的类型。</p>
<p>
	　　点击&ldquo;OK&rdquo;关闭该对话框。用户脚本生成器会用参数来替换最初的字符串常量，并用一个表格形状的图标替换&ldquo;ABC&rdquo;形状的图标。</p>
<p>
	　　要恢复参数化以前的值，点击图标，然后从弹出的菜单中选择&ldquo;Undo Parameter&rdquo;，则以前的值便会重现。</p>
<p>
	　　三、定义参数的属性</p>
<p>
	　　创建参数完成后，就可以定义其属性了。参数的属性定义就是定义在脚本执行过程中，参数使用的数据源。在Web用户脚本中，你既可以在基于文本的脚本视图中定义参数属性，也可以在基于图标的树形视图中定义参数属性。下面的过程将教你如何在基于本文的脚本视图中定义参数属性。#p#分页标题#e#</p>
<p>
	　　在基于文本的脚本视图中定义参数属性步骤：</p>
<p>
	　　在参数上点击右键，有菜单弹出。</p>
<p>
	　　在弹出的菜单中，选择&ldquo;Parameter Properties&rdquo;。参数属性对话框打开，显示和当前参数类型相关的属性。</p>
<p>
	　　输入参数的属性值。</p>
<p>
	　　点击&ldquo;Close&rdquo;关闭参数属性对话框。</p>
<p>
	　　在Web用户脚本的树形视图中定义参数的属性：</p>
<p>
	　　将关标定位在参数上，然后点击右键，选择&ldquo;Properties&rdquo;。属性对话框打开。</p>
<p>
	　　点击要定义属性的参数旁边的表格形状按钮，点击右键，选择&ldquo;Parameter Properties&rdquo;。参数属性对话框打开，和参数类型相关的属性显示出来。</p>
<p>
	　　输入参数的属性。</p>
<p>
	　　点击&ldquo;Close&rdquo;关闭参数属性对话框。</p>
<p>
	　　使用参数列表：</p>
<p>
	　　使用参数列表可以在任意时刻查看所有的参数，创建新的参数、删除参数，或者修改已经存在参数的属性。</p>
<p>
	　　点击参数列表按钮或者用&ldquo;Vuser&gt;Parameter List&rdquo;。参数列表对话框打开。</p>
<p>
	　　要创建新的参数，点击&ldquo;New&rdquo;按钮。新的参数则被添加在参数树中，该参数有一个临时的名字，你可以给它重新命名，然后回车。设置参数的类型和属性，点击&ldquo;OK&rdquo;，关闭参数列表对话框。</p>
<p>
	　　注意：不要将一个参数命名为&ldquo;unique&rdquo;，因为这个名称是用户脚本生成器本身的。用户脚本生成器创建新的参数，但是不会自动用该参数在脚本中替换任意选中的字符串。</p>
<p>
	　　要删除已有的参数，那么，要先从参数树中选择该参数，点击&ldquo;Delete&rdquo;，然后确认你的行为即可。</p>
<p>
	　　要修改已有参数，那么，要先从参数树中选择该参数，然后编辑参数的类型和属性。</p>
<p>
	　　四、理解参数的类型</p>
<p>
	　　在你定义参数属性的时候，要指定参数值的数据源。你可以指定下列数据源类型的任何一种：</p>
<p>
	　　Internal Data―― 虚拟用户内部产生的数据。</p>
<p>
	　　Data Files ――存在于文件中的数据。可能是已存在的文件或者是用脚本生成器新创建的。</p>
<p>
	　　User-Defined Functions―― 调用外部DLL函数生成的数据</p>
<p>
	　　Internal Data包括以下几种：</p>
<p>
	　　Date/Time</p>
<p>
	　　Date/Time用当前的日期/时间替换参数。要指定一个Date/Time格式，你可以从菜单列表中选择格式，或者指定你自己的格式。这个格式应该和你脚本中录制的Date/Time格式保持一致。</p>
<p>
	　　Group Name</p>
<p>
	　　Group Name 用虚拟用户组名称替换参数。在创建scenario的时候，你可以指定虚拟用户组的名称。当从用户脚本生成器运行脚本的时候，虚拟用户组名称总是None。</p>
<p>
	　　Load Generator Name</p>
<p>
	　　Load Generator Name用脚本负载生成器的名称替换参数。负载生成器是虚拟用户在运行的计算机。</p>
<p>
	　　Iteration Number</p>
<p>
	　　Iteration Number用当前的迭代数目替换参数。</p>
<p>
	　　Random Number</p>
<p>
	　　Random Number用一个随机数替换参数。通过指定最大值和最小值来设置随机数的范围。</p>
<p>
	　　Unique Number</p>
<p>
	　　Unique Number用一个唯一的数字来替换参数。你可以指定一个起始数字和一个块的大小。</p>
<p>
	　　Vuser ID</p>
<p>
	　　Vuser ID用分配给虚拟用户的ID替换参数，ID是由Loadrunner的控制器在scenario运行时生成的。如果你从脚本生成器运行脚本的话，虚拟用户的ID总是-1。</p>
<p>
	　　五、数据文件</p>
<p>
	　　数据文件包含着脚本执行过程中虚拟用户访问的数据。局部和全局文件中都可以存储数据。可以指定现有的ASCII文件、用脚本生成器创建一个新的文件或者引入一个数据库。在参数有很多已知值的时候数据文件非常有用。数据文件中的数据是以表的形式存储的。一个文件中可以包含很多参数值。每一列包含一个参数的数据。列之间用分隔符隔开，比如说，用逗号。</p>
<p>
	　　对数据文件设置参数属性</p>
<p>
	　　如果使用文件作为参数的数据源，必须指定以下内容：文件的名称和位置、包含数据的列、文件格式，包括列的分隔符、更新方法。</p>
<p>
	　　如果参数的类型是&ldquo;File&rdquo;，打开参数属性(Parameter Properties)对话框，设置文件属性如下：</p>
<p>
	　　1、在&ldquo;File path&rdquo;中输入文件的位置，或者点击&ldquo;Browse&rdquo;指定一个已有文件的位置。缺省情况下，所有新的数据文件名都是&ldquo;parameter_name.dat&rdquo;，注意，已有的数据文件的后缀必须是.dat。</p>
<p>
	　　2、点击&ldquo;Edit&rdquo;。记事本打开，里面第一行是参数的名称，第二行是参数的初始值。使用诸如逗号之类的分隔符将列隔开。对于每一新的表行开始一行新的数据。</p>
<p>
	　　注意：在没有启动记事本的情况下如果想添加列，就在参数属性对话框中点击&ldquo;Add Col&rdquo;，那么&ldquo;Add new column&rdquo;对话框就会弹出。输入新列的名称，点击&ldquo;OK&rdquo;。脚本生成器就会添加该列到表中，并显示该列的初始值。</p>
<p>
	　　3、在&ldquo;Select Column&rdquo;部分，指明包含当前参数数据的列。你可以指定列名或者列号。列号是包含你所需要数据的列的索引。列名显示在每列的第一行(row 0)。</p>
<p>
	　　4、在&ldquo;Column delimiter&rdquo;中输入列分隔符，你可以指定逗号、空格符等等。</p>
<p>
	　　5、在&ldquo;First data line&rdquo;中，在脚本执行的时候选择第一行数据使用。列标题是第0行。若从列标题后面的第一行开始的话，那就在&ldquo;First data line&rdquo;中输入1。如果没有列标题，就输入0。</p>
<p>
	　　6、在&ldquo;Select next row&rdquo;中输入更新方法，以说明虚拟用户在脚本执行的过程中如何选择表中的数据。方法可以是：连续的、随机的、唯一的、或者与其它参数表的相同行。</p>
<p>
	　　6.1、顺序(Sequential)：该方法顺序地给虚拟用户分配参数值。如果正在运行的虚拟用户访问数据表的时候，它会取到下一行中可用的数据。</p>
<p>
	　　6.2、随机(Random)：该方法在每次迭代的时候会从数据表中取随机数#p#分页标题#e#</p>
<p>
	　　6.3、使用种子取随机顺序(Use Random Sequence with Seed)：如果从Loadrunner的控制器来运行scenario，你可以指定一个种子数值用于随机顺序。每一个种子数值在测试执行的时候代表了一个随机数的顺序。无论你何时使用这个种子数值，在scenario中同样的数据顺序就被分配给虚拟用户。如果在测试执行的时候发现了一个问题并且企图使用同样的随机数序列来重复测试，那么，你就可以启动这个功能(可选项)。</p>
<p>
	　　6.4、唯一(Unique)：Unique方法分配一个唯一的有顺序的值给每个虚拟用户的参数。</p>
<p>
	　　6.5、与以前定义的参数取同一行(Same Line As <parameter></parameter>)：该方法从和以前定义过的参数中的同样的一行分配数据。你必须指定包含有该数据的列。在下拉列表中会出现定义过的所有参数列表。注意：至少其中的一个参数必须是Sequential、Random或者Unique。</p>
<p>
	　　如果数据表中有三列，三个参数定义在列表中：id1，name1和title1，如下：。</p>
<p>
	　　ID Name Title</p>
<p>
	　　132 Kim Manager</p>
<p>
	　　187 Cassie Engineer</p>
<p>
	　　189 Jane VP</p>
<p>
	　　对于参数id1，你可以指示虚拟用户使用Random方法，而为参数name1和title1就可以指定方法&ldquo;Same Line as id1&rdquo;。所以，一旦ID&ldquo;132&rdquo;被使用，那么，姓名(Name)&ldquo;Kim&rdquo;和职位(Title)&ldquo;Manager&rdquo;同时被使用。</p>
<p>
	　　7、Updta value on数据的更新方法</p>
<p>
	　　7.1、Each iteration――每次反复都要取新值</p>
<p>
	　　7.2、Each occurrence――只要发现该参数就重新取值</p>
<p>
	　　7.3、Once――在所有的反复中都使用同一个值</p>
<p>
	　　8、When out of values超出范围：(选择数据为unique时才可用到)</p>
<p>
	　　8.1、Abort Vuser――中止</p>
<p>
	　　8.2、Continue in a cyclic manner――继续循环取值</p>
<p>
	　　8.3、Continue with last value――取最后一个值</p>
<p>
	　　9、Allocate Vuser values in the Controller在控制器中分配值：(选择数据为unique时才可用到)</p>
<p>
	　　9.1、Automatically allocate block size――自动分配</p>
<p>
	　　9.2、Allocate()values for each Vuser――指定一个值</p>
<p>
	　　六、从已存在的数据库中导入数据</p>
<p>
	　　Loadrunner允许你利用参数化从已经存在的数据库中导入数据。可以使用下列两种方式之一：</p>
<p>
	　　使用Microsoft Query(要求在系统上先安装MS Query)。</p>
<p>
	　　指定数据库连接字符串和SQL语句。</p>
<p>
	　　用户脚本生成器在从数据库中导入数据的过程中提供了一个向导。在向导中，你指明如何导入数据-通过MS Query创建查询语句或者直接书写SQL语句。在导入数据以后，以.dat为后缀并作为正规的参数文件保存。要开始导入数据库中数据的过程，在参数属性对话框中点击&ldquo;Data Wizard&rdquo;，则，数据库查询向导弹出。</p>
<p>
	　　要创建新的查询</p>
<p>
	　　选择&ldquo;Create new query&rdquo;。如果需要MS Query的帮助，选择&ldquo;Show me how to use Microsoft Query&rdquo;，然后点击&ldquo;Finish&rdquo;。</p>
<p>
	　　如果你还没有安装Microsoft Query，Loadrunner会提示你这个功能不可用。在进行之前，从Microsoft Office中安装MS Query。</p>
<p>
	　　在Microsoft Query中遵循以下步骤，导入期望的表和列。</p>
<p>
	　　在完成数据的导入后，选择&ldquo;Exit and return to Virtual User Generator&rdquo;，然后点击&ldquo;Finish&rdquo;。在参数属性对话框中数据库记录以data文件的形式显示出来。</p>
<p>
	　　要在MS Query中编辑并查看数据，选择&ldquo;View data or edit in Microsoft Query&rdquo;。若要结束，则选择&ldquo;File&gt;Exit and return to Virtual User Generator&rdquo;返回到脚本生成器。</p>
<p>
	　　在&ldquo;Select Column&rdquo;部分，指定包含当前参数数据的列可以指定列号或者列名。注意：列标题默认为第0行(row 0)。</p>
<p>
	　　从&ldquo;Select next row&rdquo;列表中选择一个更新方法来告诉虚拟用户在脚本指定的过程中如何选择表中的数据。可选项是：Sequential、Random、Unique或者Same Line As。其中每一项的含义文章前面已经讲述，就不再赘述。</p>
<p>
	　　如果选择&ldquo;Advance row each iteration&rdquo;，虚拟用户在每次迭代的时候会使用新的一行的数据而不是重复同样的数据。</p>
<p>
	　　要指定数据库连接或者SQL语句</p>
<p>
	　　选择&ldquo;Specify SQL Statement&rdquo;，然后点击&ldquo;Next&rdquo;。</p>
<p>
	　　点击&ldquo;Create&rdquo;指定一个新的连接字符串。选择数据源的窗口弹出。</p>
<p>
	　　选择已有的数据源，或者点击&ldquo;New&rdquo;创建一个新的数据源。向导将提示你穿过创建ODBC数据源的过程。在完成后，连接字符串就会在连接字符串框中显示出来。</p>
<p>
	　　在SQL框中，输入或者粘贴SQL语句。</p>
<p>
	　　点击&ldquo;Finish&rdquo;继续SQL语句并导入数据。数据库记录将以data文件的形式显示在参数属性框中。</p>
<p>
	　　在&ldquo;Select Column&rdquo;部分中，指定包含当前参数数据的列。你可以指定列号或者列名。</p>
<p>
	　　从&ldquo;Select next row&rdquo;列表中选择一个更新方法来告诉虚拟用户在脚本指定的过程中如何选择表中的数据。可选项是：Sequential、Random、Unique或者Same Line As。</p>
<p>
	　　如果从Update out of values中，选择&ldquo;each iteration&rdquo;，虚拟用户在每次迭代的时候会使用新的一行的数据而不是重复同样的数据。</p>
]]></description>
    <pubDate>Fri, 16 Dec 2011 09:23:24 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>LoadRunner</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[使用LoadRunner来测试BEA TUXEDO]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2011/1216/203772.html</link>
    <description><![CDATA[<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LoadRunner</A></STRONG>&reg;是一种预测系统行为和性能的工业标准级负载<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>。它通过模拟数据以千万计用户来实施并发负载来对整个企业架构进行测试，来帮助您更快的查找和发现问题。</p>
<p>
	　　关于LoadRunner&reg;更全面的描述及使用，请参考《LoadRunner 使用手册》或<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/" target="_blank" >Mercury</A></STRONG> Interactive 公司提供的联机帮忙文档。本文旨在帮助工程师们掌握使用LoadRunner&reg;来测试BEA<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/zjj/" target="_blank" >中间件</A></STRONG>产品的方法。</p>
<p>
	　　一、如何使用LoadRunner来测试BEA TUXEDO</p>
<p>
	　　1. LoadRunner的虚拟用户</p>
<p>
	　　LoadRunner使用虚拟用户(Virtual users)来模拟实际用户对业务系统施加压力。虚拟用户在一个中央控制器(controller station)的监视下工作。如下图所示。</p>
<center>
	<img alt="" border="1" height="377" src="http://www.ltesting.net/uploads/allimg/111216/09212U913-0.gif" width="554" /></center>
<p>
	　　在做一个<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csmb/csfa/" target="_blank" >测试方案</A></STRONG>时，要做的第一件事就是创建虚拟用户执行脚本。LoadRunner提供了Virtual User Generator来录制或编辑虚拟用户脚本。</p>
<p>
	　　2. 使用Vugen创建虚拟用户执行脚本</p>
<p>
	　　A.从菜单中选择运行Virtual User Generator：</p>
<center>
	<img alt="" border="1" height="359" src="http://www.ltesting.net/uploads/allimg/111216/09212R4A-1.gif" width="425" /></center>
<p>
	　　B.创建一个单协议脚本，选择协议类型为&quot;Tuxedo 7&quot;</p>
<center>
	<img alt="" border="1" height="405" src="http://www.ltesting.net/uploads/allimg/111216/09212VR0-2.gif" width="550" /></center>
<p>
	　　C.选择工具条中的&quot;</p>
<center>
	<img alt="" border="1" height="22" src="http://www.ltesting.net/uploads/allimg/111216/09212R4V-3.gif" width="104" /></center>
<p>
	　　&quot;来录制一个脚本，在弹出的窗口中输入Tuxedo客户机程序的可执行文件名(SimpApp.exe)，并选择&quot;Record into Action&quot;为Action。如下图所示：</p>
<center>
	<img alt="" border="1" height="225" src="http://www.ltesting.net/uploads/allimg/111216/09212S328-4.gif" width="444" /></center>
<p>
	　　点击&quot;OK&quot;开始录制脚本，这时Vugen就会启动Simpapp.exe，如下图所示，输入WSNADDR，输入字符串(Tuxedo is powerful!)之后，点击TOUPPER，TUXEDO<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>完成请求后把输出字符串(TUXEDO IS POWERFUL!)写到&quot;Output string&quot;中，点击停止录制按钮。</p>
<center>
	<img alt="" border="1" height="172" src="http://www.ltesting.net/uploads/allimg/111216/09212S4N-5.gif" width="286" /></center>
<p>
	　　D.编辑Vuser脚本。我们在C中做的所有操作都被录了下来，记录到一个脚本文件中，其内容如下，我们把它存为simpapp。</p>
<center>
	<img alt="" border="1" height="310" src="http://www.ltesting.net/uploads/allimg/111216/09212V348-6.gif" width="553" /></center>
<p>
	　　脚本内容如下：</p>
<table bgcolor="#<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>cccc" border="0" cellpadding="0" cellspacing="5" class="content" width="80%">
	<tbody>
		<tr>
			<td>
				/* This file is generated by LoadRunner. You may edit it carefully! */<br />
				#include &quot;<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >lr</A></STRONG>t.h&quot;<br />
				#include &quot;replay.vdf&quot;
				<p>
					Actions()<br />
					{<br />
					lrt_tuxputenv(&quot;WSNADDR=//172.22.32.25:7110&quot;);</p>
				<p>
					lr_think_time(3);<br />
					tpresult_int = lrt_tpinitialize(<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LR</A></STRONG>T_END_OF_PARMS);<br />
					lrt_abort_on_error();<br />
					data_0 = lrt_tpalloc(&quot;STRING&quot;, &quot;&quot;, 1);<br />
					<br />
					/* Request STRING buffer 1 */<br />
					lrt_strcpy(data_0, sbuf_1);<br />
					data_1 = lrt_tpalloc(&quot;STRING&quot;, &quot;&quot;, 1);<br />
					tpresult_int = lrt_tpcall(&quot;TOUPPER&quot;,<br />
					data_0,<br />
					0,<br />
					&amp;data_1,<br />
					&amp;olen,<br />
					0);<br />
					/* Reply STRING buffer 1 */<br />
					lrt_abort_on_error();<br />
					<br />
					lrt_tpfree(data_0);<br />
					lrt_tpfree(data_1);<br />
					lrt_tpterm();</p>
				<p>
					return 0;<br />
					}</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　代码中加粗的函数是LoadRunner对TUXEDO函的二次包装。</p>
<p>
	　　E.点击工具栏中的&quot;</p>
<center>
	<img alt="" border="1" height="27" src="http://www.ltesting.net/uploads/allimg/111216/09212W504-7.gif" width="24" /></center>
<p>
	　　&quot;按钮来执行我们刚才录制的脚本，确保执行无误。</p>
<p>
	　　3. 使用控制器(Controller)来调度虚拟用户</p>
<p>
	　　A.从菜单中选择运行Controller：</p>
<center>
	<img alt="" border="1" height="323" src="http://www.ltesting.net/uploads/allimg/111216/09212QO4-8.gif" width="410" /></center>
<p>
	　　B.创建一个新的Scenario，选择刚才录制的脚本(simpapp)：</p>
<center>
	<img alt="" border="1" height="415" src="http://www.ltesting.net/uploads/allimg/111216/09212W0b-9.gif" width="556" /></center>
<p>
	　　点击&quot;OK&quot;，弹出Scenario调度界面，如下图所示。在&quot;Qu<STRONG><A href="http://www.ltesting.net/ceshi/open/qtkycsgj/ant/" target="_blank" >ant</A></STRONG>ity&quot;中输入100，表示使用100个虚拟用户。(虚拟用户与购买的LICENSE有关联)</p>
<center>
	<img alt="" border="1" height="403" src="http://www.ltesting.net/uploads/allimg/111216/09212VD4-10.gif" width="556" /></center>
<p>
	　　C.点击&quot;Edit Schedule&quot;来编辑压力调度。</p>
<center>
	<img alt="" border="1" height="251" src="http://www.ltesting.net/uploads/allimg/111216/09212S213-11.gif" width="556" /></center>
<center>
	<img alt="" border="1" height="533" src="http://www.ltesting.net/uploads/allimg/111216/09212W1I-12.gif" width="554" /></center>
<p>
	　　D.选择&quot;Runtime settings&quot;来作运行时设置</p>
<center>
	<img alt="" border="1" height="359" src="http://www.ltesting.net/uploads/allimg/111216/09212V204-13.gif" width="555" /></center>
<p>
	　　在Pacing的设置中，&quot;Number of Iterations&quot;用于设置Vusers的Actions被执行的次数;&quot;Start new iteration&quot;用于设置调度器在什么时机迭代执行Vusers的Actions。</p>
#p#分页标题#e#
<center>
	<img alt="" border="1" height="378" src="http://www.ltesting.net/uploads/allimg/111216/09212R457-14.gif" width="554" /></center>
<p>
	　　&quot;Think Time&quot;用于设置Vusers的反应和思考时间，以尽量做到和正常人一样来施压。&quot;Ignore think time&quot;表示忽略思考时间，这是理想状态，一般不使用。&quot;As recorded&quot;表示按照录制时的实际操作时间。&quot;Multiply recorded think time by&quot;表示Vusers的思考时间是实际录制时间的若干倍。</p>
<center>
	<img alt="" border="1" height="371" src="http://www.ltesting.net/uploads/allimg/111216/09212Q449-15.gif" width="541" /></center>
<p>
	　　在&quot;Miscellaneous&quot;中设置一些杂项，如使用进程还是使用线程等。对于TUXEDO，好象只能选进程模式。</p>
<p>
	　　E.选择&quot;Start scenario&quot;来开始本次<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/xncs/" target="_blank" >压力测试</A></STRONG>调度。</p>
<center>
	<img alt="" border="1" height="404" src="http://www.ltesting.net/uploads/allimg/111216/09212Ua4-16.gif" width="553" /></center>
<p>
	　　执行结果分析如下：</p>
<center>
	<img alt="" border="1" height="287" src="http://www.ltesting.net/uploads/allimg/111216/09212TY0-17.gif" width="565" /></center>
<p>
	　　施压时间为5分41秒，Vusers数量为100，一共完成的Actions交易数量为5625笔，平均响应时间为5.561秒，TPS为17.8</p>
<p>
	　　二、如何使用LoadRunner来测试BEA Weblogic Server</p>
<p>
	　　在本例中，我们将创建一个WebApp(toupper.war)，用于调用TUXEDO的TOUPPER服务。为了达到这个目的，需要在Weblogic Server上创建一个WTC服务器，导入TOUPPER服务，同时在Weblogic Server部分一个EJB(toupper.jar)，用于封装TOUPPER服务。在TUXEDO一端，需要配置<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/testdirector/" target="_blank" >TD</A></STRONG>OMAIN网关。</p>
<p>
	　　部署toupper.war和toupper.jar，测试toupper.war，得如下界面：</p>
<center>
	<img alt="" border="1" height="293" src="http://www.ltesting.net/uploads/allimg/111216/09212TR1-18.gif" width="556" /></center>
<p>
	　　点击&quot;TOUPPER&quot;，得如下界面：</p>
<center>
	<img alt="" border="1" height="304" src="http://www.ltesting.net/uploads/allimg/111216/09212R234-19.gif" width="549" /></center>
<p>
	　　这表明WTC、Webapp和EJB都工作正常。</p>
<p>
	　　1. 录制Weblogic Server测试脚本</p>
<p>
	　　A.在Virtual User Generator中选择创建一个新脚本，选择Single Protocol Script，选择Web(HTTP/HTML)，点击OK。</p>
<center>
	<img alt="" border="1" height="410" src="http://www.ltesting.net/uploads/allimg/111216/09212TE9-20.gif" width="554" /></center>
<p>
	　　点击&quot;</p>
<center>
	<img alt="" border="1" height="22" src="http://www.ltesting.net/uploads/allimg/111216/09212R4V-3.gif" width="104" /></center>
<p>
	　　&quot;开始录脚本，在URL中输入http://jq:7001/toupper/jsp1.jsp，点击OK。</p>
<p>
	　　执行一次TOUPPER操作，停止录制。得如下脚本：</p>
<center>
	<img alt="" border="1" height="155" src="http://www.ltesting.net/uploads/allimg/111216/09212R311-22.gif" width="447" /></center>
<center>
	<img alt="" border="1" height="365" src="http://www.ltesting.net/uploads/allimg/111216/09212Q553-23.gif" width="551" /></center>
<p>
	　　执行一次TOUPPER操作，停止录制。得如下脚本：</p>
<p>
	　　点击&quot;</p>
<center>
	<img alt="" border="1" height="27" src="http://www.ltesting.net/uploads/allimg/111216/09212W504-7.gif" width="24" /></center>
<p>
	　　&quot;，作一次运行测试，确保脚本执行无误。</p>
<p>
	　　2. 使用控制器(Controller)来调度虚拟用户</p>
<p>
	　　使用与TUXEDO一样的调度策略，创建100个虚拟用户，以线程的方式来给</p>
<center>
	<img alt="" border="1" height="404" src="http://www.ltesting.net/uploads/allimg/111216/09212S038-25.gif" width="554" /></center>
<p>
	　　http://jq:7001/toupper/jsp1.jsp链接加压，一共处理了5429笔交易，TPS为17.8。平均每秒点击次数为29.34次，测试报表如下：</p>
<center>
	<img alt="" border="1" height="454" src="http://www.ltesting.net/uploads/allimg/111216/09212Q419-26.gif" width="566" /></center>
]]></description>
    <pubDate>Wed, 28 Dec 2011 16:28:29 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111216/09212U913-0-lp.gif</subImagePath>
     <category>LoadRunner</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[Loadrunner性能测试一个实例]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2011/1216/203771.html</link>
    <description><![CDATA[<p>
	　　随着测试越来越重要，其中的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/xncs/" target="_blank" >性能测试</A></STRONG>也受到越来越多的关注。比较普遍的性能<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>是Loadrunner7.51，但是很多人对此性能工具不是很熟悉。本人也是总结心得体会，将做过的性能测试实例以饷大家，希望对各位做测试的朋友有所帮助。</p>
<p>
	　　该方案是针对某公司试题库的性能测试。该试题库是用来对公司内部员工培训结果的一个考核。试题库在公司内部web<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>上，假设开设50个账号和密码可供50个考生同时参加考试。要求，每台机器只能由一个用户使用，每个用户只能使用各自不同的账号登录考试系统，做完题目后，要求提交考试结果，若在制定的时间内不提交，则系统强制提交考试结果。</p>
<p>
	　　但是，一般测试部门不可能有50台机器同时进行测试的。所以，可以借Loadrunner7.51模拟IP地址，修改脚本来协助测试。但是，为了保证测试结果，建议搜罗公司中所有可用的机器进行复测，因为有时候是不可以完全信赖工具的。</p>
<p>
	　　现场<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/" target="_blank" >测试环境</A></STRONG></p>
<p>
	　　硬件：50台PC机，Web服务器</p>
<p>
	　　软件：Loadrunner7.0，Win2000，IE5.0和IE6.0</p>
<p>
	　　人员：质控部2人，执行现场测试</p>
<p>
	　　项目部22人，提供现场环境</p>
<p>
	　　技术部各1人，提供技术支持</p>
<p>
	　　测试要求</p>
<p>
	　　50个用户拥有独立IP地址，不同的用户及密码登录，试题完成后各自同时提交。</p>
<p>
	　　测试内容</p>
<p>
	　　50个用户以不同的用户名和密码登录试题库。试题完成后，提交考试结果。测试考试结果是否能正常提交以及正确评分。</p>
<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csmb/csfa/" target="_blank" >测试方案</A></STRONG></p>
<p>
	　　1、 完全20台实际的PC机进行现场测试。</p>
<p>
	　　(1) 准备工作，并做计划。第一轮测试执行三遍，设定用户考试内容全部同时提交，第一遍全部使用IE5.0，第二遍10台使用IE5.0，10台使用IE6.0，第三遍全部使用IE6.0</p>
<p>
	　　(2) At 9：00 ，20个用户同时登录系统</p>
<p>
	　　(3) At 9：05 ，20个用户同时全部提交</p>
<p>
	　　(4) 分别记录第一轮测试(三遍)的结果</p>
<p>
	　　(5) 第二轮测试准备工作，设定15个用户考试内容同时提交，另外5个用户延时5分钟提交，全部使用IE5.0</p>
<p>
	　　(6) At 9：15 ，20个用户同时登录系统</p>
<p>
	　　(7) At 9：20 ，15个用户同时提交</p>
<p>
	　　(8) At 9：25 ，剩余5个用户同时提交</p>
<p>
	　　(9) 记录第二轮测试结果</p>
<p>
	　　(10) 第三轮测试准备工作，设定15个用户考试内容同时提交，另外5个用户延时5分钟提交，全部使用IE6.0</p>
<p>
	　　(11) At 9：15 ，20个用户同时登录系统</p>
<p>
	　　(12) At 9：20 ，15个用户同时提交</p>
<p>
	　　(13) At 9：25 ，剩余5个用户同时提交</p>
<p>
	　　(14) 记录第三轮测试结果</p>
<p>
	　　(15) 第四轮测试准备工作，设定15个用户考试内容同时提交，另外5个用户延时5分钟提交，正常提交用户使用IE5.0，延时提交用户使用IE6.0</p>
<p>
	　　(16) At 9：15 ，20个用户同时登录系统</p>
<p>
	　　(17) At 9：20 ，15个用户同时提交</p>
<p>
	　　(18) At 9：25 ，剩余5个用户同时提交</p>
<p>
	　　(19) 记录第四轮测试结果</p>
<p>
	　　(20) 第五轮测试准备工作，设定15个用户考试内容同时提交，另外5个用户延时5分钟提交，正常提交用户使用IE6.0，延时提交用户使用IE5.0</p>
<p>
	　　(21) At 9：15 ，20个用户同时登录系统</p>
<p>
	　　(22) At 9：20 ，15个用户同时提交</p>
<p>
	　　(23) At 9：25 ，剩余5个用户同时提交</p>
<p>
	　　(24) 记录第五轮测试结果</p>
<p>
	　　(25) 第六轮测试准备工作，设定15个用户考试内容同时提交，另外5个用户延时5分钟提交，正常提交用户其中10个使用IE5.0，5个使用IE6.0，延时提交用户使用IE5.0</p>
<p>
	　　(26) At 9：15 ，20个用户同时登录系统</p>
<p>
	　　(27) At 9：20 ，15个用户同时提交</p>
<p>
	　　(28) At 9：25 ，剩余5个用户同时提交</p>
<p>
	　　(29) 记录第六轮测试结果</p>
<p>
	　　(30) 第七轮测试准备工作，设定10个用户考试内容同时提交，另外10个用户分两次分别延时5分钟、15提交</p>
<p>
	　　(31) At 9：35 ，20个用户同时登录系统</p>
<p>
	　　(32) At 9：40 ，10个用户同时提交</p>
<p>
	　　(33) At 9：45 ，剩余的其中5个用户同时提交</p>
<p>
	　　(34) At 9：55 ，剩余的5个用户同时提交</p>
<p>
	　　(35) 记录第七轮测试结果，参见第二轮测试-第六轮测试过程分别对IE5.0和IE6.0的情况进行测试</p>
<p>
	　　(36) 第八轮测试准备工作，设定其中10个用户不提交，由系统强行提交</p>
<p>
	　　(37) At 10：10 ，20个用户同时登录系统</p>
<p>
	　　(38) At 10：15 ，10个用户同时提交</p>
<p>
	　　(39) 其余用户的内容由系统强行提交</p>
<p>
	　　(40) 记录第八轮测试结果，参见第二轮测试-第六轮测试过程分别对IE5.0和IE6.0的情况进行测试</p>
<p>
	　　(41) 第九轮测试准备工作，设定其中10个用户同时提交，5个用户延时5分钟提交，其余用户由系统强行提交</p>
<p>
	　　(42) At 10：25 ，20个用户同时登录系统</p>
<p>
	　　(43) At 10：30 ，10个用户同时提交</p>
<p>
	　　(44) At 10：35 ，剩余的其中5个用户同时提交</p>
<p>
	　　(45) 剩余5个用户系统强制提交</p>
<p>
	　　(46) 记录第九轮测试结果，参见第二轮测试-第六轮测试过程分别对IE5.0和IE6.0的情况进行测试</p>
<p>
	　　2、 模拟20个用户进行测试。其中，10台是PC机，另外10台机器的IP地址是Loadrunner模拟出来的。</p>
<p>
	　　(1) 在10台实际的PC机中抽取其中一台虚拟10个IP地址，包括自身的IP地址，该机器上共11个IP地址，这11个IP地址只能全部使用IE5.0或者全部使用IE6.0</p>
<p>
	　　(2) 其余9台实际的PC机分别由9个人操作，另外一台机器由一位质控部人员操作</p>
<p>
	　　(3) 对于异常情况，延时提交和强制提交全部由实际的机器来模拟</p>
<p>
	　　(4) 其余过程参见1</p>
<p>
	　　3、 模拟20个用户进行测试。其中，5台是PC机，另外15台机器的IP地址是用Loadrunner模拟出来的。</p>
<p>
	　　(1) 在5台实际的PC机中抽取其中一台虚拟15个IP地址，包括自身的IP地址，该机器上共16个IP地址，这16个IP地址只能全部使用IE5.0或者全部使用IE6.0#p#分页标题#e#</p>
<p>
	　　(2) 其余4台实际的PC机分别由4个人操作，另外一台机器由一位质控部人员操作</p>
<p>
	　　(3) 对于异常情况，延时提交和强制提交全部由实际的机器来模拟</p>
<p>
	　　(4) 其余过程参见1</p>
<p>
	　　4、 模拟35个用户进行测试。其中，20台是PC机，另外15台机器的IP地址是用Loadrunner模拟出来的。</p>
<p>
	　　(1) 在20台实际的PC机中抽取其中两台分别虚拟7个、8个IP地址，这17个IP地址只能全部使用IE5.0或者全部使用IE6.0</p>
<p>
	　　(2) 其余18台实际的PC机分别由18个人操作，另外两台机器由两位质控部人员操作</p>
<p>
	　　(3) 对于异常情况，延时提交和强制提交全部由实际的机器来模拟</p>
<p>
	　　(4) 其余过程参见1</p>
<p>
	　　5、 模拟50台用户进行测试。其中，20台是PC机，另外30台机器的IP地址是用分别用两台实际的PC机模拟出来的。记录测试结果。</p>
<p>
	　　(1) 在20台实际的PC机中抽取其中两台分别虚拟15个IP地址，这32个IP地址只能全部使用IE5.0或者全部使用IE6.0</p>
<p>
	　　(2) 其余18台实际的PC机分别由18个人操作，另外两台机器由两位质控部人员操作</p>
<p>
	　　(3) 对于异常情况，延时提交和强制提交全部由实际的机器来模拟</p>
<p>
	　　(4) 其余过程参见1</p>
<p>
	　　6、 对5中所述情况重复测试两次。</p>
<p>
	　　7、 为了保证结果的正确性，完全50台实际的PC机进行现场测试。过程参见1</p>
<p>
	　　测试过程</p>
<p>
	　　注：该测试过程针对虚拟IP地址情况。</p>
<p>
	　　1、 一台PC机上创建15个虚拟的IP地址。首先，启动IP Wizard，如下：开始程序-&gt;Loadrunner-&gt;Tools-&gt;IP Wizard</p>
<p>
	　　点击&ldquo;Add&rdquo;，添加你计划虚拟的IP地址。但是注意不能添加已经被占用的IP地址。</p>
<p>
	　　2、 启动Virtual User Generator，并录制脚本，由于50个用户的账号和密码各不相同，所以，要修改脚本，设置参数。我是录制了一个脚本，复制了49份，在每个脚本中手工修改了各自不同的地方。</p>
<p>
	　　3、 启动Loadrunner Controller，先将刚才保存的脚本添加进来。然后点击&ldquo;Scenario&rdquo;菜单，激活其中的&ldquo;Enable IP Spoofer&rdquo;。</p>
<p>
	　　4、 点击屏幕右方的&ldquo;Generators&rdquo;，添加已经建立的IP，然后connect建立连接。</p>
<p>
	　　5、对连接起来的不同用户(IP地址)分配不同的脚本，在Controller中的&ldquo;design&rdquo;中，点击&ldquo;Load Generators&rdquo;其中，每个脚本有一个用户执行。</p>
<p>
	　　6、 执行Scenario。</p>
]]></description>
    <pubDate>Fri, 16 Dec 2011 09:16:09 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>LoadRunner</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[QTP对象库的管理与合并]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/2011/1215/203770.html</link>
    <description><![CDATA[<table align="center" border="0" cellpadding="0" cellspacing="0" width="86%">
	<tbody>
		<tr>
			<td class="content" valign="top">
				<p class="content">
					对于使用<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/" target="_blank" >QTP</A></STRONG>做为自动化<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>的测试项目来说，其对象库的管理在整个<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/zdcs/" target="_blank" >自动化测试</A></STRONG>过程中，占有非常重要的地位。特别是对于一个大型的应用系统，其界面的对象多而杂，一个统一、有序的对象仓库非常有利于脚本的快速<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>，以及团队成员间的协作。<br />
					<br />
					　然而，在实际使用中，虽然可以改变对象库中对象节点添加时的位置（如Tools-&gt;Options-&gt;Web-&gt;Page/Frame Options），但是在多人操作过程中，难免会出现偏离原始设计思路的地方。这个就需要对象库管理员进行修改纠正和修改。</p>
				<p class="content">
					在Object Repository中，可以修改对象节点的名称，维护对象的属性，保存对象库，但并没有移动对象节点的功能。还好QTP提供了一个Reporsitories Merge Utility，可以实现对象库的合并功能。</p>
				<p class="content">
					下面我们就来尝试使用Reporsitories Merge Utility来改变对象节点的位置。</p>
				<p class="content">
					首先，复制三个源对象库，一个作为目标对象库，两个作为源对象库。<br />
					<br />
					　然后，打开Reporsitories Merge Utility，如图</p>
				<p class="content">
					<img height="725" src="/uploads/allimg/111215/09492HS9-0.gif" width="700" /></p>
				<p class="content">
					选择好对象库所在的路径后，点击红框中的按钮，进入手动合并对象库页面。</p>
				<p class="content">
					<img height="616" src="/uploads/allimg/111215/09492H526-1.gif" width="700" /><br />
					<br />
					　从左边的对象树上选择要移动的节点，目标的节点则默认是根节点。如果要移动到其他的节点下面，还需要在右边对象树上选择该节点才行。最后是点按钮Add top Level或者Add child，就将对象节点连同他的子节点一同添加到目标对象树上。也就是实现了我们的目标，把对象节点移位。</p>
				<p class="content">
					好了，检查一下你需要的所有的对象是否都已经成功添加。</p>
				<p class="content">
					注意一点，当遇到对象的descrīption完全相同的情况，即使节点的名字不同，QTP也会当作是相同的节点，不进行多次添加，即使在源对象树上是两个节点，添加到目标对象树上的仍然是一个节点。</p>
				<p class="content">
					对于两边都有的父节点，可以对其进行Merge操作，合并子节点。操作同增加节点，不同的是要选中左右两边名字相同的节点，这样merge按钮才会出来。</p>
				<p class="content">
					在合并的过程中，如果遇到对象的描述完全相同，会自动跳出Resolve Conflict页面，来帮助解决冲突。</p>
				<p class="content">
					<img height="613" src="/uploads/allimg/111215/09492G243-2.gif" width="700" /><br />
					　这里提供了4种选项，但是好像不管选择哪一种，QTP都不会把它认为描述相同的对象添加两次（这些对象都是在Object Repository中Add的)。</p>
				<p class="content">
					个人感觉，Reporsitories Merge Utility针对于有多个节点相同的两个对象库，进行合并操作的时候不是很好用。我在做测试的时候，有两个节点没有自动添加进来，需要手动添加。而且出现了上述的对象描述相同但名字不同的情况，也是没有办法添加进来的。不过对于其他情况，还是可以做到添加新对象到统一的对象库中，把多人开发的结果集中到一起管理。</p>
			</td>
		</tr>
	</tbody>
</table>
&nbsp;]]></description>
    <pubDate>Thu, 15 Dec 2011 09:46:05 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111215/09492HS9-0-lp.gif</subImagePath>
     <category>QuickTestPro</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[揭秘QTP之Reporter对象]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/2011/1215/203769.html</link>
    <description><![CDATA[<p>
	　　本文介绍了Reporter对象的几个鲜为人知的方法，利用LogEvent、SetContext、UnSetContext方法，可以实现日志的结构化、层次化写入，让你的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/" target="_blank" >QTP</A></STRONG>测试报告看起来更加有条理、分类清晰。</p>
<p>
	　　QTP的日志其实有很多的缺点，尤其是当你的脚本依赖函数来执行的时候，因为函数执行时调用Reporter对象来写日志，只会顺序从上到下、扁平、不分类地写下去，如图1所示。</p>
<center>
	<img alt="" border="1" height="207" src="/uploads/allimg/111215/0945225255-0.jpg" width="428" /></center>
<p>
	　　图1 函数执行时调用Reporter对象写日志的问题</p>
<p>
	　　而不像在Action中写日志一样，按一定的层次关系来写日志(例如根据调用的关系嵌套)。那么如何让函数调用Reporter对象来写日志时也具备一定的层次关系，让日志展现更加灵活、分类清晰呢?其实QTP的Report对象中暗藏了不少可利用的属性和方法。</p>
<p>
	　　Report对象的&ldquo;私家珍藏&rdquo;</p>
<p>
	　　在关键字视图通过InterlliSense查看QTP的Report对象时(如图2所示)，可发现仅有3个属性、1个方法可用，其中最常用的是ReportEvent方法。</p>
<center>
	<img alt="" border="1" height="124" src="/uploads/allimg/111215/0945221027-1.jpg" width="264" /></center>
<p>
	　　图2 Reporter对象的公开方法和属性</p>
<p>
	　　而实际上，QTP的Report对象还有其他的方法可用，这些方法并没有对外公开，例如可用LogEvent方法来在日志树中写入一个节点：</p>
<p>
	　　&#39; 使用Reporter对象的LogEvent写入新节点</p>
<p>
	　　intContext = Reporter.LogEvent(&quot;User&quot;, dicMetaDescription, Reporter.GetContext)</p>
<p>
	　　用SetContext方法把某个节点作为父节点，这样的话，后续写入的Log都将在这个父节点之下：</p>
<p>
	　　&#39; 调用Reporter对象的SetContext把新写入的节点作为父节点</p>
<p>
	　　Reporter.SetContext intContext</p>
<p>
	　　如果要退出该节点，返回日志树的上一层，则可调用UnSetContext方法即可，如下脚本所示：</p>
<p>
	　　&#39;调用Reporter对象的UnSetContext，返回上一层</p>
<p>
	　　Reporter.UnSetContext</p>
<p>
	　　Report对象&ldquo;解密&rdquo;</p>
<p>
	　　有了LogEvent、SetContext、UnSetContext这几个方法，我们就可以实现日志的结构化、层次化写入了，例如下面的例子所示：</p>
<p>
	　　&#39; 用一个Dictionary对象来存储节点的信息</p>
<p>
	　　Set dicMetaDescription = CreateObject(&quot;Scripting.Dictionary&quot;)</p>
<p>
	　　&#39; 设置节点的状态</p>
<p>
	　　dicMetaDescription(&quot;Status&quot;) = MicDone</p>
<p>
	　　&#39; 设置节点的名称</p>
<p>
	　　dicMetaDescription(&quot;PlainTextNodeName&quot;) = &quot;父节点&quot;</p>
<p>
	　　&#39; 设置节点的详细描述信息(可以使用HTML格式)</p>
<p>
	　　dicMetaDescription(&quot;StepHtmlInfo&quot;) = &quot;</p>
<div align="left">
	<h1>
		这是一个拥有孩子的节点</h1>
	<b>Hello!</b> How are you!.</div>
&quot;
<p>
	&nbsp;</p>
<p>
	　　&#39; 设置节点的图标</p>
<p>
	　　dicMetaDescription(&quot;DllIconIndex&quot;) = 210</p>
<p>
	　　dicMetaDescription(&quot;DllIconSelIndex&quot;) = 210</p>
<p>
	　　&#39; 节点图标从ContextManager.dll这个DLL文件中读取</p>
<p>
	　　dicMetaDescription(&quot;DllPAth&quot;) = &quot;D:\Program Files\HP\QuickTest Professional\bin\ContextManager.dll&quot;</p>
<p>
	　　&#39; 使用Reporter对象的LogEvent写入新节点</p>
<p>
	　　intContext = Reporter.LogEvent(&quot;User&quot;, dicMetaDescription, Reporter.GetContext)</p>
<p>
	　　&#39; 调用Reporter对象的SetContext把新写入的节点作为父节点</p>
<p>
	　　Reporter.SetContext intContext</p>
<p>
	　　&#39; 后续写入的Log都将在这个父节点之下</p>
<p>
	　　Reporter.ReportEvent MicPass, &quot;Step1&quot;, &quot;Step1 Pass!&quot;</p>
<p>
	　　Reporter.ReportEvent MicWarnning, &quot;Step2&quot;, &quot;Step2 Pass With Warnning!&quot;</p>
<p>
	　　Reporter.ReportEvent MicFail, &quot;Step2&quot;, &quot;Step2 Fail!&quot;</p>
<p>
	　　&#39;调用Reporter对象的UnSetContext，返回上一层</p>
<p>
	　　Reporter.UnSetContext</p>
<p>
	　　&#39; 在父节点之外写Log</p>
<p>
	　　Reporter.ReportEvent MicPass, &quot;Case2&quot;, &quot;Case2 Pass!&quot;</p>
<p>
	　　在这个例子中，我们首先用一个Dictionary对象来存储节点的信息，其中Status表示节点的状态，例如MicDone就表示完成状态;PlainTextNodeName表示节点的名称;StepHtmlInfo表示节点的详细内容，可以用HTML格式来写入;还可以用DllIconIndex、DllIconSelIndex、DllPAth这3个属性来表示节点的图标。</p>
<p>
	　　然后使用Reporter对象的LogEvent把Dictionary中存储的信息写入一个新节点，再调用Reporter对象的SetContext把新写入的节点作为父节点，这样后续写入的Log都将在这个父节点之下，最后调用Reporter对象的UnSetContext，返回上一层，这样后续写入的Log将在这个父节点之外。</p>
<p>
	　　这个例子的运行结果如图3所示。</p>
<center>
	<img alt="" border="1" height="287" src="/uploads/allimg/111215/094522NP-2.jpg" width="561" /></center>
<p>
	　　图3 脚本运行结果</p>
<p>
	　　封装成可重用的函数</p>
<p>
	　　可以把上面的代码封装成一个可重用的函数，以方便调用。方法如下：</p>
<p>
	　　(1)首先在QTP中使用&ldquo;Function Definition Generator&rdquo;来定义一个名为&ldquo;EnterNode&rdquo;的函数。如图4所示。</p>
<center>
	<img alt="" border="1" height="325" src="/uploads/allimg/111215/0945225156-3.jpg" width="248" /></center>
<p>
	　　图4 定义函数EnterNode</p>
<p>
	　　该函数实现的是把日志写入某个节点下，输入参数为NodeName(节点的名称)，NodeContent(节点的描述信息)。</p>
<p>
	　　函数的脚本如下：#p#分页标题#e#</p>
<p>
	　　&#39;@Description 指定把日志写入节点下</p>
<p>
	　　Public Function EnterNode(ByRef NodeName, ByRef NodeContent)</p>
<p>
	　　&#39; 用一个Dictionary对象来存储节点的信息</p>
<p>
	　　Set dicMetaDescription = CreateObject(&quot;Scripting.Dictionary&quot;)</p>
<p>
	　　&#39; 设置节点的状态</p>
<p>
	　　dicMetaDescription(&quot;Status&quot;) = MicDone</p>
<p>
	　　&#39; 设置节点的名称</p>
<p>
	　　dicMetaDescription(&quot;PlainTextNodeName&quot;) = NodeName</p>
<p>
	　　&#39; 设置节点的详细描述信息(可以使用HTML格式)</p>
<p>
	　　dicMetaDescription(&quot;StepHtmlInfo&quot;) = NodeContent</p>
<p>
	　　&#39; 设置节点的图标</p>
<p>
	　　dicMetaDescription(&quot;DllIconIndex&quot;) = 210</p>
<p>
	　　dicMetaDescription(&quot;DllIconSelIndex&quot;) = 210</p>
<p>
	　　&#39; 节点图标从ContextManager.dll这个DLL文件中读取</p>
<p>
	　　dicMetaDescription(&quot;DllPAth&quot;) = &quot;D:\Program Files\HP\QuickTest Professional\bin\ContextManager.dll&quot;</p>
<p>
	　　&#39; 使用Reporter对象的LogEvent写入新节点</p>
<p>
	　　intContext = Reporter.LogEvent(&quot;User&quot;, dicMetaDescription, Reporter.GetContext)</p>
<p>
	　　&#39; 调用Reporter对象的SetContext把新写入的节点作为父节点</p>
<p>
	　　Reporter.SetContext intContext</p>
<p>
	　　End Function</p>
<p>
	　　(2)然后再定义一个与&ldquo;EnterNode&rdquo;相应的函数&ldquo;ExitNode&rdquo;，如图5所示：</p>
<center>
	<img alt="" border="1" height="325" src="/uploads/allimg/111215/0945225045-4.jpg" width="248" /></center>
<p>
	　　图5 定义函数ExitNode</p>
<p>
	　　ExitNode函数用于退出当前日志节点，需要与EnterNode配对使用，函数的脚本如下所示：</p>
<p>
	　　&#39;@Description 退出当前日志节点(与EnterNode配对使用)</p>
<p>
	　　Public Function ExitNode</p>
<p>
	　　&#39;调用Reporter对象的UnSetContext，返回上一层</p>
<p>
	　　Reporter.UnSetContext</p>
<p>
	　　End Function</p>
<p>
	　　(3)有了EnterNode和ExitNode函数后，我们就可以像下面的例子一样使用EnterNode和ExitNode，实现日志记录的结构化、层次化写入：</p>
<p>
	　　&#39; 进入节点</p>
<p>
	　　EnterNode &quot;父节点&quot;,&quot;</p>
<div align="left">
	<h1>
		这是一个拥有孩子的节点</h1>
	<b>Hello!</b> How are you!.</div>
&quot;
<p>
	&nbsp;</p>
<p>
	　　&#39; 在节点内写Log</p>
<p>
	　　Reporter.ReportEvent MicPass, &quot;Step1&quot;, &quot;Step1 Pass!&quot;</p>
<p>
	　　Reporter.ReportEvent MicWarnning, &quot;Step2&quot;, &quot;Step2 Pass With Warnning!&quot;</p>
<p>
	　　Reporter.ReportEvent MicFail, &quot;Step2&quot;, &quot;Step2 Fail!&quot;</p>
<p>
	　　&#39; 退出节点</p>
<p>
	　　ExitNode</p>
<p>
	　　&#39; 在节点之外写Log</p>
<p>
	　　Reporter.ReportEvent MicPass, &quot;Case2&quot;, &quot;Case2 Pass!&quot;</p>
<p>
	　　该脚本首先调用EnterNode，创建一个&quot;父节点&quot;，并自动进入该节点的层次下，然后使用普通的ReportEvent方法写日志，当需要退出该&quot;父节点&quot;时，就调用一下ExitNode，则后续的日志都在该节点之外写。</p>
<p>
	　　小结</p>
<p>
	　　本文介绍了Reporter对象的几个鲜为人知的方法，利用LogEvent、SetContext、UnSetContext这几个方法，可以实现日志的结构化、层次化写入，让你的QTP测试报告看起来更加有条理、分类清晰。</p>
<p>
	　　不知道为什么QTP的帮助文档中没有列出这几个有用的方法，但是不管怎样，在我们揭开了Reporter对象的这些隐藏的方法后，我们就可以充分利用它们为我们服务，让我们的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/zdcs/" target="_blank" >自动化测试</A></STRONG>脚本更加强大。</p>
]]></description>
    <pubDate>Thu, 15 Dec 2011 09:43:47 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111215/0945225255-0-lp.jpg</subImagePath>
     <category>QuickTestPro</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[QTP应用模式设计]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/2011/1215/203768.html</link>
    <description><![CDATA[<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/zdcs/" target="_blank" >自动化测试</A></STRONG>并不只是利用自动化<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>进行录制回放操作。虽然基本是每一个自动化测试工具都必须提供的功能，但如果只是这么应用，从严格意义上来说，这并不能算是自动化测试。最多只能说是实现了一定的自动化操作。因为这时自动化脚本都是写死的，自动化测试使用的数据也是写死的，没有灵活性可言，也没有对脚本进行容错性处理，脚本基本是运行不完。且也没有添加测试验证，不能验证执行结果是否符合预期的结果。</p>
<p>
	　　早期使用<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/" target="_blank" >QTP</A></STRONG>，可以利用QTP提供的功能实现三层架构：测试数据，测试对象和测试脚本三个结构的分离。QTP提供DataTable对象来保存测试数据，且也提供了把脚本中的测试数据参数化到DataTable而脚本中只引用了参数化的名称的功能，而DataTable存储的是一个Excel文档，方便修改测试数据，这样便实现了测试数据与测试脚本分离;QTP也把自动化测试中要操作的对象放到了对象库中进行管理者，实现了对对象的统一管理，也实现了测试对象与测试脚本的分离。</p>
<center>
	<img alt="" border="1" height="208" src="/uploads/allimg/111215/09431G632-0.jpg" width="322" /></center>
<p>
	　　进一步的深入，会发现自动化脚本中的逻辑结构的功能实现紧密的结合在一起，给后期的维护和修改造成的很大的麻烦。这时就会想到需要把测试脚本进行细分。因此除了按上面说到的把测试数据，测试对象分离出脚本外，还需要把脚本细分为：逻辑控制和功能实现脚本。也即实现了自动化脚本的四层架构设计。功能实现脚本即为把脚本把每个小功能细分出来并编写成一个个独立的小的功能实现脚本，如登录，登记等等。然后编写逻辑控制脚本来实现这些小的功能实现脚本执行的先后和次数，如，实现流程等。</p>
<center>
	<img alt="" border="1" height="168" src="/uploads/allimg/111215/09431L5T-1.jpg" width="500" /></center>
<p>
	　　实际应用自动化后，会发现很多脚本实现方法相同或相似，而且功能小脚本拼接不容易修改。这时可以再上面四层架构的基础再增加一个框架结构，实现五层架构。利用框架封装一些常用的方法、函数和小脚本，以实现公共脚本的复用，减少自动化脚本的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>时间。在框架中还可以把上面的四层架构的内容包含到框架中进行统一管理和调度。当然还可以利用配置文档(如ini文件)来实现流程或其他功能的可配置测试(如，网址，用户名，密码。方便改变<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/" target="_blank" >测试环境</A></STRONG>后修改)。</p>
<center>
	<img alt="" border="1" height="226" src="/uploads/allimg/111215/09431M2Y-2.jpg" width="560" /></center>
<p>
	　　以上只是针对整体的大的自动化方面来区分，当然还可以对一些小的部分进行细分，以达到更好的可配置性和容错性，降低脚本的修改成本。可以再细分的设计如下(暂时想到的)：</p>
<p>
	　　1.测试对象的定制</p>
<p>
	　　首先可以应用QTP的对象管理来实现对象维护功能，但是这个功能在实现对象的定制上还是比较弱。QTP支持使用描述性编程来实现对象的识别，即可以通过定制的识别对象的属性名和属性值来实现对象的识别。这样就可以把对象的类型和识别对象的属性名和属性值维护在框架中的对象识别Excel文档中，格式如下，这样就能实现更强的对象定制功能：</p>
<p>
	　　表--对象识别表</p>
<table border="1" cellpadding="0" cellspacing="0" class="content" id="table5" width="436">
	<tbody>
		<tr>
			<td valign="top" width="136">
				<b>对象名</b></td>
			<td valign="top" width="153">
				<b>对象类型</b></td>
			<td valign="top" width="147">
				<b>识别对象属性及值</b></td>
		</tr>
		<tr>
			<td valign="top" width="136">
				登录按钮</td>
			<td valign="top" width="153">
				WebButton</td>
			<td valign="top" width="147">
				Name:=登录</td>
		</tr>
		<tr>
			<td valign="top" width="136">
				&nbsp;<wbr /></td>
			<td valign="top" width="153">
				&nbsp;<wbr /></td>
			<td valign="top" width="147">
				&nbsp;<wbr /></td>
		</tr>
	</tbody>
</table>
<p>
	　　2. 逻辑配置到外部文档，实现事件与脚本分离</p>
<p>
	　　通过把要实现的逻辑按顺序配置到外部文件，然后再QTP脚本中调用此配置文件，最后根据配置文件中的信息调用不同的脚本、对象、测试数据来进行测试。配置样表如下：</p>
<p>
	　　表--登录流程表</p>
<table border="1" cellpadding="0" cellspacing="0" class="content" id="table6">
	<tbody>
		<tr>
			<td valign="top" width="189">
				<b>序号</b></td>
			<td valign="top" width="189">
				<b>对象</b></td>
			<td valign="top" width="189">
				<b>事件</b></td>
		</tr>
		<tr>
			<td valign="top" width="189">
				1</td>
			<td valign="top" width="189">
				用户名输入框</td>
			<td valign="top" width="189">
				Set</td>
		</tr>
		<tr>
			<td valign="top" width="189">
				2</td>
			<td valign="top" width="189">
				用户密码输入框</td>
			<td valign="top" width="189">
				Set</td>
		</tr>
		<tr>
			<td valign="top" width="189">
				3</td>
			<td valign="top" width="189">
				登录按钮</td>
			<td valign="top" width="189">
				Click</td>
		</tr>
		<tr>
			<td valign="top" width="189">
				4</td>
			<td valign="top" width="189">
				登录后页面</td>
			<td valign="top" width="189">
				Check</td>
		</tr>
		<tr>
			<td valign="top" width="189">
				&nbsp;<wbr /></td>
			<td valign="top" width="189">
				&nbsp;<wbr /></td>
			<td valign="top" width="189">
				&nbsp;<wbr /></td>
		</tr>
	</tbody>
</table>
<p>
	　　3. 页面对象检验文档化</p>
<p>
	　　把要添加大量验证点的页面的对象维护到外部Excel文档，然后在QTP脚本中调用此文档，这样就可以实现要验证对象的动态修改。样表如下：</p>
<table border="1" cellpadding="0" cellspacing="0" class="content" id="table7" width="568">
	<tbody>
		<tr>
			<td valign="top" width="133">
				<b>页面</b></td>
			<td valign="top" width="150">
				<b>对象类型</b></td>
			<td valign="top" width="144">
				<b>识别对象属性及值</b></td>
			<td valign="top" width="142">
				<b>期望值</b></td>
		</tr>
		<tr>
			<td valign="top" width="133">
				案件保存结果页面</td>
			<td valign="top" width="150">
				姓名</td>
			<td valign="top" width="144">
				Name:=姓名</td>
			<td valign="top" width="142">
				测试姓名</td>
		</tr>
		<tr>
			<td valign="top" width="133">
				案件保存结果页面</td>
			<td valign="top" width="150">
				地址</td>
			<td valign="top" width="144">
				Name:=address</td>
			<td valign="top" width="142">
				北京市海淀区</td>
		</tr>
		<tr>
			<td valign="top" width="133">
				&nbsp;<wbr /></td>
			<td valign="top" width="150">
				&nbsp;<wbr /></td>
			<td valign="top" width="144">
				&nbsp;<wbr /></td>
			<td valign="top" width="142">
				&nbsp;<wbr /></td>
		</tr>
	</tbody>
</table>
<p>
	　<br />
	#p#分页标题#e#<br />
	<br />
	&nbsp;　4.测试数据按功能分离</p>
<p>
	　　QTP虽然把测试数据给分离出来到一个Excel文档中，但当测试数据很多时就不好查找，这时可以把测试数据按功能模块划分，分别放到多个测试数据Excel文档中，然后在QTP脚本中通过QTP内置对象DataTable提供的方法ImportSheet根据脚本需要使用的测试数据加载对应的Excel数据文档的工作表。这样就能实现一个数据文件按功能分解成多个数据文档，方便后期维护。</p>
<p>
	　　5.测试数据自动生成</p>
<p>
	　　当需要比较多的测试数据时，如果人工方式输入，将需要比较大的工时投入。这时可以考虑应用<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/vb/" target="_blank" >VB</A></STRONG>，C#等编写一个修改Excel数据文件中的数据的工具，且要实现能自动生成测试数据。然后在编写的工具中能过QTP提供的接口自动调用QTP并执行自动化测试，然后显示测试结果。</p>
<p>
	　　6. 脚本与QTP分离</p>
<p>
	　　要实现脚本与QTP分离，使QTP只成为执行工具，最好可以使用VBS文件来实现，毕竟QTP支持VBS，加载VBS脚本到QTP中后可以直接运行。当然也可以使用其他文件来存储这些脚本，然后加载到QTP后使用Execute来动态执行这些脚本。不过最好还是用VBS，在VBS文件中最好全用Function和Sub来模块化小脚本，以实现更好的可配置。使用的方式可以如下：</p>
<center>
	<img alt="" border="1" height="317" src="/uploads/allimg/111215/09431J130-3.jpg" width="635" /></center>
<p>
	　　以上只是在学习QTP和使用QTP的过程中想到的一些QTP应用方式的设计思路(有些思路已经在当前测试部的自动化测试中实际应用了)，并不是说要应用QTP就得实现这些设计，只有适应当前QTP应用现状和项目现状的应用方式才是最好的方式。但这些设想也可以为将来更好的使用和优化QTP测试提供一些思路。但主要还是在实践中要多总结，并多考虑更好的架构和实现形式，并不断补充和实践，才能促进自动化更好的应用。</p>
]]></description>
    <pubDate>Fri, 16 Dec 2011 09:09:18 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111215/09431G632-0-lp.jpg</subImagePath>
     <category>QuickTestPro</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[【软件测试自动化-QTP系列讲座 10】 QTP的两种回放模式]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/2011/1214/203761.html</link>
    <description><![CDATA[<p>
	当你在回放<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/quicktestpro/" target="_blank" >QTP</A></STRONG>的时候，你是否有注意过QTP在回放的时候鼠标是没有运动的</p>
<p>
	有些朋友肯定会问，既然是CLICK点击为什么鼠标没有动，而QTP回放的时候却可以成功的点击按钮的呢<br />
	<br />
	其实QTP是有两种回放模式的：</p>
<p>
	1. Event模式 -- 事件跟踪</p>
<p>
	2. Mouse模式 -- 鼠标跟踪</p>
<p>
	Event模式就是我们平时默认用的模式，也就是事件，其实QTP的click方法只是触发了对象的CLICK事件，而并未真正通过鼠标来进行点击按钮。而如果我们使用的是Mouse模式的话，我们会看到回放的时候，鼠标是跟着对象走的，也就是鼠标跟踪模式。</p>
<p>
	下面我们来具体看一下是怎么切换回放模式：</p>
<p>
	切换回放模式有两种方法：</p>
<p>
	a.修改QTP OPTIONS设置</p>
<p>
	我们进入到TOOLS--》options--》WEB--&gt;ADVANCED 然后列表拖到最下面可以找到REPLAY TYPE</p>
<p>
	&nbsp;</p>
<img src="http://www.uml.org.cn/Test/images/z1.bmp" />
<p>
	我们可以看到QTP默认的回放模式是EVENT，也就是事件跟踪。</p>
<p>
	如果我们现在切换到MOUSE，点击确认后，回放时鼠标就会进行跟踪，不信大家可以试一下。</p>
<p>
	&nbsp;b.代码控制（个人推荐第二种）</p>
<p>
	为什么推荐这种方式，因为这种方式可以在QTP运行时根据我们的个性化需要来进行控制，随时可以进行开和关</p>
<p>
	而使用第一种方式就不能够达到以上的效果。</p>
<p>
	代码：</p>
<p>
	Setting.WebPackage(&quot;ReplayType&quot;) = 2</p>
<p>
	这句话的意思就是把回放模式设置为2， 1代表事件跟踪，2代表鼠标跟踪</p>
<p>
	很清楚了吧，这样我们就可以在QTP运行时个性化的定制我们的回放模式</p>
<p>
	那说到这里，肯定会有朋友问，那鼠标模式有什么用，我们平时默认的事件模式不是都够用了吗</p>
<p>
	接下来就说一下，我们为什么要使用鼠标模式，比如触发了CLICK事件后，应该弹出页面的，却被IE给拦截了，而手工点击可以成功</p>
<p>
	；还有当我们需要操作鼠标右键的时候，等等这些情况我们都可以临时把回放模式切换成鼠标模式</p>
<p>
	==================实例==================</p>
<p>
	我们现在要实现右键点击GOOGLE主页中GOOGLE大全的链接</p>
<p>
	1.首先我们把这个链接对象加载到QTP对象库中</p>
<p>
	&nbsp;</p>
<img src="http://www.uml.org.cn/Test/images/z2.bmp" />
<p>
	2.添加完之后我们输入一下脚步</p>
<p>
	Setting.WebPackage(&quot;ReplayType&quot;) = 2 Browser(&quot;Google&quot;).Page(&quot;Google&quot;).Link(&quot;Google 大全&quot;).FireEvent &quot;onclick&quot;,,,micRightBtn</p>
<p>
	3.回放之后就可以看到已经成功点击了右键</p>
<p>
	<img src="http://www.uml.org.cn/Test/images/z3.bmp" /></p>
<p>
	<br />
	这边先附上简单的方法介绍</p>
<p>
	Argument Description<br />
	object A test object of type WebElement.<br />
	EventName Required. A String value. The name of event to trigger. Available events: onchange, onclick, ondblclick, onblur, onfocus, onmousedown, onmouseup, onmouseover, onmouseout, onsubmit, onreset, onpropertychange.<br />
	x Optional. A Long value. The x-coordinate, relative to the upper left corner of the object.<br />
	y Optional. A Long value. The y-coordinate, relative to the upper left corner of the object.<br />
	BUTTON Optional. A predefined constant or number. See the Constants table, below. The mouse button used to fire the object. Default = micLeftBtn (0).</p>
]]></description>
    <pubDate>Wed, 14 Dec 2011 09:34:05 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>QuickTestPro</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[LoadRunner性能测试基础知识问答]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2011/1214/203760.html</link>
    <description><![CDATA[<p>
	　　Q1：什么是负载测试?什么是<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/xncs/" target="_blank" >性能测试</A></STRONG>?</p>
<p>
	　　A1：负载测试是通过逐步增加系统负载，测试系统性能的变化，并最终确定在满足性能指标的情况下，系统所能承受的最大负载量的测试，例如，访问一个页面的响应时间规定不超过1秒，负载测试就是测试在响应时间为1秒时，系统所能承受的最大并发访问用户的数量。</p>
<p>
	　　性能测试：指在一定的约束条件下(指定的软件、硬件、<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlzs/" target="_blank" >网络</A></STRONG>环境等)，确定系统所能承受的最大负载压力。</p>
<p>
	　　Q2.性能测试包含了哪些测试(至少举出3种)</p>
<p>
	　　A2：性能测试包含负载测试、<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/xncs/" target="_blank" >压力测试</A></STRONG>、大数据量测试、疲劳强度测试等。</p>
<p>
	　　Q3.简述性能测试的步骤</p>
<center>
	<img alt="" border="1" height="200" src="/uploads/allimg/111214/09324J528-0.jpg" width="605" /></center>
<p>
	　　Q4.简述使用Loadrunner的步骤</p>
<p>
	　　A4：制定性能<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csmb/csjh/" target="_blank" >测试计划</A></STRONG>&mdash;&gt;<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>测试脚本&mdash;&gt;设计测试场景&mdash;&gt;执行测试场景&mdash;&gt;监控测试场景&mdash;&gt;分析测试结果</p>
<center>
	<img alt="" border="1" height="248" src="/uploads/allimg/111214/09324M161-1.jpg" width="605" /></center>
<p>
	　　Q5.什么时候可以开始执行性能测试?</p>
<p>
	　　A5：<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/" target="_blank" >功能测试</A></STRONG>通过;一般需要进行性能测试的系统，都是用户量比较大、业务使用比较频繁、比较重要的功能模块。</p>
<p>
	　　Q6.<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LoadRunner</A></STRONG>由哪些部件组成?</p>
<p>
	　　A6：主要有三部分组成：</p>
<center>
	<img alt="" border="1" height="200" src="/uploads/allimg/111214/09324MI9-2.jpg" width="605" /></center>
<p>
	　　Q7.你使用LoadRunner的哪个部件来录制脚本?</p>
<p>
	　　A7：使用Virtual User Generator录制测试脚本</p>
<p>
	　　Q8.LoadRunner的哪个部件可以模拟多用户并发下回放脚本?</p>
<p>
	　　A8：LoadRunner的Controller组件。</p>
<p>
	　　Q9.什么是集合点?设置集合点有什么意义?Loadrunner中设置集合点的函数是哪个?</p>
<p>
	　　A9：在性能测试过程中，需要模拟大量用户在同一时刻，访问系统并同时操作某一任务，可以通过配置集合点来实现，多个用户同时进行某操作;</p>
<p>
	　　集合点可以在<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>上创建密集的用户负载，使LoadRunner能够测试服务器在负载状态下的性能。</p>
<p>
	　　设置集合点函数：<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >lr</A></STRONG>_rendezvous(&quot;Meeting&quot;); // Meeting是集合点名称</p>
<p>
	　　Q10.什么是场景?场景的重要性有哪些?如何设置场景?</p>
<p>
	　　A10：场景用于模拟用户实际业务操作;</p>
<p>
	　　LoadRunner中场景有手工场景和面向目标的场景。</p>
<p>
	　　设置场景：选择场景类型、设置运行时设置、模拟用户数、加减压方式、持续时间，配置负载生成器。</p>
<p>
	　　Q11.请解释一下如何录制web脚本?</p>
<p>
	　　A11：利用Virtual User Generator录制测试脚本，录制步骤：</p>
<p>
	　　1、选择合适的协议</p>
<center>
	<img alt="" border="1" height="382" src="/uploads/allimg/111214/09324LV7-3.jpg" width="605" /></center>
<p>
	　　2、设置录制选项</p>
<center>
	<img alt="" border="1" height="423" src="/uploads/allimg/111214/09324M1Z-4.jpg" width="558" /></center>
<p>
	　　3、开始录制</p>
<center>
	<img alt="" border="1" height="257" src="/uploads/allimg/111214/09324GV2-5.jpg" width="447" /></center>
<p>
	　　Q12.为什么要创建参数?如何创建参数?</p>
<p>
	　　A12：LoadRunner在录制脚本的时候，只是忠实的记录了所有从客户端发送到服务器的数据，而在进行性能测试的时候，为了更接近真实的模拟现实应用，对于某些信息需要每次提交不同的数据，或者使用多个不同的值进行循环输入。这时，在LoadRunner中就可以进行参数化设置，以使用多个不同的值提交应用请求。</p>
<p>
	　　【参数化】：使用指定数据源中的值来替换脚本录制生成的语句中的参数。</p>
<p>
	　　【参数化好处】</p>
<p>
	　　减少脚本的大小</p>
<p>
	　　提供使用不同的值执行脚本的能力，更加真实的模拟现实应用。</p>
<p>
	　　【参数化步骤】</p>
<p>
	　　用参数替换Vuser脚本中的常量值</p>
<p>
	　　为参数设置属性和数据源</p>
<p>
	　　Q13.什么是关联?请解释一下自动关联和手动关联的不同。</p>
<p>
	　　A13：【关联的定义】简单的说：就是把脚本中某些写死(固定)的数据，转变成动态的数据，或者说将前面语句的结果数据保存下来，然后在后面的语句提交请求时使用这些数据。</p>
<p>
	　　【需要关联的前提条件】：</p>
<p>
	　　客户端需要从服务器端返回数据中获取部分数据，并将这些部分数据处理后作为自己下一次请求的一部分发出。</p>
<p>
	　　【自动关联与手工关联的不同】：自动关联是在脚本录制过程中，VuGen会根据已经制定好的规则，自动找出需要关联的值或脚本录制完成后，执行脚本一次，通过Correlation Studio自动找出需要关联的数据，并建立关联;而手动关联是需要录制两份相同业务流程的脚本，输入的数据要相同，利用WinDiff工具，找出两份脚本之间不同之处，也就是需要关联的数据，再通过web_reg_save_param函数手动建立关联，将脚本中用到关联的数据参数化。</p>
<p>
	　　Q14.你如何找出哪里需要关联?请给一些你所在项目的实例。</p>
<p>
	　　A14：</p>
<p>
	　　1、录制两份相同业务流程的脚本，输入的数据要相同</p>
<p>
	　　2、利用WinDiff工具，找出两份脚本之间不同之处，也就是需要关联的数据</p>
<p>
	　　3、通过web_reg_save_param函数手动建立关联，将脚本中用到关联的数据参数化。</p>
<p>
	　　示例：</p>
<center>
	<img alt="" border="1" height="235" src="/uploads/allimg/111214/09324I1B-6.jpg" width="558" /></center>
<p>
	　　通过录制两份脚本，进行对比，可知jsessionid、sap-ext-sid、sap-wd-cltwndid、sap-wd-tstamp需要进行关联。</p>
<center>
	<img alt="" border="1" height="235" src="/uploads/allimg/111214/09324I137-7.jpg" width="558" /></center>
<p>
	　　Q15.你在哪里设置自动关联选项?</p>
<p>
	　　A15：录制选项中进行设置，如下图所示：#p#分页标题#e#</p>
<center>
	<img alt="" border="1" height="416" src="/uploads/allimg/111214/09324M0Y-8.jpg" width="551" /></center>
<p>
	　　Q16.哪个函数是用来截取虚拟用户脚本中的动态值?(手工关联)</p>
<p>
	　　A16：Web_reg_save_param函数主要根据需要做关联的动态数据前面和后面的固定字符串来识别、提取动态数据，所以在做关联时，需要找出动态数据的左、右边界字符串。</p>
<p>
	　　1.函数原型：</p>
<p>
	　　int web_reg_save_param (const char *ParamName, <list attributes="" of="">, LAST);</list></p>
<list attributes="" of="">
<p>
	　　2.参数说明：</p>
<p>
	　　ParamNam：存放动态数据的参数名称</p>
<p>
	　　List of Attributes：其它属性，包含Notfound、LB、RB、RelFrameID、Search、ORD、SaveOffset、Convert、SaveLen。</p>
<p>
	　　Notfound：指当找不到要找的动态数据时，怎么处理。</p>
<p>
	　　Notfound=error，当找不到动态数据时，发出一个错误信息，为LoadRunner的默认值。</p>
<p>
	　　Notfound=warning，当找不到动态数据时，不发出错误信息，只发出警告，脚本会继续执行下去不会中断。</p>
<p>
	　　LB:动态数据的左边界字符串，该参数为必选参数，并区分大小写。</p>
<p>
	　　RB:动态数据的右边界字符串，该参数为必选参数，并区分大小写。</p>
<p>
	　　ORD:指提取第几次出现的左边界的数据，该参数为可选参数，默认值是1。假如值为All,则查找所有符合条件的数据并把这些数据存储在数组中。</p>
<p>
	　　Search：搜寻的范围。可以是Headers(只搜寻Headers)、Body(只搜寻Body部分，不搜寻Headers)、Noresources(只搜寻Body部分，不搜寻Header与Resource)或是All(搜寻全部范围，此为默认值)，该参数为可选参数。</p>
<p>
	　　RelFrameID：相对于URL而言，欲搜寻的网页的Frame，此属性可以是All或是具体的数字，该参数为可选参数。</p>
<p>
	　　SaveOffset：当找到符合的动态数据时，从第几个字符开始才存储到参数中，该参数为可选参数，此属性值不可为负数，其默认值是0.</p>
<p>
	　　Convert：可能的值有两种:</p>
<p>
	　　HTML_TO_URL:将HTML-encoded数据转成URL-encoded数据格式。</p>
<p>
	　　HTML_TO_TEXT:将HTML-encoded数据转成纯文字数据格式。</p>
<p>
	　　SaveLen：从Offset开始算起，到指定长度内的字符串，才储存到参数中，该参数为可选参数，默认值为-1，表示储存到结尾整个字符串。</p>
<p>
	　　Q17.你在VUGen中何时选择关闭日志?何时选择标准和扩展日志?</p>
<p>
	　　A17：在测试场景执行时，关闭日志，因为日志信息过多，也会影响性能测试结果;在调试测试脚本时，可以选择标准或扩展日志，用于输出调试信息。</p>
<p>
	　　可以在运行时设置中，进行日志设置，如下图所示：</p>
<center>
	<img alt="" border="1" height="408" src="/uploads/allimg/111214/09324K4C-9.jpg" width="556" /></center>
<p>
	　　Q18.你如何调试LoadRunner脚本?</p>
<p>
	　　A18： 通常采用以下方法调试LoadRunner测试脚本</p>
<p>
	　　断点</p>
<p>
	　　【方法】在脚本的任意一行上按右键菜单或F9增加断点。</p>
<p>
	　　单步跟踪</p>
<p>
	　　【方法】通过菜单命令VUser&mdash;&gt;Run Step by Step或F10，可以控制脚本以语句为单位执行。</p>
<p>
	　　日志输出</p>
<p>
	　　【方法】通过日志输出函数lr_message、lr_log_message、lr_output_message输出。</p>
<p>
	　　对话框输出</p>
<p>
	　　综上，在实际测试工作中，基本上使用前三种方法，对话框输出基本上没用过。</p>
<p>
	　　Q19、你在<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LR</A></STRONG>中如何编写自定义函数?请给出一些你在以前进行的项目中编写的函数。</p>
<p>
	　　A19：在编写用户自定义函数之前，需要首先为函数创建外部库(DLL)文件，将这些库文件放在bin目录下，一旦库文件已经被添加并且将用户自定义函数作为参数，函数应该为以下格式：__declspec (dllexport) char* (char*， char*)</p>
<p>
	　　Q20.在运行设置下你能更改那些设置?</p>
<p>
	　　A20：可以修改Run Logic、pacing、Log、Think Time等，见下图;可以测试实际需要，修改相关选项。</p>
<center>
	<img alt="" border="1" height="412" src="/uploads/allimg/111214/09324Kb5-10.jpg" width="559" /></center>
<p>
	　　Q21.你在不同的环境下如何设置迭代?</p>
<p>
	　　A21：在&ldquo;运行时设置&rdquo;中设置，如下图所示：</p>
<center>
	<img alt="" border="1" height="412" src="/uploads/allimg/111214/09324MA4-11.jpg" width="559" /></center>
<p>
	　　Q22.你如何在负载测试模式下执行功能测试?</p>
<p>
	　　A22：在负载测试模式下，可以通过同时运行数个虚拟用户，通过增加虚拟用户数，确定服务器在多大的负载量下，仍然可以正常运行，我一般进行核心功能操作，验证核心功能运行是否正常。</p>
<p>
	　　Q23.什么是逐步递增?你如何来设置?</p>
<p>
	　　A23：虚拟用户数随着负载时间逐渐增加，可以帮助确定系统响应时间减慢的准确时间点。</p>
<p>
	　　可以在&ldquo;加压&rdquo;选项卡中进行设置：如下图所示，将设置更改为：&ldquo;每 30 秒启动 2 个 Vuser&rdquo;</p>
<center>
	<img alt="" border="1" height="137" src="/uploads/allimg/111214/09324H429-12.jpg" width="369" /></center>
<p>
	　　Q24.以线程方式运行的虚拟用户有哪些优点?</p>
<p>
	　　A24：以线程方式运行的虚拟用户，在默认情况下，Controller为每50个用户仅启动一个mmdrv进程，而每个用户都按线程方式来运行，这些线程用户将共享父进程的内存，这就节省了大量内存空间，从而可以在一个负载生成器上运行更多的用户。</p>
<p>
	　　Q25.当你需要在出错时停止执行脚本，你怎么做?</p>
<p>
	　　A25：取消运行设置中的&ldquo;Continue on error&rdquo;复选框。</p>
<p>
	　　或者使用lr_abort函数。</p>
<center>
	<img alt="" border="1" height="408" src="/uploads/allimg/111214/09324LI6-13.jpg" width="556" /></center>
<p>
	　　Q26.响应时间和吞吐量之间的关系是什么?</p>
<p>
	　　A26：当系统吞吐量未达到系统处理极限时，系统性能不会衰减，交易平均响应时间一般也不会递增，当系统达到吞吐量极限时，客户端交易会在请求队列中排队等待，等待的时间会记录在响应时间中，故交易平均响应时间一般会递增。#p#分页标题#e#</p>
<p>
	　　Q27.说明一下如何在LR中配置系统计数器?</p>
<p>
	　　A27：以windows资源监控为例，可右键点&ldquo;添加<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/rjdl/" target="_blank" >度量</A></STRONG>&rdquo;，输入系统IP、选择平台类型，确定即可，详细参加LR自带操作手册^_^。</p>
<p>
	　　对于监控不同类型的操作系统，需要做一些准备工作，可参见监控操作系统资源部分。</p>
<p>
	　　Q28.你如何识别性能瓶颈?</p>
<p>
	　　A28：性能瓶颈分为：硬件瓶颈和软件瓶颈</p>
<p>
	　　性能瓶颈可以通过监控器来分析发现，这些监控器包括应用服务器监控、web服务器监控、<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>服务器监控器和网络监控器;它们可以帮助分析导致响应时间增加的原因;性能度量一般包括响应时间、吞吐量、每秒点击率、网络延迟等等。</p>
<p>
	　　Q29.如果web服务器、数据库以及网络都正常，问题会出在哪里?</p>
<p>
	　　A29：问题可能出在系统本身或应用服务器、或为应用编写的代码编写中。</p>
<p>
	　　Q30.如何发现web服务器的相关问题?</p>
<p>
	　　A30：可以利用web资源监控器发现web服务器相关问题，在场景执行过程中，可以利用监控器分析web服务器吞吐量、每秒点击率、每秒HTTP响应数、每秒页面<STRONG><A href="http://www.ltesting.net/ceshi/down" target="_blank" >下载</A></STRONG>数，以及web服务器硬件资源使用情况等。</p>
<p>
	　　Q31.如何发现数据库的相关问题?</p>
<p>
	　　A31：可以通过数据库监控器和数据资源图发现数据库相关的问题，例如在运行Controller之前，可以指定需要度量的资源，之后可以根据监控的数据，分析数据库相关的问题。</p>
<p>
	　　Q32.解释所有web录制配置?</p>
<p>
	　　A32：选择录制协议、设置录制选项、选择浏览器、选择存放路径、开始录制。</p>
<p>
	　　Q33.解释一下覆盖图和关联图的区别?</p>
<p>
	　　A33：覆盖图：合并两个图的内容，使用同一个X轴，合并图左Y轴显示当前图的值，合并图右Y轴显示被合并图的值。</p>
<p>
	　　关联图：当前活动图的Y轴变为合并图的X轴，被合并图的Y轴变成合并图的Y轴。</p>
<p>
	　　Q34.你如何设计负载?标准是什么?</p>
<p>
	　　A34：负载测试计划多少用户数量、使用什么类型的机器、以及在什么环境下进行。主要基于两个重要的文档，任务分布图和事务信息，任务分布图告诉我们在负载时间段内，某一个事务使用的用户数，高峰使用率及低峰使用率均来自该文档;</p>
<p>
	　　事务信息告诉我们事务名及优先级，在设计场景时可以参考。</p>
<p>
	　　Q35.Vuser_init中包括什么内容?</p>
<p>
	　　A35：Vuser_init中包含在脚本执行过程中只需执行一次的脚本。一般来说，所有需要初始化的都可以放在vuser_init里面，比如登录。</p>
<p>
	　　Q36. Vuser_end中包括什么内容?</p>
<p>
	　　A36：vuser_end中一般包含退出的过程，比如退出系统，主要在脚本执行完成或停止时运行，在设置了迭代次数时，vuser_end和vuser_int均只执行一次。</p>
<p>
	　　Q37.什么是think time?think_time有什么用?</p>
<p>
	　　A37：思考时间：用户在各步骤之间停下来进行思考的时间，由于用户基于其经验水平和目标而与应用程序进行交互操作，因此技术水平更高的用户工作起来可能会比新用户要快。</p>
<p>
	　　通过启用思考时间，可以使 Vuser在负载测试期间更准确地模拟其对应的真实世界用户。</p>
<p>
	　　Q38.标准日志和扩展日志的区别是什么?</p>
<p>
	　　A38：标准日志：脚本执行过程中，将函数集及信息发送到日志文件中</p>
<p>
	　　扩展日志：可以将详细的脚本执行信息输出到日志文件中，可以选择以下三种扩展日志信息：</p>
<p>
	　　参数替换：脚本运行过程中，可以将参数及当前参数值输出到日志文件中</p>
<p>
	　　服务器返回的数据：将服务器返回给客户端的数据输出到日志文件中</p>
<p>
	　　高级跟踪：所有的虚拟用户信息和函数调用输出到日志文件中</p>
<p>
	　　Q39.解释以下函数及他们的不同之处。</p>
<p>
	　　A39：lr_debug_message：发送调试信息到输出窗口或业务监控日志文件中</p>
<p>
	　　lr_output_message：发送日志信息到输出窗口或业务监控日志文件中</p>
<p>
	　　lr_error_message：发送错误信息到输出窗口或业务监控日志文件中</p>
<p>
	　　lrd_stmt：赋予一个SQL语句用于处理</p>
<p>
	　　lrd_fetch：获取结果集中的下一行数据</p>
<p>
	　　Q40.什么是吞吐量?</p>
<p>
	　　A40：客户端每秒从服务器接收到的数据，或系统服务器每秒能处理通过的交易数。一般随着虚拟用户数的增加，吞吐量也增加，说明网络带宽比较充足，反之，吐过随着虚拟用户数的增加，吞吐量比较平稳，呈直线状态，则说明网络带宽成为瓶颈，限制了数据传输。</p>
<p>
	　　Q41.场景设置有哪几种方法?</p>
<p>
	　　A41：面向目标的场景设置和手动场景</p>
</list>]]></description>
    <pubDate>Wed, 14 Dec 2011 09:31:00 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111214/09324J528-0-lp.jpg</subImagePath>
     <category>LoadRunner</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[探讨LoadRunner的并发用户和集合点]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2011/1214/203759.html</link>
    <description><![CDATA[<p>
	　　近来跟踪一个项目，发现同事们在执行<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/xncs/" target="_blank" >性能测试</A></STRONG>时，比较热衷于使用集合点，从概念上认为要得到并发用户就必须设置集合点，认为在执行一个<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/xncs/" target="_blank" >压力测试</A></STRONG>脚本时，设置了集合点才算是有效的并发用户，没有设置结合点，就认为可能这个就不能准确的代表并发用户数。当前我并反对这个观点，不过却让我有一种疑虑，促使我想更深入的理解并发用户和集合点，我相信大多数进入性能测试研究领域的朋友都应该有疑惑，主要原因我觉得还是由于不能深入理解<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LoadRunner</A></STRONG>的实现原理，而且缺乏对系统整个过程的分析，其中这里面涉及到的<STRONG><A href="http://www.ltesting.net/ask/" target="_blank" >知识</A></STRONG>包括<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlzs/" target="_blank" >网络</A></STRONG>、协议、<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/zjj/" target="_blank" >中间件</A></STRONG>、<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>、应用层以及缓冲区和缓存等等，当然还与硬件资源CPU队列和内存等有着千丝万缕的联系。所以说要成为一个优秀的性能测试人员，真还不一个容易的过程，是需要长时间积累和学习的，只有通过大量的项目实践和分析，最后再总结于思想，才有可能成为这个领域的专家，当然也希望真正想把性能测试做好的朋友都能为此将不懈努力，乐于分享和讨论。</p>
<p>
	　　先来看一个应用系统的结构图，如下所示：</p>
<center>
	<img alt="" border="1" height="405" src="/uploads/allimg/111214/09302Tc9-0.jpg" width="788" /></center>
<p>
	　　这个图源于小布老师的<STRONG><A href="http://www.ltesting.net/ceshi/video" target="_blank" >视频</A></STRONG>中，比较直观、简洁地反映了一个应用系统的运行过程，其中包括客户端、网络、应用<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>和数据库服务器，其中每一个环节都是在执行性能测试分析中必不可少的元素，结构图中也合理得分析出了响应时间的处理过程，当请求从客户端发出之后到最后返回到客户端，这个过程中每一个环节的处理都有可能最后成为系统运行中的性能瓶颈，所以可见对系统整体结构的理解是何等重要。</p>
<p>
	　　接下来我们来看看关于并发用户和集合点的定义：</p>
<p>
	　　并发用户：通俗意义上讲就是同时操作的用户，当然这个&ldquo;同时&rdquo;可以理解为同一时间段，还可以理解为同一时间点，当然如果说并发就是同一时间点上同时操作的用户，这样理解没有错误，但对于实际情况来讲，是没有严格意义上的并发执行的，就如同进程和线程关系一样，在某一个点严格上讲就只有一个人得到执行的权利。</p>
<p>
	　　集合点：用以同步虚拟用户，以便恰好在同一时刻执行任务。这个从概念上来讲，其实也是比较模糊，正因为模糊，使用才值得去深入探讨。对于LoadRunner来说，集合点只是一种策略，而这个策略也会有很多规则，因为实际情况中并非所有用户都会同时到达集合点，上面的那个结构图就能解释这个误解，因为从客户端发出到网络、中间件、应用层再到数据库，这其中的每一个环节都有延时，也就是说不可能所有的用户都能到达所谓的集合点，才开始同时执行操作。</p>
<p>
	　　从上面的两个概念的理解来讲，有人就会思考，并发用户和集合点到底有没有关系，这才是关键。当然这个就要看<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求</A></STRONG>是什么了，所以说很多时候我们误用集合点和并发用户，其实根本原因在于对需求的理解，需求本身都没有搞清楚他想实现的场景，得到什么样的结果。当然，我们只能感慨需求并是专业的技术人员，至少我们大多数人碰到的需求都不一定是技术出身，所以他们不明白，我们就不能装忽悠，不然结果就肯定不符合实际了。</p>
<p>
	　　通常情况下，我们会得到用户这样的需求&ldquo;本系统要达到并发用户200&rdquo;，这种需求从严格意义上来讲是不合格的，因为对于一个系统来说有很多个功能，比如系统登录、注册、查询、删除等等，是要求登录达到200，还是所有功能总共达到200，因为当用户进入系统之后，有些用户在执行注册，有些用户在执行查询，是否可以并行操作，也是所谓的并发，所以说要理解集合点和并发数，从根本上就应该更清晰的理解业务流程，只有把业务分析清楚了，方才可以合理的使用集合点，正确的理解并发用户数。</p>
<p>
	　　当然，就我个人来讲，我是很少使用集合点的，因为通过LoadRunner的理解，我认为LoadRunner本身就已经在模拟实现一个并发的过程，而增加集合点设置只是为了并实现严格意义上的所谓的并发，而实际是这个集合点的设置也并非绝对达到了这个目的，结构中的过程就可以证明。当然为此我也通过一些实例来做验证，以下是对<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/" target="_blank" >Mercury</A></STRONG> web Tours网站首页，录制访问过程，脚本如下：</p>
<p>
	　　脚本 1：设置集合点</p>
<p>
	　　Action()</p>
<p>
	　　{</p>
<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >lr</A></STRONG>_rendezvous(&quot;同步访问web页面&quot;);</p>
<p>
	　　lr_start_transaction(&quot;start&quot;);</p>
<p>
	　　web_url(&quot;mercuryWebTours&quot;,</p>
<p>
	　　&quot;URL=http://192.168.3.34:1080/mercuryWebTours/&quot;,</p>
<p>
	　　&quot;Resource=0&quot;,</p>
<p>
	　　&quot;RecContentType=text/html&quot;,</p>
<p>
	　　&quot;Referer=&quot;,</p>
<p>
	　　&quot;Snapshot=t1.inf&quot;,</p>
<p>
	　　&quot;Mode=HTML&quot;,</p>
<p>
	　　LAST);</p>
<p>
	　　lr_end_transaction(&quot;start&quot;, <STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LR</A></STRONG>_AUTO);</p>
<p>
	　　return 0;</p>
<p>
	　　}</p>
<p>
	　　脚本 2：不设置集合点</p>
<p>
	　　Action()</p>
<p>
	　　{</p>
<p>
	　　web_url(&quot;mercuryWebTours&quot;,</p>
<p>
	　　&quot;URL=http://192.168.3.34:1080/mercuryWebTours/&quot;,</p>
<p>
	　　&quot;Resource=0&quot;,</p>
<p>
	　　&quot;RecContentType=text/html&quot;,</p>
<p>
	　　&quot;Referer=&quot;,</p>
<p>
	　　&quot;Snapshot=t1.inf&quot;,</p>
<p>
	　　&quot;Mode=HTML&quot;,</p>
<p>
	　　LAST);</p>
<p>
	　　return 0;</p>
<p>
	　　}</p>
<p>
	　　在相同场景实际中执行两个脚本之后，发现其响应时间其实误差很小。当然，这只是我实践中的一个，近期做的其他项目中，包括C/S和B/S都有的，我也都有实践过，期待有兴趣的朋友也可以实践验证哈，分享结论。</p>
<p>
	　　以上我只是想表达的一个观点就是，并不是集合点在我们的性能测试中没有作用，如果没有作用我相信设计LoadRunner的公司也不会给出来，而是要理解如何选择去用它，这才是关键。之前我们就讲到过，在一些业务流程比较复杂的应用程序测试中，我们就必须要使用集合点，比如一个企业系统中业务是这样的：用户登录进入之后，一部分人在完善个人资料，一部分人在查询数据，另一部分人在执行删除操作，还有一部分来发送消息等等。就这样的一个业务中，在模拟执行性能测试时，就必须明确并发用户跟集合点的关系，在实际录制脚本的时候，我们就需要把这个业务分割成多个事务，然后分别对各个不同的事务要设置集合点，为什么此时要使用集合点呢，因为我们必须分析出每一个事务的并发情况，加入200个用户进去之后，我们就这样放任去这200个用户自由去操作，就不能判断出查询并发数多少、删除并发数多少、发送消息的并发又是多少，因为进入系统之后，没办法确定200个用户都同时干了些什么，所以此处才是集合点使用最合理的地方。至于，我为什么很少使用集合点，也源于此，因为通常情况我们主要是对单一业务进行压力测试，比如登录或者是注册，单一功能就如同上面的那个访问web页面一样，脚本只有一个操作，此时对于LoadRunner来讲，其实有没有设置集合点效果不大，而且为了模拟能更加接近去实际情况，当然这也是要做实际分析的。#p#分页标题#e#</p>
<p>
	　　这里我还要个举例子，比如，一个OA系统，要求并发用户数200，而我们的场景设置是这样的，200个并发用户平均每10s加载5个用户，大约运行半小时，此时执行的场景，我们可以结合实际情况进行分析：根据实际情况得出，通常登录OA系统的的用户大部分都在早上上班9：00～9：30，此时是一个时间段，而并非一个时间点，使用我们的模拟场景是完全符合实际需求的，所以得出结论是在30分钟的时间内，我们的OA系统可以允许200个用户同时进行登录操作。由此可以说明，任何需求的提出都必须从实际环境来考虑，我们在设置场景时也必须反映出实际情况，才能模拟出更接近真实的场景，得出来的结果才更有价值。</p>
<p>
	　　当然，性能测试的执行应该是有目的，通常是为了调优，也有的是为了评测</p>
<p>
	　　在以评测为目的的性能测试中，用户更关心的是业务上的并发，其实是真实业务场景的并发情况，这种情况下就不需要设置集合点了。</p>
<p>
	　　集合点是一种特殊情况下的并发，通常是在以调优为目的的性能测试中才会用得到，主要是为了有针对性地进行施压，以便找到性能瓶颈。</p>
<p>
	　　以上纯属个人理解，期待拍砖!</p>
]]></description>
    <pubDate>Wed, 14 Dec 2011 09:28:24 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111214/09302Tc9-0-lp.jpg</subImagePath>
     <category>LoadRunner</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[LoadRunner检查点使用小结]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2011/1214/203758.html</link>
    <description><![CDATA[<p class="artcon">
	<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LR</A></STRONG>中检查点有两种：图片和文字。</p>
<p class="ar<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/testdirector/" target="_blank" >td</A></STRONG>ir1">
	常用检查点函数如下：</p>
<p class="artcon">
	1）web_find()函数用于从 HTML 页中搜索指定的文本字符串；</p>
<p class="artcon">
	2）web_reg_find()函数注册一个请求，以在下一个操作函数（如 web_url）检索到的HTML网页上搜索指定的文本字符串；</p>
<p class="artcon">
	3）web_image_check()函数用于从HTML页面中查找指定的图片；</p>
<p class="artcon">
	4）web_global_verfication()属于注册函数，注册一个在web页面中搜索文本字符串的请求，与web_reg_find只在下一个Action函数中执行搜索不同的是它在之后所有的Action类函数中执行搜索指定的文本字符串；</p>
<p class="artdir1">
	<strong>下面分别介绍以上函数的用法：</strong></p>
<p class="artdir3">
	1、web_find()函数参数举例：</p>
<p class="artcon">
	web_find(&quot;web_find&quot;,&quot;RighOf=a&quot;,&quot;LeftOf=b&quot;,&quot;What=name&quot;,LAST);</p>
<p class="artcon">
	参数解释：&quot;web_find&quot;定义该查找函数的名称；&ldquo;LeftOf&rdquo;和&ldquo;RighOf=&rdquo;用来定义查找字符的左右边界；&ldquo;What=&rdquo;定义查找内容；</p>
<p class="artcon">
	例如上述参数举例中的意思就是在页面中查找左边界为b，右边界为a，内容为name的信息；</p>
<p class="artcon">
	使用该函数注意事项：该函数是在查找页面中的内容，所以要放在要查找的内容的后面；该函数只能在基于HTML模式录制的脚本中进行查找</p>
<p class="artcon">
	注意事项：使用该函数时，要在Vuser-&gt;Run-Tme Settings中更改下设置</p>
<p class="artcon">
	<img height="333" src="/uploads/allimg/111214/092GW318-0.jpg" width="481" /></p>
<p class="artcon">
	勾选Enable Image and text check</p>
<p class="artcon">
	<img height="408" src="/uploads/allimg/111214/092GT251-1.jpg" width="555" /></p>
<p class="artcon">
	系统默认是不勾选该选项的。</p>
<p class="artdir3">
	2、web_reg_find()函数参数举例：</p>
<p class="artcon">
	web_reg_find(&quot;Search=Body&quot;,&quot;SaveCount=ddd&quot;,&quot;Test=aaa&quot;,LAST);</p>
<p class="artcon">
	参数解释： Search用来定义查找范围，SaveCount定义查找计数变量名称，该参数可以记录在缓存中查找内容出现的次数，可以使用该值，来判断要查找的内容是否被找到；</p>
<p class="artcon">
	例如上述参数举例中的意思就是Body中查找内容为aaa的信息，并将出现次数记录在变量ddd中；</p>
<p class="artcon">
	【代码一：web_reg_find(&quot;Text=Payment Details&quot;,LAST);</p>
<p class="artcon">
	代码思路：1.&ldquo;Payment Details&rdquo; 为你要检查的文本；</p>
<p class="artcon">
	2. 脚本执行到此处，若在页面上找到了这几个字符串，那脚本继续执行下去；若没有找到，脚本将在此报错并且结束。】</p>
<p class="artcon">
	【代码二：web_reg_find(&quot;Text=Payment Details&quot;, &quot;SaveCount=para_count&quot;, LAST); //check 的函数</p>
<p class="artcon">
	web_submit_form(&quot;reservations.pl_2&quot;, //要check的页面的录制时的代码</p>
<p class="artcon">
	&quot;Snapshot=t22.inf&quot;,</p>
<p class="artcon">
	ITE<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/mda/" target="_blank" >MDA</A></STRONG>TA,</p>
<p class="artcon">
	&quot;Name=outboundFlight&quot;, &quot;Value=003;0;06/23/2007&quot;, ENDITEM,</p>
<p class="artcon">
	&quot;Name=reserveFlights.x&quot;, &quot;Value=61&quot;, ENDITEM,</p>
<p class="artcon">
	&quot;Name=reserveFlights.y&quot;, &quot;Value=2&quot;, ENDITEM,</p>
<p class="artcon">
	LAST);</p>
<p class="artcon">
	if (atoi(lr_eval_string(&quot;{para_count}&quot;))&gt;0) //验证是否找到了页面上的要检查的字符串</p>
<p class="artcon">
	lr_output_message(&quot;we find the string!&quot;);</p>
<p class="artcon">
	else</p>
<p class="artcon">
	lr_output_message(&quot;sorry,don&#39;t find the string!&quot;);</p>
<p class="artcon">
	代码思路：1.&ldquo;Payment Details&rdquo; 为你要检查的文本；</p>
<p class="artcon">
	2. 脚本执行到此处，不管页面上是否存在你要检查的字符串，脚本都不会报错，而是执行下去。</p>
<p class="artcon">
	3. 此段代码将找到的你要检查的字符串的个数，存为一个参数。 然后在页面代码的后面，通过检查这个参数的值是否大于0，来判断是否找到了你所要检查的字符串。】</p>
<p class="artcon">
	【代码三：</p>
<p class="artcon">
	A. web_reg_find(&quot;Text=Payment Detdils&quot;, &quot;Fail=NotFound&quot;,LAST);或</p>
<p class="artcon">
	B. web_reg_find(&quot;Text=Payment Detdils&quot;, &quot;Fail=Found&quot;,LAST);</p>
<p class="artcon">
	代码思路：</p>
<p class="artcon">
	1.&ldquo;Payment Details&rdquo; 为你要检查的文本；</p>
<p class="artcon">
	2. 若是A代码：脚本执行到此处，若没有找到check的字符串，脚本将FAIL， 并且停止执行下去。反之，则一直执行下去。</p>
<p class="artcon">
	3. 若是B代码：脚本执行到此处，若找到check的字符串，脚本将FAIL， 并且停止执行下去。反之，则一直执行下去】</p>
<p class="artcon">
	使用该函数注意事项：该函数是在缓存中查找相应的内容，所以要放在查找内容之前；通常情况下写在如下六个函数之前：Web_castom_request(); web_image(); web_link(); web_submit_data(); web_submit_form(); web_url()；</p>
<p class="artcon">
	使用技巧：在该函数的参数中有个&ldquo;SaveCount&rdquo;，该参数可以记录在缓存中查找内容出现的次数，我们可以使用该值，来判断要查找的内容是否被找到，下面举个例子来说明：（引用LR的帮助中的例子）</p>
<p class="artcon">
	// Run the Web Tours sample</p>
<p class="artcon">
	web_url(&quot;MercuryWebTours&quot;,</p>
<p class="artcon">
	&quot;URL=http://localhost/MercuryWebTours/&quot;,</p>
#p#分页标题#e#<p class="artcon">
	&quot;Resource=0&quot;,</p>
<p class="artcon">
	&quot;RecContentType=text/html&quot;,</p>
<p class="artcon">
	&quot;Referer=&quot;,</p>
<p class="artcon">
	&quot;Snapshot=t1.inf&quot;,</p>
<p class="artcon">
	&quot;Mode=HTML&quot;,</p>
<p class="artcon">
	LAST);</p>
<p class="artcon">
	// Set up check for su<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>essful login by looking for &quot;Welcome&quot;</p>
<p class="artcon">
	web_reg_find(&quot;Text=Welcome&quot;,</p>
<p class="artcon">
	&quot;SaveCount=Welcome_Count&quot;,</p>
<p class="artcon">
	LAST);</p>
<p class="artcon">
	// Now log in</p>
<p class="artcon">
	web_submit_form(&quot;login.pl&quot;,</p>
<p class="artcon">
	&quot;Snapshot=t2.inf&quot;,</p>
<p class="artcon">
	ITEMDATA,</p>
<p class="artcon">
	&quot;Name=username&quot;, &quot;Value=jojo&quot;, ENDITEM,</p>
<p class="artcon">
	Name=password&quot;, &quot;Value=bean&quot;, ENDITEM,</p>
<p class="artcon">
	&quot;Name=login.x&quot;, &quot;Value=35&quot;, ENDITEM,</p>
<p class="artcon">
	&quot;Name=login.y&quot;, &quot;Value=14&quot;, ENDITEM,</p>
<p class="artcon">
	LAST);</p>
<p class="artcon">
	// Check result</p>
<p class="artcon">
	if (atoi(lr_eval_string(&quot;{Welcome_Count}&quot;)) &gt; 0){ //判断如果Welcome字符串出现次数大于0</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;lr_output_message(&quot;Log on successful.&quot;); }//在日志中输出Log on successful</p>
<p class="artcon">
	else{ //如果出现次数小于等于</p>
<p class="artcon">
	lr_error_message(&quot;Log on failed&quot;); //在日志中输出Log on failed</p>
<p class="artcon">
	return(0); }</p>
<p class="artcon">
	我觉得这个方法非常有用，我们可以举一反三，应用到我们实际的项目</p>
<p class="artcon">
	注：在录制过程中添加的检查点，用到的函数是web_reg_find()，且参数只有&ldquo;Text=&rdquo;</p>
<p class="artdir3">
	3、web_image_check()函数参数说明：</p>
<p class="artcon">
	web_image_check(&quot;web_image_check&quot;,&quot;Alt=&quot;,&quot;Src=&quot;,LAST);</p>
<p class="artcon">
	参数解释：&ldquo;Alt&rdquo;和&ldquo;Src&rdquo;的值直接取该图片在网页源代码中相应参数的值；</p>
<p class="artcon">
	注意事项：使用该函数时，要在Vuser-&gt;Run-Tme Settings中勾选Enable Image and text check，具体操作请看web_find()中的注意事项。</p>
<p class="artcon">
	经过测试，该函数用到查找内容前面或后面，都不影响查找结果。</p>
<p class="artdir1">
	举例说明（脚本）</p>
<p class="artcon">
	该脚本记录的是登陆系统后退出的操作，在脚本中用到atoi()函数和lr_eval_string(&rdquo;{SaveCount定义的变量}&rdquo;)两个函数结合使用，判断查找内容出现的次数是否大于0，若大于0，则输入登录成功的信息。</p>
<p class="artcon">
	vuser_init()</p>
<p class="artcon">
	{</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;web_url(&quot;xjcost&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;URL=http://gczj-server8:9205/xjcost/&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Resource=0&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;RecContentType=text/html&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Referer=&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Snapshot=t1.inf&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Mode=HTML&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;EXTRARES,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Url=jsp/images/index/index.swf&quot;, ENDITEM,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Url=jsp/images/index/xxfb2.gif&quot;, ENDITEM,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; &quot;Url=jsp/images/index/ywpt2.gif&quot;, ENDITEM,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp; &nbsp;LAST);</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; web_url(&quot;userAction.struts&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; &quot;URL=http://gczj-server8:9205/xjcost/userAction.struts?actionType=reLogin&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; &quot;Resource=0&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; &quot;RecContentType=text/html&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; &quot;Referer=&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Snapshot=t2.inf&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; &quot;Mode=HTML&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; LAST);</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;return 0;</p>
<p class="artcon">
	}</p>
<p class="artcon">
	Action()</p>
<p class="artcon">
	{</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;lr_start_transaction(&quot;Log_on&quot;);</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;lr_rendezvous(&quot;Log_on&quot;);</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; web_add_cookie(&quot;userAccount=admin; DOMAIN=gczj-server8&quot;);</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;web_reg_find(&quot;Text=欢迎您&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;SaveCount=欢迎您_Count&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; LAST);</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;web_image_check(&quot;web_image_check&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Src=/xjcost/jsp/images/index1/edit_01.gif&quot;,#p#分页标题#e#</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; LAST);</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;web_submit_data(&quot;userLogin.struts&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Action=http://gczj-server8:9205/xjcost/userLogin.struts?actionType=userLogin&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Method=POST&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;RecContentType=text/html&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Referer=http://gczj-server8:9205/xjcost/userAction.struts?actionType=reLogin&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Snapshot=t3.inf&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Mode=HTML&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; ITEMDATA,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Name=userAccount&quot;, &quot;Value=admin&quot;, &nbsp;&nbsp;&nbsp;&nbsp;ENDITEM,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Name=pwd&quot;, &quot;Value=1111&quot;, ENDITEM,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;EXTRARES,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Url=jsp/images/index1/edit_01a.gif&quot;, &quot;Referer=http://gczj-server8:9205/xjcost/userLogin.struts?actionType=userLogin&quot;, &nbsp;&nbsp;&nbsp;&nbsp;ENDITEM,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;LAST);</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;web_find(&quot;web_find&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;What=欢迎您&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;LAST);</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;lr_end_transaction(&quot;Log_on&quot;,LR_AUTO);</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;//检查是否登录成功</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; //如果&ldquo;欢迎您&rdquo;这个字符出现次数大于0，输出&ldquo;Log on successfully!&rdquo;</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;if(atoi(lr_eval_string(&quot;{欢迎您_Count}&quot;))&gt;0)</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; lr_output_message(&quot;Log on successfully!&quot;);</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp; else</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;lr_error_message(&quot;Log on failed!&quot;);</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;return 0;</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;return 0;</p>
<p class="artcon">
	}</p>
<p class="artcon">
	//atoi()函数的作用是将一个ASCII字符串转换为整型</p>
<p class="artcon">
	//lr_eval_string()函数作用是取得参数值，将字符串变量中的参数值替换为当前的参数值并将这个字符串返回</p>
<p class="artcon">
	vuser_end()</p>
<p class="artcon">
	{</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;lr_think_time(4);</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;web_url(&quot;userAction.struts_2&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;URL=http://gczj-server8:9205/xjcost/userAction.struts?actionType=reLogin&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Resource=0&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;RecContentType=text/html&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Referer=&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;&quot;Snapshot=t4.inf&quot;,</p>
<p class="artcon">
	&quot;Mode=HTML&quot;,</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;LAST);</p>
<p class="artcon">
	&nbsp;&nbsp;&nbsp;&nbsp;return 0;</p>
<p class="artcon">
	}</p>
<p class="artcon">
	Global.h：</p>
<p class="artcon">
	#ifndef _GLOBALS_H</p>
<p class="artcon">
	#define _GLOBALS_H</p>
<p class="artcon">
	//--------------------------------------------------------------------</p>
<p class="artcon">
	// Include Files</p>
<p class="artcon">
	#include &quot;lrun.h&quot;</p>
<p class="artcon">
	#include &quot;web_api.h&quot;</p>
<p class="artcon">
	#include &quot;lrw_custom_body.h&quot;</p>
<p class="artcon">
	//--------------------------------------------------------------------</p>
<p class="artcon">
	// Global Variables</p>
<p class="artcon">
	#endif // _GLOBALS_H</p>
<p class="artcon">
	<strong>Replay Log常见信息说明</strong></p>
<p class="artcon">
	<strong>1、web_find()和web_image_check()函数的日志信息（这两个日志信息实际上是一样的，只是输出的函数名和参数不同）</strong></p>
<p class="artcon">
	1）信息1Action.c(22): Verification checks not enabled. web_image_check is skipped. See the &#39;Run-time settings/Preferences/Checks&#39;</p>
<p class="artcon">
	[MsgId: MMSG-27197]</p>
<p class="artcon">
	Action.c(22): web_image_check was successful</p>
<p class="artcon">
	[MsgId: MMSG-26392]</p>
<p class="artcon">
	出现该信息，说明没有勾选Enable Image and text check</p>
<p class="artcon">
	2）信息2Action.c(22): &quot;web_image_check&quot; succeeded (1 occurrence(s) found. Alt=&quot;&quot;, Src=&quot;/xjcost/jsp/images/index1/edit_01.gif&quot;)</p>
<p class="artcon">
	[MsgId: MMSG-27192]</p>
<p class="artcon">
	Action.c(22): web_image_check was successful</p>
<p class="artcon">
	[MsgId: MMSG-26392]</p>
<p class="artcon">
	出现该信息，说明检查点设置成功，且已经查找到信息#p#分页标题#e#</p>
<p class="artcon">
	3）信息3Action.c(22): Error -27191: &quot;web_image_check&quot; failed (0 occurrence(s) found. Alt=&quot;&quot;, Src=&quot;/xjcost/jsp/images/index1/edit_1.gif&quot;)</p>
<p class="artcon">
	[MsgId: MERR-27191]</p>
<p class="artcon">
	Action.c(22): web_image_check highest severity level was &quot;ERROR&quot;</p>
<p class="artcon">
	[MsgId: MMSG-26391]</p>
<p class="artcon">
	出现该信息，说明要查找的内容没有找到。这时依次尝试以下操作：</p>
<p class="artcon">
	（1）检查参数的信息是否写错；</p>
<p class="artcon">
	（2）如果是web_find(),检查函数的位置是否在要查找内容的后面；</p>
<p class="artcon">
	（3）如果是web_image_check()，查看该图片的源代码，看其是否是这个页面上的图片，很可能是图片选择错误，即所选图片不属于该页面。</p>
<p class="artcon">
	<strong>2、web_reg_find()函数的日志信息</strong></p>
<p class="artcon">
	1）信息1Action.c(15): Registering web_reg_find was successful</p>
<p class="artcon">
	[MsgId: MMSG-26390]</p>
<p class="artcon">
	出现该信息，说明内容已查找到</p>
<p class="artcon">
	2）信息2Action.c(27): Error -26366: &quot;Text=ABC&quot; not found for web_reg_find</p>
<p class="artcon">
	[MsgId: MERR-26366]</p>
<p class="artcon">
	Action.c(27): web_submit_data(&quot;userLogin.struts&quot;) highest severity level was &quot;ERROR&quot;, 18364 body bytes, 918 header bytes, 13 chunking overhead bytes</p>
<p class="artcon">
	[MsgId: MMSG-26387]</p>
<p class="artcon">
	该信息在replay log页面是红色显示的，说明没有找到内容，出现此情况尝试以下两个操作：</p>
<p class="artcon">
	（1）参数的信息是否正确；</p>
<p class="artcon">
	（2）查看该函数是否在查找内容的前面。</p>
<p class="artcon">
	<strong>插入函数的方法：</strong></p>
<p class="artcon">
	1、 手工写入，在需要插入函数的位置手工写入该函数；</p>
<p class="artcon">
	2、 光标停留在要插入函数的位置，在INSERT菜单中，选择new step，在列表中选择或查找要插入的函数，根据提示填写必要的参数；</p>
<p class="artcon">
	3、 在tree view模式下，在树状菜单中选中要插入函数的位置，右键，选择insert after或insert before，根据提示填写必要的参数；</p>
<p class="artdir1">
	总结：</p>
<p class="artcon">
	1、 这两个函数函数类型不同，WEB_FIND是普通函数，WEB_REG_FIND是注册函数；</p>
<p class="artcon">
	2、 WEB_FIND使用时必须开启内容检查选项，而WEB_REG_FIND则不没有此限制；</p>
<p class="artcon">
	3、 WEB_FIND只能用在基于HTML模式录制的脚本中，而WEB_REG_FIND没有此限制；</p>
<p class="artcon">
	4、 WEB_FIND是在返回的页面中进行内容查找，WEB_REG_FIND是在缓存中进行查找；</p>
<p class="artcon">
	5、 WEB_FIND在执行效率上不如WEB_REG_FIND；</p>
]]></description>
    <pubDate>Wed, 14 Dec 2011 09:23:46 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111214/092GW318-0-lp.jpg</subImagePath>
     <category>LoadRunner</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[IBM Rational 助您轻松完成自动化功能测试]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/2011/1213/203756.html</link>
    <description><![CDATA[<table border="0" cellpadding="0" cellspacing="0" id="table1" width="100%">
	<tbody>
		<tr valign="top">
			<td width="100%">
				<p>
					<span class="atitle2">1 解析<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/zdcs/" target="_blank" >自动化测试</A></STRONG>的困惑</span><br />
					在软件工程领域，如果说有一种工作让人在痛苦中感受它的价值、在无休止的加班中体会它的苦涩、在技术的进步中体验它的快乐的话，那它一定是软件测试。计算机技术发展到今天，自动化<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>的广泛应用使人们重新认识到测试的源动力：最优的质量成本，软件<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>过程中的测试及各种<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/" target="_blank" >质量保证</A></STRONG>活动，无疑是在追求软件质量成本和收益间的最佳平衡点。</p>
				<p>
					谈到自动化测试，首先我们要明确什么情况下需要自动化。自动化测试的目的是通过自动执行测试脚本，使测试人员在更短的时间内能够更快地完成更多的软件测试，并提供以更高的频率执行测试的能力，从而有效降低测试成本、提高测试效率。从软件测试的成本来看，使用测试工具进行软件自动化测试的成本可以以下公式表示：</p>
				<p>
					自动化测试的成本＝测试工具成本＋测试脚本的创建成本＋测试脚本的维护成本</p>
				<p>
					既然自动化测试的目的在于降低测试成本、提高测试效率，因此，测试团队在选择自动化测试工具时，必须在提高测试效率的同时，尽量做到自动化测试的总体成本小于<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/" target="_blank" >手工测试</A></STRONG>成本。因此，自动化测试工具的脚本自动化创建能力和可维护性，就成了衡量自动化测试工具的重要因素。</p>
				<p>
					在实际的测试工作中，一般说来，我们选择自动化的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/" target="_blank" >功能测试</A></STRONG>工具无外乎要解决以下三个问题：</p>
				<ul xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
					<li>
						自动化的功能<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csgl/hgcs/" target="_blank" >回归测试</A></STRONG></li>
					<li>
						大批量数据驱动的软件测试</li>
					<li>
						整个软件测试生命周期的管理</li>
				</ul>
				<p>
					在选择自动化测试工具解决这些问题的过程中，人们主要关心的问题是使用自动化测试工具创建测试脚本的能力、工具的易用性、测试脚本的编程和扩展能力、测试脚本的参数化技术以及作为软件开发重要环节的测试工作和其它软件生命周期管理工具的集成能力。</p>
				<p>
					因此，摆脱自动化测试困惑的根本途径，就是理解自动化测试的本质，明确自己的自动化测试需求，选择合适的自动化测试工具，帮助测试团队提高效率、降低成本，最终实现软件开发过程的全过程质量保证。</p>
				<p>
					<span class="atitle2">2 IBM最新自动化功能测试<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/jjfa/" target="_blank" >解决方案</A></STRONG>：Rational Functional Tester</span><br />
					IBM Rational Functional Tester（简称<STRONG><A href="http://www.ltesting.net/a/FunctionalTester/" target="_blank" >RFT</A></STRONG>）是一款先进的、自动化的功能和回归测试工具，它适用于测试人员和GUI开发人员。使用它，测试新手可以简化复杂的测试任务，很快上手；<STRONG><A href="http://www.ltesting.net/ceshi/blog/zhuanjia/" target="_blank" >测试专家</A></STRONG>能够通过选择工业标准化的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/zdcsjbyy/" target="_blank" >脚本语言</A></STRONG>，实现各种高级定制功能。通过IBM的最新专利技术，例如基于Wizard的智能数据驱动的软件<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/" target="_blank" >测试技术</A></STRONG>、提高测试脚本重用的ScriptAssurance技术等等，大大提高了脚本的易用性和可维护能力。同时，它第一次为<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcskfyy/java/" target="_blank" >Java</A></STRONG>和<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/webcs/" target="_blank" >Web测试</A></STRONG>人员，提供了和开发人员同样的操作平台（Eclipse），并通过提供与IBM Rational整个测试生命周期软件的完美集成，真正实现了一个平台统一整个软件开发团队的能力。</p>
				<p>
					<span class="atitle2">3 使用IBM RFT轻松完成自动化功能测试</span><br />
					　</p>
				<p>
					<span class="atitle3">3.1 基于与开发人员同一开发平台的功能测试</span><br />
					IBM RFT的最大特色就是基于开发人员的同一开发平台（Eclipse），为Java和Web测试人员提供了自动化测试能力。如图一所示，使用RFT进行软件测试时，我们只要在开发人员工作的Eclipse环境中打开Functional Test透视图，就会马上拥有专业的自动化功能测试工具所拥有的全部功能。</p>
				<p>
					图一、IBM Rational Functional Test工作界面<br />
					<img alt="图一、IBM Rational Functional Test工作界面" border="0" height="389" src="/uploads/allimg/111213/094F23I1-0.jpg" width="604" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /></p>
				<p>
					在RFT中实现测试脚本的过程和大部分的自动化测试工具一样，是基于录制的脚本生成技术。当我们完成<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csyl/" target="_blank" >测试用例</A></STRONG>后，只要在功能测试工具条上选择测试脚本录制按钮，就会启动测试用例的脚本实现过程。</p>
				<p>
					如图二所示，在脚本录制的&quot;选择脚本资产&quot;对话框中，用户可以选择预定义好的公用测试对象图和公用测试数据池，也可以选择在脚本录制过程中生成私有测试对象图和数据池。测试对象图是IBM用来解决测试脚本在不同被测版本间，成功回放的关键技术，它为测试脚本的重用提供了重要保证；而测试数据池是IBM用来实现数据驱动的自动化功能测试的重要手段，使用智能化的数据驱动测试向导，测试脚本的参数化几乎变得易如反掌。</p>
				<p>
					图二、&quot;选择脚本资产&quot;对话框<br />
					<img alt="图二、选择脚本资产对话框" border="0" height="372" src="/uploads/allimg/111213/094F2E07-1.jpg" width="520" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /></p>
				<p>
					如图三所示，在功能测试的录制监视窗口，测试员可以根据提示启动被测应用系统，执行测试用例中规定的测试步骤，实现测试脚本的录制。在测试脚本录制过程中，测试员可以根据需要插入验证点和数据驱动的测试脚本，验证点是在指令中比较实际结果和预期结果的测试点，自动化功能测试工具正是通过它实现对被测系统功能需求的验证。</p>
				<p>
					图三、测试脚本录制窗口<br />
					<img alt="图三、测试脚本录制窗口" border="0" height="258" src="/uploads/allimg/111213/094F2LF-2.jpg" width="268" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /></p>
				<p>
					完成脚本录制过程以后，RFT会自动生成用工业标准语言Java描述的测试脚本，如下所示：</p>
				<br />
				　
				<table bgcolor="#<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>cccc" border="1" cellpadding="5" cellspacing="0" id="table2" width="100%">
					<tbody>
						<tr>
							<td>
								<pre>
<code class="content">
import resources.ThirdwithDatapoolHelper;
import com.<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/" target="_blank" >rational</A></STRONG>.test.ft.*;
import com.rational.test.ft.object.interfaces.*;
import com.rational.test.ft.script.*;
import com.rational.test.ft.value.*;
import com.rational.test.ft.vp.*;
/**
 * Description   : Functional Test Script
 * @author ndejun
 */
public class ThirdwithDatapool extends ThirdwithDatapoolHelper
{
	/**
	 * Script Name   : &lt;b&gt;ThirdwithDatapool&lt;/b&gt;
	 * Generated     : &lt;b&gt;2005-4-17 15:22:36&lt;/b&gt;
	 * Description   : Functional Test Script
	 * Original Host : WinNT Version 5.1  Build 2600 (S)
	 * 
	 * @since  2005/04/17
	 * @author ndejun
	 */
	public void testMain(Object[] args) 
	{
		
		startApp(&quot;ClassicsJavaB&quot;);
		
		// Frame: ClassicsCD
		classicsJava(ANY,MAY_EXIT).close();
	}
}
</code></pre>
							</td>
						</tr>
					</tbody>
				</table>
				<p>
					基于Java的测试脚本，为高级测试软员提高了更强大的编程和定制能力，测试员甚至可以通过在Helper类中加入各种客户化脚本，实现各种高级测试功能。</p>
				<p>
					<span class="atitle3">3.2 使用RFT轻松实现数据驱动的软件测试</span><br />
					RFT具有基于向导（Wizards）的数据驱动的功能测试能力。在功能测试脚本的录制过程中，如图四所示，我们可以方便选择被测应用图形界面上的各种被测对象，进行参数化，通过生成新的数据池字段或从数据池中选择已存在数据字段，实现数据驱动的功能回归测试。</p>
				<p>
					图四、数据驱动的功能测试<br />
					<img alt="图四、数据驱动的功能测试" border="0" height="490" src="/uploads/allimg/111213/094F221W-3.jpg" width="496" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /></p>
				<p>
					在生成测试脚本的同时，RFT还能够帮助测试员在验证点中使用正则表达式或使用数据驱动的方法建立动态验证点。动态验证点用来处理普通验证点的期望值随着输入参数不同而发生变化的情况。在下面的例子中，如图五所示，订单总金额会随着购买商品数量的不同而变化，通过数据驱动的功能测试方法，测试员首先要对购买的商品数量和订单总金额进行参数化，然后编辑验证点中的期望值，将其用数据池中的对应订单总金额代替，这样验证点中的总金额就随着购买商品数量的不同而得出正确的总金额。通过简单操作、无需任何编程，测试员就可以很方便地实现动态验证点的功能。</p>
				<p>
					图五、生成动态验证点<br />
					<img alt="图五、生成动态验证点" border="0" height="333" src="/uploads/allimg/111213/094F2K61-4.jpg" width="623" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /></p>
				<p>
					此外，测试员还可以通过在验证点中使用正则表达式，建立更加灵活的验证点，保证测试脚本的重用性。</p>
				<p>
					图六、正则表达式在验证点中的应用<br />
					<img alt="图六、正则表达式在验证点中的应用" border="0" height="314" src="/uploads/allimg/111213/094F24C0-5.jpg" width="484" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /></p>
				<p>
					<span class="atitle3">3.3 提供多种专利技术，提高脚本的可维护性</span><br />
					使用IBM Rational Functional Test工具进行Java和Web应用<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csgl/xtcs/" target="_blank" >系统测试</A></STRONG>时，标准Java的测试脚本语言，为测试脚本的可重用性和脚本能力提供了第一层保证。此外，通过维护&quot;测试对象图&quot;，IBM为测试员提供了不用任何编程就可以实现测试脚本在不同的被测系统版本间的重用能力。&quot;测试对象图&quot;分为两种，一种是公用&quot;测试对象图&quot;，它可以为项目中的所有测试脚本使用；另一种是私有&quot;测试对象图&quot;，它只被某一个管理的测试脚本所使用。在软件开发的不同版本间，开发员会跟据系统需求的变化，修改被测系统和用于构建被测系统的各种对象，所以测试脚本在不同的版本间进行回归测试时经常会失败。因此，通过维护公用&quot;测试对象图&quot;，如图七所示，测试员可以根据被测应用系统中对象的改变，更新测试对象的属性值及对应权重，这样在不修改测试脚本的前提下，就能使原本会失败的测试脚本回放成功。同时，为了方便测试员对测试对象图的修改和维护能力，RFT还提供了强大的查询和查询定制能力，帮助测试脚本维护人员快速找到变化的测试对象，进行修改和维护工作。</p>
				<p>
					图七、测试对象图的维护<br />
					<img alt="图七、测试对象图的维护" border="0" height="379" src="/uploads/allimg/111213/094F24944-6.jpg" width="612" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /></p>
				<p>
					其次，IBM提供的ScriptAssurance专利技术，使测试员能够从总体上改变工具对测试对象变更的容忍度，在很大程度上提高了脚本的可重用性。ScriptAssurance技术主要使用以下两个参数：脚本回放时，工具所容忍被测对象差异的最大门值和用于识别被测对象的属性权重。使用这种技术，测试员可以通过Eclipse的首选项设定脚本回放的容错级别，即门值，如图八和图九所示：</p>
				<p>
					图八、IBM专利技术：ScriptAssurance容错级别设定<br />
					<img alt="图八、IBM专利技术：ScriptAssurance容错级别设定" border="0" height="350" src="/uploads/allimg/111213/094F2D62-7.jpg" width="604" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /></p>
				<p>
					点击高级，能够看到各种具体的可接受的识别门值。</p>
				<p>
					图八、ScriptAssurance门值设定<br />
					<img alt="图八、ScriptAssurance门值设定" border="0" height="374" src="/uploads/allimg/111213/094F241R-8.jpg" width="623" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /></p>
				<p>
					其次，测试员可以根据被测对象实际更改情况，在测试对象图中（如图七所示）修改用于回放时识别被测对象的属性及其权重。在测试脚本回访时，测试对象的识别分数将由以下公式计算得出：</p>
				<br />
				　
				<table bgcolor="#cccccc" border="1" cellpadding="5" cellspacing="0" class="content" id="table3" width="100%">
					<tbody>
						<tr>
							<td height="106">
								<pre>
<code>
int score = 0;
for ( int i = 0; i &lt; property.length; ++i )
score += (100 - match(property[i])) * weight;
</code></pre>
							</td>
						</tr>
					</tbody>
				</table>
				<p>
					其中，match()将根据属性的符合程度返回0～100之间的值，完全符合返回100，完全不符合返回0。</p>
				<p>
					测试脚本回放成功与否则取决于：识别得分 &lt; 识别门值。通过这一技术，如图十所示，通过设置恰当的ScriptAssurance门值和为用于识别对象的属性设置合适的权重，即使在两个回归测试的版本间测试对象有多个属性不同，对象仍有可能被正确识别，脚本仍有可能回放成功。这为测试脚本的重用提供了最大程度的灵活性。</p>
				<p>
					图十、ScriptAssrance技术保证脚本的重用<br />
					<img alt="图十、ScriptAssrance技术保证脚本的重用" border="0" height="254" src="/uploads/allimg/111213/094F261L-9.gif" width="576" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /></p>
				<p>
					<span class="atitle3">3.4 与其它生命周期管理软件的完美集成</span><br />
					IBM Rational的自动化功能测试工具基于Eclipse平台，提供了和<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求管理</A></STRONG>工具（RequisitePro）、建模工具、代码级测试工具和变更及<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/pzgl/" target="_blank" >配置管理</A></STRONG>工具（<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearquest/" target="_blank" >ClearQuest</A></STRONG>和<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >ClearCase</A></STRONG>）的完美集成，这使得系统测试人员能够和整个软件开发团队在同一个软件平台上，实现系统功能测试，完成测试脚本的配置管理和缺陷追踪。</p>
				<p>
					<span class="atitle2">4 小结</span><br />
					如果一种软件工具能够在提供强健的自动化测试脚本录制和自动化测试能力的同时，很好地解决测试脚本的可维护性、大批量数据驱动的软件测试和整个软件开发生命周期的集成问题，它无疑为降低软件测试的质量成本提供了重要保证，而IBM Rational Functional Tester正是这样的工具，它的出现必将使我们的测试生活变得更加美好！</p>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#]]></description>
    <pubDate>Tue, 13 Dec 2011 09:41:32 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111213/094F23I1-0-lp.jpg</subImagePath>
     <category>Robot</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[消除识别测试对象过程中的二义性情形]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/2011/1213/203755.html</link>
    <description><![CDATA[<table border="0" cellpadding="0" cellspacing="0" class="content" id="table1" width="477">
	<tbody>
		<tr>
			<td class="left-nav-highlight">
				本文内容包括：</td>
		</tr>
		<tr class="left-nav-child-highlight">
			<td>
				<ul>
					<li>
						前提条件</li>
					<li>
						Rational Functional Tester 项目结构的概述 </li>
					<li>
						快速浏览一下 find() 方法</li>
					<li>
						导航基于路径的对象识别</li>
					<li>
						更好测试对象识别的建议 </li>
					<li>
						<STRONG><A href="http://www.ltesting.net/ceshi/down" target="_blank" >下载</A></STRONG></li>
					<li>
						参考资料 </li>
				</ul>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　IBM&reg; Rational&reg; Functional Tester 为测试人员提供了一个测试对象识别框架以及一个简单的用户界面，以执行基于 GUI 的测试脚本。但是，在有些条件下，例如测试一个基于 Eclipse 的程序，您可能会发现测试的 GUI 中全是二义性情形的测试对象。这些对象拥有几乎一样的属性，只有轻微的差异。很难直接指定目标对象属性的模式以及识别对象。识别的结果可能包含有多个二义性的类似对象，从而导致识别失败。本文向您介绍了怎样消除这些二义性的情况，并给出了一些指导以执行灵活且轻松的维护性测试脚本。</p>
<p>
	　　前提条件</p>
<p>
	　　安装 IBM&reg; Rational&reg; Functional Tester V7 版本。</p>
<p>
	　　Rational Functional Tester 项目结构的概述</p>
<p>
	　　导入范例 Rational Functional Tester 项目(查看 下载)。您将会看到一个名为 BaseCase 的脚本以及一个名为 util 的文件夹。</p>
<p>
	　　通过选择 Window &gt; Open Perspective &gt; Java 来切换至 Java&trade; 视图。您将会看到以下的三个包：</p>
<p>
	　　(default package)</p>
<p>
	　　resources</p>
<p>
	　　util</p>
<p>
	　　BaseCase 脚本位于默认的包中，其中还有它的辅助类 BaseCaseHelper ，以及与 Resources 包中脚本有关的其他配置文件。这两个包在 Functional Test 视图下看不到。您创建了 util 包，以及包中的类。在接下来的章节中，您将会使用到这个框架(见于图 1)。</p>
<p>
	　　图 1. Rational Functional Tester 项目的结构</p>
<center>
	<img alt=" Java Perspective 下的包 " border="1" height="320" src="/uploads/allimg/111213/0940201632-0.gif" width="400" /></center>
<p>
	　　快速浏览一下 find() 方法</p>
<p>
	　　建议您在 getMappedTestObject() 方法不能使用时，使用 find() 方法来找到一个测试对象。列表 1 中的代码显示了 find() 方法的结构。</p>
<p>
	　　列表 1. 找到方法结构</p>
<table border="0" cellpadding="0" cellspacing="0" id="table10" width="100%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="content">
// Finds all candidates that match given search criteria starting at this TestObject
public TestObject[] find(Subitem properties);</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　find() 方法通过将测试对象的特定属性，与给定的标准相比较以找到一系列的候选对象。您可以通过代表属性的名字/值，或者包含有一个或者多个匹配字符串来搜索一个测试对象。如果使用默认的 getMappedTestObject() 方法不能识别一个测试对象，那么您可以首先定位它的父类，然后通过访问父类的 find() 方法来找到目标测试对象。显然，find() 方法提供了可观的便利。脚本不再取决于对象映射。搜索候选测试对象的结果是可预测的，因此也是可靠的。您可以通过对象的属性值来找到一个测试对象，这些属性值可能是一个简单的文本。维护脚本起来会更加容易。</p>
<p>
	　　但是，如果 getMappedTestObject() 方法不可行的话，find() 方法不会包含所有的事例。不会总有明显系列的属性值会匹配。find() 方法取决于明显系列的属性值。因此，如果测试对象没有这样一系列的属性，那么这种方法就不会正常地发挥其功能。但是我们可以在返回的数组中一个个地试一下测试对象，这并不是一个聪明的办法。有时，甚至很难找到测试对象可识别的父类，所以搜索必须从最顶层开始，例如从窗口开始。这就会降低测试对象的可识别性。</p>
<p>
	　　导航基于路径的对象识别</p>
<p>
	　　考虑一下 find() 以及 getMappedTestObject() 方法的缺陷，您需要另外一个方法来解决 Rational Functional Tester 对象识别中的二义性情形。在本文中，我们介绍了基于路径导航方法，来找到目标测试对象。我们将会使用程序 ClassicsJavaA 作为一个范例。为了让事情变得更加简单，我们假设 Place Order 按钮就是要找的测试对象。</p>
<p>
	　　图 2. 范例程序的主窗口</p>
<center>
	<img alt="控制 Main 窗口中的图片和按钮" border="1" height="484" src="/uploads/allimg/111213/0940202b3-1.jpg" width="541" /></center>
<p>
	　　在记录 Place Order 按钮的点击操作之后，您会得到图 3 中对象映射的以下层级结构。您可以看到 Place Order 按钮是框架的子部分。框架会作为主窗口来显示，而且它就是 Place Order 按钮的位置所在。当然，在本例中，您可以简单使用 find() 方法来定位按钮。但是，我们将会尝试另外一种方法来解决这个问题。</p>
<p>
	　　图 3. 对象映射的层级结构</p>
<center>
	<img alt="对象映射内的按钮测试对象 " border="1" height="321" src="/uploads/allimg/111213/094020J44-2.jpg" width="445" /></center>
<p>
	　　对基于导航对象识别的介绍</p>
<p>
	　　有时测试人员会通过可见的线索来搜索测试的对象，例如关系中的相对位置。例如，您可能会通过它与文件夹封面图片的相对位置来找到 Place Order 按钮。与之类似，对于一个给定的测试对象，叫做锚对象，您可以使用 Rational Functional Tester API 来找到带有给定路径的任何对象。再次使用上面的例子，您可以通过找到对象附近的位置、文件夹的图片以及特定路径来找到 Place Order 按钮。这里所谓的术语&ldquo;路径&rdquo;是指在对象映射中将一个对象节点移动到另一个上时的逻辑距离。</p>
<p>
	　　通过对象映射来进行导航</p>
<p>
	　　在 Private Test Object Map for Script BaseCase 窗口中，您知道 Place Order 按钮是主框架的子类。显然，该对象映射并 没有 包含主框架中所有的构件。按照以下步骤来得到对象映射树的大致轮廓：#p#分页标题#e#</p>
<p>
	　　点击 Test Object 然后在主窗口的菜单上点击 Insert Object(s) 以打开向导对话框。</p>
<p>
	　　使用 Object Finder 来强调主框架，然后选中它。</p>
<p>
	　　选择 Include all available objects on this window 然后点击 Finish 。</p>
<p>
	　　如图 4 所示，现在您可以看到添加至对象映射的主框架的更多子节点。</p>
<p>
	　　重点：</p>
<p>
	　　尽管您选择了&ldquo;include all&rdquo;选项，该选项并没有 包含主框架的所有子节点。该对象映射只能帮助您知道 Place Order 按钮的位置。</p>
<p>
	　　图 4. 对象影响更加具体的层级结构</p>
<center>
	<img alt="添加的测试对象拥有多个附属对象  " border="1" height="377" src="/uploads/allimg/111213/094020GK-3.jpg" width="449" /></center>
<p>
	　　您可以使用另外一种工具，来找到主框架的所有子节点。实际上，您刚刚已经使用了它。它就是 Insert Object(s) 向导对话框(图 4)。使用这个向导，您就可以看到所有的 可映射对象。按照以下的步骤来定位 Place Order 按钮。</p>
<p>
	　　在主窗口中选择 Test Object &gt;Insert Object(s) 以重新打开向导对话框(图 5)。</p>
<p>
	　　对于 Selection Method，选择 Test Object Browser 。</p>
<p>
	　　找到 Place Order 按钮，根据上面生成的测试对象映射给出的层级关系中的暗示进行操作。</p>
<p>
	　　图 5. 测试对象浏览器</p>
<center>
	<img alt="对象映射中按钮的确切位置 " border="1" height="571" src="/uploads/allimg/111213/0940204401-4.jpg" width="465" /></center>
<p>
	　　根据 Test Object Browser，您可以在测试对象映射中看到许多的对象。对象浏览器中的对象的顺序，与测试对象映射中的顺序不同。但是，测试对象映射仅仅给了您一点暗示，以帮助您在对象浏览器中找到当前的对象。通过再一次按照前面介绍的步骤进行操作，您可以轻松找到文件夹的图形节点。然后您可以找到从图形节点到按钮节点的确切路径(见于图 6)。</p>
<p>
	　　图 6. 从图形到 Place Order 按钮的路径</p>
<center>
	<img alt="对象映射中从图片到 Place Order 的路径 " border="1" height="405" src="/uploads/allimg/111213/0940205495-5.gif" width="329" /></center>
<p>
	　　如图 6 所示，从图形节点到按钮节点的路径如下所述。注意子类的索引在这里非常重要。</p>
<p>
	　　首先，将三个层次移动到父层次上。</p>
<p>
	　　然后移动主框架的 FIFTH 。</p>
<p>
	　　使用 API 来执行导航操作</p>
<p>
	　　现在您已经知道，怎样找到两个测试对象之间的路径。在本部分中，您将会学到怎样使用 API 来自动定位带有给定路径的目标测试对象。这项任务所需的 API 在列表 2 进行了总结。</p>
<p>
	　　列表 2. 定位测试对象所需的 API</p>
<table border="0" cellpadding="0" cellspacing="0" id="table14" width="100%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="content">
				/**
* This method returns an array of references to the object&#39;s mappable children.
* The references to the objects should be released by calling he unregister method.
* If the object has no mappable children, a 0-length array will be returned.
**/
TestObject[] testObject.getMappableChildren();

/**
* This method returns a reference to the parent object that appears in the object map.
* The references to the objects should be released by calling he unregister method.
**/
TestObject testObject.getMappableParent();

/**
* This method returns the topmost mappable parent object that appears in the object map.
* The references to the objects should be released by calling he unregister method.
**/
TestObject testObject.getTopMappableParent();</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　至于简单性，我们并不使用 unregister 方法来注销迭代的测试对象。ObjectFinder 类是含有所有导航操作的辅助类。图 7 中的 UML 显示了这些类之间的关系。注意出于稳定性考虑，TestObjectNotLocatedException 必须源自于 RuntimeException 。</p>
<p>
	　　图 7. 类与 UML 之间的关系</p>
<center>
	<img alt="类 ObjectFinder 是外观类 " border="1" height="355" src="/uploads/allimg/111213/094020H34-6.gif" width="416" /></center>
<p>
	　　考虑一下路径范例，列表 3 向您展示了怎样书写代码以找到 Place Order 按钮：</p>
<p>
	　　列表 3. 找到 Place Order 按钮的对象</p>
<table border="0" cellpadding="0" cellspacing="0" id="table15" width="100%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="content">
				// This method is used to find the button Place Order
public GuiTestObject PlaceOrder() throws TestObjectNotLocatedException{
	// The path we specified to find the button from the album image
	// First move up 3 times, then move down to the fifth child
	String pathString = &quot;P3;C5&quot;;
	Path path = null;
	try{
		path = new Path(pathString);
	}catch(IllegalPathStringException illegalpath){
		logError(illegalpath.getMessage());
	}
	
	// Assume that the imageAlbum() is a<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >lr</A></STRONG>eady found
	return new GuiTestObject(ObjectFinder.locateTestObject(imageAlbum(), path));
}
</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　首先我们指定一个路径字符串，它描述了从图标到 Place Order 按钮的路径。然后我们使用 ObjectFinder 类来定位我们想要的目标测试对象。</p>
<p>
	　　更好测试对象识别的建议</p>
<p>
	　　我们已经看到了，怎样以各种方法来找到一个测试对象。我们可以使用默认的方法来找到测试对象。我们还可以使用 find() 方法来找到匹配属性/值的测试对象。而且我们可以定位带有给定对象及路径的测试对象。在本段中，我们将会讨论怎样选择正确的方法，以及怎样组织 Rational Functional Tester 对象的源代码。#p#分页标题#e#</p>
<p>
	　　选择合适的对象识别方法</p>
<p>
	　　显然，默认的方法拥有丰厚的工具支持。Rational Functional Tester 提供了强大的工具，例如 Test Object Map 和 Script Assure ，可以轻松解决脚本<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>的复杂性问题，并降低开发所需的时间。但是，有一些脚本开发员所抱怨的正是简单性。他们认为工具隐藏了一些他们想要控制的细节。find() 方法是灵活和简单的。它使脚本开发员能够更强地控制测试脚本。这就是为什么在脚本开发中它得到广泛的应用，以替换默认方法的原因。基于导航对象识别方法非常有效和简单。有一点非常重要：它几乎可以在任何场所使用。但是，使用 UI 结构还是十分敏感的。</p>
<p>
	　　我们将会向您展示怎样使用 find() 方法，以及替代性的基于导航方法，同时享受使用工具所带来的便捷之处。</p>
<p>
	　　脚本组织的建议</p>
<p>
	　　回忆一下 Rational Functional Tester 对象结构的第一部分。我们知道所有的对象搜索方法默认条件下都是在辅助类中执行。例如，搜索 Place Order 按钮的默认方法如列表 4 所示。</p>
<p>
	　　列表 4. 默认的 Place Order 按钮代码</p>
<table border="0" cellpadding="0" cellspacing="0" id="table19" width="100%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="content">
public abstract class BaseCaseHelper extends RationalTestScript {
	/**
	* PlaceOrder: with default state.
	* .class : <STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcskfyy/java/" target="_blank" >java</A></STRONG>x.swing.JButton
	* a<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>essibleContext.accessibleName : Place Order
	* name : placeOrderButton2
	* .classIndex : 0
	*/
	protected GuiTestObject placeOrder() {
		return new GuiTestObject(getMappedTestObject(&quot;placeOrder&quot;));
	}
	
	/**
	* Schubert4_14Jpg: with default state.
	* .class : javax.swing.JLabel
	* iconDescription : Schubert4_14.jpg
	* .classIndex : 2
	*/
	protected GuiTestObject schubert4_14Jpg() {
		return new GuiTestObject(
			getMappedTestObject(&quot;schubert4_14Jpg&quot;));
	}
}</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　然后您创建一个辅助类，该类扩展了默认的辅助类并超越了默认的方法。它如列表 5 中的代码所示。</p>
<p>
	　　列表 5. 创建辅助类的代码</p>
<table border="0" cellpadding="0" cellspacing="0" id="table20" width="100%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="content">
public class BaseCaseUserHelper extends BaseCaseHelper {
// This method is used to find the button Place Order
public GuiTestObject PlaceOrder() throws TestObjectNotLocatedException{
		// The path we specified to find the button from the album image
		// First move up 3 times, then move down to the fifth child
		String pathString = &quot;P3;C5&quot;;
		Path path = null;
		try{
			path = new Path(pathString);
		}catch(IllegalPathStringException illegalpath){
			logError(illegalpath.getMessage());
		}
		
		// schubert4_14Jpg() is object for the cover image
		return new GuiTestObject(
			ObjectFinder.locateTestObject(schubert4_14Jpg(), path));
	}
}
			</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　最后，让脚本类扩展用户定义的类。通过这种方法，您不需要编辑任何已存在的对象搜索方法。您只是超越了它们，将已存在的对象搜索方法的最强部分结合起来。</p>
<p>
	　　下载</p>
<table border="1" cellpadding="2" cellspacing="0" class="content" id="table24" width="100%">
	<tbody>
		<tr>
			<th scope="col">
				描述</th>
			<th scope="col">
				名字</th>
			<th scope="col">
				大小</th>
			<th scope="col">
				下载方法</th>
		</tr>
		<tr>
			<td class="tb-row" scope="row">
				<div align="center">
					示例脚本</div>
			</td>
			<td nowrap="nowrap">
				<div align="center">
					RBAT_Impl.zip</div>
			</td>
			<td nowrap="nowrap">
				<div align="center">
					10KB</div>
			</td>
			<td nowrap="nowrap">
				<div align="center">
					<b>HTTP</b></div>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　参考资料</p>
<p>
	　　学习</p>
<p>
	　　查看 Rational Functional Tester 信息中心，在那里，您也可以查看一段短的 演示<STRONG><A href="http://www.ltesting.net/ceshi/video" target="_blank" >视频</A></STRONG>。</p>
<p>
	　　调查 Rational Functional Tester Plus，它是一个软件应用程序测试包。</p>
<p>
	　　参与 developerWorks 上 的 Rational Functional Tester 学习路线图，介绍更深入的信息。</p>
<p>
	　　在 IBM Rational 软件交付平台 中了解其它应用程序，包括适用于并行开发和地域分布式团队的协作工具，以及用于架构管理、资产管理、变更和发布管理，集成<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求管理</A></STRONG>、过程和组合管理，和质量管理。您可以在 IBM Rational 在线文档中心 查找产品手册、安装指南以及其它文档。</p>
<p>
	　　访问 developerWorks 上的 Rational 专区，了解有关 Rational 软件交付平台产品的技术资源和最佳实践。</p>
<p>
	　　查找 Rational 基于计算机，基于 Web，以及在线指导课程。训练您的技能，并学习更多有关 Rational 工具的课程，包括入门级和高级课程。在此目录上的课程可进行购买，包括基于计算机的和基于 Web 的培训。此外，一些&ldquo;入门&rdquo;课程是免费的。</p>
<p>
	　　订阅 IBM developerWorks 时事通讯，获得有关最佳的 developerWorks 教程、文章、下载、社区活动、<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlzs/" target="_blank" >网络</A></STRONG>广播和事件的每周更新。</p>
<p>
	　　浏览 技术书店，获得有关这些和其它技术主题的书籍。</p>
<p>
	　　获得产品和技术</p>
<p>
	　　下载免费的 IBM Rational Functional Tester 试用版。</p>
<p>
	　　下载 IBM Rational 软件的试用版。</p>
<p>
	　　下载这些 IBM 产品评估版，并着手使用来自于 DB2&reg;，Lotus&reg;，Tivoli&reg;，以及 <STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/zjj/websphe/" target="_blank" >WebSphere</A></STRONG>&reg; 的应用程序开发工具和<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/zjj/" target="_blank" >中间件</A></STRONG>产品。</p>
<p>
	　　讨论#p#分页标题#e#</p>
<p>
	　　参与<STRONG><A href="http://bbs.ltesting.net/" target="_blank" >论坛</A></STRONG>讨论。</p>
<p>
	　　参与 developerWorks 上的功能和 GUI 测试讨论区，您可以讨论并询问有关 Rational Functional Tester 和一般性测试主题的问题。</p>
<p>
	　　查看 developerWorks <STRONG><A href="http://blog.ltesting.net/" target="_blank" >博客</A></STRONG>，并加入 developerWorks 社区。</p>
]]></description>
    <pubDate>Tue, 13 Dec 2011 09:39:13 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111213/0940201632-0-lp.gif</subImagePath>
     <category>Robot</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[配置 Rational Functional Tester 在 Linux 上运行]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/2011/1213/203754.html</link>
    <description><![CDATA[<table border="0" cellpadding="0" cellspacing="0" class="content" id="table1" width="528">
	<tbody>
		<tr>
			<td class="left-nav-highlight">
				本文内容包括：</td>
		</tr>
		<tr class="left-nav-child-highlight">
			<td>
				<ul>
					<li>
						引言</li>
					<li>
						操作系统安装以及配置 </li>
					<li>
						安装 Firefox 2.0 和 Rational Functional Tester</li>
					<li>
						配置 Firefox 以和 Rational Functional Tester 协同运行</li>
					<li>
						测试 Firefox</li>
					<li>
						总结</li>
					<li>
						参考资料 </li>
				</ul>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　IBM&reg; Rational&reg; Functional Tester 是一种自动化<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>，设计时是为了能够在 Microsoft&reg; Windows&reg; 以及 Linux&reg; 操作系统上运行。当您在 Microsoft Windows 操作系统上安装 IBM Rational Functional Tester 时，测试工具已经能够使用了。但是，当您在 Linux 操作系统上安装工具时，您必须配置该程序，以便使用该测试自动化功能。本文向您介绍了需要执行的一些操作，以使用 IBM Rational Functional Tester 在 Linux 平台上测试基于 Web 的程序。</p>
<p>
	　　引言</p>
<p>
	　　基于 Web 程序的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/" target="_blank" >手工测试</A></STRONG>以及<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csgl/hgcs/" target="_blank" >回归测试</A></STRONG>是十分费时的，有时甚至是不断重复的。Rational Functional Tester 通过将一些手动的步骤自动化，并帮助您创建回归测试中使用的测试套装来提高效率。尽管 Rational Functional Tester 可以在 Microsoft Windows 以及 Linux 操作系统上使用，但是在 Linux 操作系统上安装和配置，不如在 Windows 上安装那么容易。有一些用户不会使用 Java &trade;插件，激活浏览器，或者注册对象。但是，使用 Rational Functional Tester 以在 Linux 平台上运行是可行的，通过执行一些额外的步骤，来配置环境以进行测试自动化。</p>
<p>
	　　本篇文章假设您已经熟悉了 Rational Functional Tester 以及测试自动化和对象识别的概念。如果您想要得到更多关于这个话题的信息，可以查看本文的 References 部分。</p>
<p>
	　　在本文中讨论了以下软件版本：</p>
<p>
	　　Rational Functional Tester 8.0</p>
<p>
	　　Red Hat Enterprise Linux 5.3</p>
<p>
	　　Firefox 2.0</p>
<p>
	　　操作系统安装以及配置</p>
<p>
	　　使用 Red Hat Enterprise Linux 5.3 DVD 来在测试电脑上安装操作系统。在安装完成之后，验证您所安装软件的版本：</p>
<p>
	　　输入以下这条命令：</p>
<p>
	　　# cat /etc/redhat-release</p>
<p>
	　　验证电脑的响应：</p>
<p>
	　　Red Hat Enterprise Linux Server release 5.3 (Tikanga)</p>
<p>
	　　您需要安装 32 位的 libXp 库，以让 Rational Functional Tester 图形化界面正常工作。输入以下命令：</p>
<p>
	　　# yum install libXp.i386</p>
<p>
	　　安装 Firefox 2.0 和 Rational Functional Tester</p>
<p>
	　　默认条件下 Red Hat Enterprise Linux 5.3 会与 Firefox 3.0 一起安装。但是，Rational Functional Tester 8.0 并不支持 Firefox 3.0。您必须删除它，然后安装 Firefox 2.0。Rational Functional Tester 同样需要 32 位版本的 Firefox，因为测试工具使用的 Java 浏览器插件是 32 位的。</p>
<p>
	　　从 http://www.rpmfind.net/ 或者 http://rpm.pbone.net/ 下载一个 32 位 Firefox 2.0 .rpm 文件。Fedora Core 8 .rpm 文件同样可以在 Red Hat Enterprise Linux 5.3 操作系统上运行，这样如果您不能找到一个对于 Red Hat Enterprise Linux 特定的文件，那么您可以使用它们。在写作本文时，最新发布的版本是 2.0.0.18 版本。您可能需要一个额外的 .rpm 文件，这取决于您所使用的 Firefox .rpm 文件。</p>
<p>
	　　在您安装 Firefox 2.0 之前，作出以下几条变更：</p>
<p>
	　　输入以下这条命令来删除 Firefox 3.0：</p>
<p>
	　　&ndash; yum erase firefox</p>
<p>
	　　输入以下这条命令，来安装 libgnomeui 32 位的版本以及附属包：</p>
<p>
	　　&ndash;yum install libgnomeui.i386</p>
<p>
	　　xu<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >lr</A></STRONG>unner 包及其附属的包可能会与 Firefox 2.0 相冲突。通过输入以下这条命令来删除包。</p>
<p>
	　　&ndash;yum erase xulrunner</p>
<p>
	　　输入以下两条命令，来安装 Firefox .rpm 文件以及系统标签的 .rpm 文件：</p>
<p>
	　　# rpm -ivh firefox-2.0.0.18-1.fc8.i386.rpm</p>
<p>
	　　# rpm -ivh fedora-bookmarks-10-1.noarch.rpm</p>
<p>
	　　通过输入以下命令来验证安装的版本：</p>
<p>
	　　# firefox &ndash;version</p>
<p>
	　　安装成功的系统响应该是：</p>
<p>
	　　Mozilla Firefox 2.0.0.18, Copyright (c) 1998 - 2008 mozilla.org</p>
<p>
	　　如果功能性的测试工具没有安装，那么在您安装 Firefox 2.0 之后，您还需要使用安装介质的硬盘 1 中的 launchpad.sh 脚本，来安装 Rational Functional Tester。</p>
<p>
	　　配置 Firefox 以和 Rational Functional Tester 协同运行</p>
<p>
	　　为了对 Rational Functional Tester 配置 Firefox，向 Firefox 添加 Java 浏览器插件。然后向 Rational Functional Tester 环境添加 Firefox。</p>
<p>
	　　向 Firefox 添加 Java 浏览器插件</p>
<p>
	　　典型的 Firefox 安装并没有包含 Java 浏览器插件。没有插件，Rational Functional Tester 不能使用 Firefox。Rational Functional Tester 中的 Java <STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>员工具并没有包含插件的 32 位的版本。通过在 Firefox 插件目录中创建一个软性链接。在目录中插入以下这些链接：</p>
<p>
	　　# cd /usr/lib/firefox-2.0.0.18/plugins/</p>
<p>
	　　# ln -s /opt/IBM/SDP/jdk/jre/plugin/i386/ns7/libjavaplugin_oji.so libjavaplugin_oji.so</p>
<p>
	　　Firefox 中的 About Plug-ins 页面显示了安装的 Java 插件：</p>
<p>
	　　图 1. Firefox About Plug-ins 页面</p>
<center>
	<img alt=" About Plug-ins 页面列出了 Java 插件 " border="1" height="405" src="/uploads/allimg/111213/093K0C26-0.jpg" width="572" /></center>
<p>
	　　向 Rational Functional Tester 环境添加 Firefox#p#分页标题#e#</p>
<p>
	　　按照以下方法来向 Rational Functional Tester 添加 Firefox：</p>
<p>
	　　通过输入以下命令来启动 Rational Functional Tester：</p>
<p>
	　　# /opt/IBM/SDP/ft_starter</p>
<p>
	　　保持选中的默认工作区状态。</p>
<p>
	　　关闭打开的欢迎界面。</p>
<p>
	　　点击 Configure &gt; Enable Environments for Testing。</p>
<p>
	　　点击 Web Browsers &gt; Search &gt; Search in。</p>
<p>
	　　输入 /usr，并点击 Search。Rational Functional Tester 会找到 Firefox 2.0，并向浏览器的列表添加程序。</p>
<p>
	　　选择 Firefox 2.0 条目，并点击 Enable。</p>
<p>
	　　图 2. 搜索安装的浏览器</p>
<center>
	<img alt="搜索进度条打开了 " border="1" height="342" src="/uploads/allimg/111213/093K03222-1.jpg" width="572" /></center>
<p>
	　　点击 Test。浏览器会打开，显示一个带有 Click here to run diagnostic tests 单选按钮的页面。</p>
<p>
	　　点击单选按钮。一会儿过后，浏览器会显示以下信息： Browser Enablement Test Result: Passed!</p>
<p>
	　　关闭浏览器。</p>
<p>
	　　图 3. 成功的浏览器激活</p>
<center>
	<img alt="激活浏览器测试的结果 " border="1" height="404" src="/uploads/allimg/111213/093K02G8-2.jpg" width="572" /></center>
<p>
	　　带有以下信息的窗口会显示出来： Errors encountered when starting browser。不管这条信息，并点击 OK 以关闭该窗口。该出错信息的显示，是 Rational Functional Tester v8.0 已知会出现的问题。</p>
<p>
	　　点击 Apply 然后点击 Finish 以完成添加浏览器的操作。</p>
<p>
	　　图 4. 带有添加浏览器的 Enable Environments 窗口</p>
<center>
	<img alt=" Web Browsers 页面显示 Firefox 添加了 " border="1" height="342" src="/uploads/allimg/111213/093K063J-3.jpg" width="572" /></center>
<p>
	　　测试 Firefox</p>
<p>
	　　因为在花时间对程序进行复杂的测试之前，测试 Rational Functional Tester 与 Firefox 是怎样与一个简单的程序协调工作的。构建由三个主要任务组成的测试：</p>
<p>
	　　创建一个测试程序</p>
<p>
	　　创建一个测试项目以及测试项目映射</p>
<p>
	　　验证 Add Object 向导检测到浏览器对象</p>
<p>
	　　创建一个测试程序</p>
<p>
	　　创建一个简单的基于 Web 的程序：</p>
<p>
	　　在 Rational Functional Tester 中，点击 Configure &gt; Configure Applications for Testing。</p>
<p>
	　　点击 Add &gt; HTML Application。</p>
<p>
	　　输入以下的 URL 以载入一个简单的 HTML 页面：</p>
<p>
	　　file:////usr/lib/firefox-2.0.0.18/defaults/profile/bookmarks.html。</p>
<p>
	　　点击 Finish 以保存细节信息。</p>
<p>
	　　图 5. 添加至 Application Configuration Tool 窗口的测试 HTML 程序</p>
<center>
	<img alt=" Applications 列表包含了新程序 " border="1" height="350" src="/uploads/allimg/111213/093K030O-4.jpg" width="572" /></center>
<p>
	　　选择添加的条目，并点击 Run。Firefox 会随着显示的 bookmarks.html 页面一起打开。</p>
<p>
	　　创建一个测试项目以及测试对象映射</p>
<p>
	　　按照以下方法，来创建一个功能性的测试项目以及对象映射：</p>
<p>
	　　在 Rational Functional Tester 中，点击 File &gt; New &gt; Functional Test Project。</p>
<p>
	　　输入名字 TestProject1，并创建新的项目。</p>
<p>
	　　右击新的项目，并选择 Add Test Object Map。</p>
<p>
	　　输入名字 TestObjectMap1，并创建新的映射。</p>
<p>
	　　验证 Add Object 向导检测到了浏览器对象</p>
<p>
	　　验证您可以将浏览器中显示的对象添加到对象映射：</p>
<p>
	　　通过点击 Configure &gt; Configure Applications for Testing，以启动新的 Web 程序。</p>
<p>
	　　通过点击 Run，以选择 Web 程序。</p>
<p>
	　　打开新的对象映射，TestObjectMap1。</p>
<p>
	　　点击 Insert Test Object 以打开 Add Object 向导。</p>
<p>
	　　选择 Time-delayed test selection，并将定时器设置为 5 秒。</p>
<p>
	　　将鼠标在浏览器中 Web 页面上的链接上停留 5 秒钟。</p>
<p>
	　　链接将会以红色强调显示，并在 Add Object 向导中显示出来。</p>
<p>
	　　图 6. bookmarks.html 页面上的对象选择</p>
<center>
	<img alt=" bookmarks.html 页面及对象浏览器 " border="1" height="406" src="/uploads/allimg/111213/093K0EG-5.jpg" width="572" /></center>
<p>
	　　点击 OK，并确认对象映射包含了对象。</p>
<p>
	　　图 7. 带有添加对象的对象映射</p>
<center>
	<img alt="对象映射与 bookmarks.html-页面对象 " border="1" height="405" src="/uploads/allimg/111213/093K0HM-6.jpg" width="572" /></center>
<p>
	　　总结</p>
<p>
	　　当对象映射含有基于 Web 的项目时，您知道 Rational Functional Tester 与 Firefox 会在 Linux 上协同工作了。只需要额外的一点步骤，就可以让 Rational Functional Tester 在 Linux 操作系统上运行，以测试基于 Web 的程序。现在您已经可以测试更加复杂的基于 Web 的程序了。</p>
<p>
	　　参考资料</p>
<p>
	　　学习</p>
<p>
	　　访问 Rational Functional Tester 产品页面 和 developerWorks 上的 Rational Functional Tester 产品<STRONG><A href="http://www.ltesting.net/ceshi/zhuanti/" target="_blank" >专题</A></STRONG>。</p>
<p>
	　　从 Rational Functional Tester V8.0 发布说明 中获得更新信息。</p>
<p>
	　　阅读 Hello World: 学习如何使用 Rational Functional Tester 创建健壮和可重用的自动<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/" target="_blank" >功能测试</A></STRONG>。</p>
<p>
	　　阅读 使用IBM Rational Functional Tester 6.1 运行你的第一个功能回归测试。</p>
<p>
	　　查看 Rational Functional Tester 信息中心，在那里，您还可以查看一段短的 演示<STRONG><A href="http://www.ltesting.net/ceshi/video" target="_blank" >视频</A></STRONG>。</p>
<p>
	　　调查 Rational Functional Tester Plus，它是一个软件应用程序测试包。</p>
<p>
	　　参与 developerWorks 上 的 Rational Functional Tester 学习路线图，介绍更深入的信息。</p>
<p>
	　　在 IBM Rational 软件交付平台 中了解其它应用程序，包括适用于并行开发和地域分布式团队的协作工具，以及用于架构管理、资产管理、变更和发布管理，集成<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求管理</A></STRONG>、过程和组合管理，和质量管理。您可以在 IBM Rational 在线文档中心 查找产品手册、安装指南以及其它文档。#p#分页标题#e#</p>
<p>
	　　访问 developerWorks 上的 Rational 专区，了解有关 Rational 软件交付平台产品的技术资源和最佳实践。</p>
<p>
	　　查找 Rational 基于计算机，基于 Web，以及在线指导课程。训练您的技能，并学习更多有关 Rational 工具的课程，包括入门级和高级课程。在此目录上的课程可进行购买，包括基于计算机的和基于 Web 的培训。此外，一些&ldquo;入门&rdquo;课程是免费的。</p>
<p>
	　　查看 Rational Edge 中文版，获得了解高效软件开发背后概念的文章。</p>
<p>
	　　订阅 IBM developerWorks 时事通讯，获得有关最佳的 developerWorks 教程、文章、下载、社区活动、<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlzs/" target="_blank" >网络</A></STRONG>广播和事件的每周更新。</p>
<p>
	　　浏览 技术书店，获得有关这些和其它技术主题的书籍。</p>
<p>
	　　获得产品和技术</p>
<p>
	　　下载免费的 IBM Rational Functional Tester 试用版。</p>
<p>
	　　下载 IBM Rational 软件的试用版。</p>
<p>
	　　下载这些 IBM 产品评估版，并着手使用来自于 DB2&reg;，Lotus&reg;，Tivoli&reg;，以及 <STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/zjj/websphe/" target="_blank" >WebSphere</A></STRONG>&reg; 的应用程序开发工具和<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/zjj/" target="_blank" >中间件</A></STRONG>产品。</p>
]]></description>
    <pubDate>Tue, 13 Dec 2011 09:35:10 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111213/093K0C26-0-lp.jpg</subImagePath>
     <category>Robot</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[用Robot写Java代理]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/2011/1213/203753.html</link>
    <description><![CDATA[　　Rational <STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/" target="_blank" >Robot</A></STRONG>是通过录制用户操作进行功能，性能和<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/jrxcs/" target="_blank" >兼容性测试</A></STRONG>的自动化<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>。通过回放录制脚本进行功能和可靠性测试。本文主要介绍Rational Robot针对java程序和applets如何进行<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/" target="_blank" >功能测试</A></STRONG>。<br />
　　Rational Robot当前版本支持用以下类库<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcskfyy/java/" target="_blank" >Java</A></STRONG>程序和applet程序：<br />
　　Java Foundation Classes(JFCs)<br />
　　Sun的Swing 和 Abstract Windowing Toolkit(AWT)<br />
　　Sym<STRONG><A href="http://www.ltesting.net/ceshi/open/qtkycsgj/ant/" target="_blank" >ant</A></STRONG>ec的Visual Caf&eacute;<br />
　　Sitraka Software的JClass库<br />
　　还有一些Java类超出了Rational Robot支持的范围，但是需要注意的是这些超出Robot支持的Java类中的一些类继承自Rational Robot支持的类。测试人员可以通过编写Java代理来扩展Rational Robot识别对象的能力。使用Java扩展API，需要注意的是，这些代理只能够测试在SUN的JVM上运行的类，并可以运行在Netscape和IE上的程序和Applet。<br />
　　本文将讨论，Rational Robot怎样使用Java代理并且当需要第三方Java代理的时候怎么做。示范如何开发Java代理，怎样用Java扩展Api支持Rational软件。<br />
　　Rational Robot怎样用Java代理<br />
　　执行功能，性能或者可靠性测试的时候，Rational Robot通过AUT监控用户交互进而生成Rational的SQABasic脚本，不必管开发程序的语言是什么，当录制的脚本回放，他通过AUT再现用户的操作行为。测试Java程序和Applets的时候，SQABasic有一套定义好的图形界面(GUI)对象.<br />
　　表格一：展示了一组SQABasic 测试Java程序和Applect的GUI对象<br />
<table align="center" border="1" cellpadding="0" cellspacing="0" id="table1">
	<tbody>
		<tr>
			<td style="width: 142px; height: 30px">
				JavaMenu</td>
			<td style="width: 142px; height: 30px">
				JavaMenuItem</td>
			<td style="width: 142px; height: 30px">
				CheckBox</td>
			<td style="width: 142px; height: 30px">
				RadioButton</td>
		</tr>
		<tr>
			<td style="width: 142px">
				ComboBox</td>
			<td style="width: 142px">
				ComboListBox</td>
			<td style="width: 142px">
				Label</td>
			<td style="width: 142px">
				ListBox</td>
		</tr>
		<tr>
			<td style="width: 142px">
				ScrollBar</td>
			<td style="width: 142px">
				EditBox</td>
			<td style="width: 142px">
				TrackBar</td>
			<td style="width: 142px">
				TabControl</td>
		</tr>
		<tr>
			<td style="width: 142px">
				ProgressBar</td>
			<td style="width: 142px">
				JavaPanel</td>
			<td style="width: 142px">
				JavaWindow</td>
			<td style="width: 142px">
				JavaTree</td>
		</tr>
		<tr>
			<td style="width: 142px">
				JavaSplitPanel</td>
			<td style="width: 142px">
				JavaSplitter</td>
			<td style="width: 142px">
				JavaMenuBar</td>
			<td style="width: 142px">
				JavaObject</td>
		</tr>
		<tr>
			<td style="width: 142px">
				JavaCheckBoxMenuItem</td>
			<td style="width: 142px">
				PushButton</td>
			<td style="width: 142px">
				Toolbar</td>
			<td style="width: 142px">
				JavaListView</td>
		</tr>
		<tr>
			<td style="width: 142px">
				JavaMenuSeparator</td>
			<td style="width: 142px">
				JavaTable</td>
			<td style="width: 142px">
				JavaCanvas</td>
			<td style="width: 142px">
				&nbsp;</td>
		</tr>
		<tr>
			<td style="width: 142px">
				JavaPopupMenu</td>
			<td style="width: 142px">
				JavaTableHeader</td>
			<td style="width: 142px">
				&nbsp;</td>
			<td style="width: 142px">
				&nbsp;</td>
		</tr>
	</tbody>
</table>
　　这些SQABasic GUI对象表现为他们的属性和功能表现。这些功能定义允许Robot模拟用户操作和对象进行交互。Robot知道怎样处理SQABasic GUI对象。测试Java和applets，Java对象必须映射为SQABasic GUI对象。比如JFC 中的Jbutton组件需要映射为SQABasic 对象的PushButton。<br />
　　通过反射或者说反映，Rational Robot可以动态地决定加载到JVM中Java GUI组建的类、功能和属性。它使用包含在JavaClassMap.dat中的信息确定什么样的SQABasic对象可以映射到相关类，也可以确定使用什么样的代理与Java组建相互交互。<br />
　　Rational提供的JavaClass模板被放在项目目录下\TestDatastoe\DefaultTestScriptDataStore\TMS_scripts\dat JavaClassMap.dat信息格式如下：<br />
　　[SQABasic Object]<br />
　　Java GUI component=proxy<br />
　　图一描述的过程展现了Rational Robot是如何使用代理与Java应用程序交互的。对于Rational 所支持的Java代理类，包含在JavaClassMap.dat 里的信息在Robot内部有效。<br />
<center>
	<img alt="" border="1" height="208" src="/uploads/allimg/111213/0933544E8-0.jpg" width="521" /></center>
　　此过程是如下工作的<br />
　　1、 在录制的时候，Rational Robot侦查用户和AUT之间的交互;通过反省，他知道用户与什么样的控间的类交互。<br />
　　2、 Rational Robot使用JavaClassMap.dat文件或者使用Robot内部可接受的相似信息，去决定这个类映射到的SQABasic GUI对象和与Java组件相互影响的代理。<br />
　　3、 然后Rational Robot使用代理学习到关于Java组件的必要信息，生成适当的SQABasic代码。<br />
　　4、 为了回放已录制的代码，SQABasic代码被转化为Robot可调用的适当的函数或者代理类的函数列表。这些列表一次触发被测组件中的适当的函数。<br />
　　举个例子，模拟一个用户点击一个Java GUI组件(比如：Jbutton)，Rational Robot生成如下SQABasic命令：<br />
　　PushButton Click, recMethod<br />
　　这里的recMethod是AUT一个唯一可识别的按钮名称。同样的命令别用于所有的按钮，不管它使用什么语言开发的。<br />
　　什么时候需要第三方得Java代理<br />
　　如果被开发的应用程序使用任何明确的可支持标准Java GUI组件的类库，那么Rational支持的代理对于与Robot交互的应用程序就足够了。本文中所说的标准Java GUI组件是指类中可被引用的组件。Jbutton, Jtree和Jplanel都是JFCs中标准的Java GUI组件。#p#分页标题#e#<br />
　　如果客户化的类或者它的父类可以被映射到同一个SQABasic对象，那么使用这样的客户化标准Java GUI组件开发的应用程序也是不需要第三方Java代理的。举个例子，如果一个应用程序使用了BeechButton<br />
]]></description>
    <pubDate>Tue, 13 Dec 2011 09:32:17 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111213/0933544E8-0-lp.jpg</subImagePath>
     <category>Robot</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[在PB中如何使用软件测试工具rational teamtest]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/2011/1212/203750.html</link>
    <description><![CDATA[<p>
	　　jbgsn问：</p>
<p>
	　　其中有个<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/" target="_blank" >robot</A></STRONG>，不知道该怎么在PB中用做测试，哪位大侠指点一二。</p>
<p>
	　　kukoc答：</p>
<p>
	　　很简单啊，启动PB，启动robot，点击GUI图标开始录制，再运行PB程序，完成后停止录制，会自动生成GUI脚本，通过回放这些GUI脚本，可以达到<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/" target="_blank" >功能测试</A></STRONG>的目的。</p>
<p>
	　　还要学会用datapools</p>
<p>
	　　jbgsn又问：</p>
<p>
	　　基本摸索成功了，谢谢版主指点。:)</p>
<p>
	　　还有一个问题请教，我想让程序制动运行测试，并且用不同的数据，应该是用datapools，我也定义好了，但不知道怎样在GUI脚本调用。</p>
<p>
	　　kukoc答：</p>
<p>
	　　datapools就是一个数据集，有点象SQL中的游标使用方法。</p>
<p>
	　　给个例子吧，我在PB9系列的《软件工程与PB》中写的：</p>
<p>
	　　&#39;打开datapool personnel</p>
<p>
	　　dp_personnel= SQADatapoolOpen(&quot;personnel&quot;, SQA_DP_SEQUENTIAL)</p>
<p>
	　　&#39;循环插入10条人员记录</p>
<p>
	　　For i = 1 to 10</p>
<p>
	　　&#39;移动游标到数据池的下一行</p>
<p>
	　　Call SQADatapoolFetch(dp_personnel)</p>
<p>
	　　&#39;取得第i行第1列的值--部门</p>
<p>
	　　Call SQADatapoolvalue(dp_personnel,1,dep)</p>
<p>
	　　&#39;取得第i行第2列的值--姓名</p>
<p>
	　　Call SQADatapoolvalue(dp_personnel,2, uname)</p>
<p>
	　　&#39;取得第i行第3列的值--性别</p>
<p>
	　　Call SQADatapoolvalue(dp_personnel,3, sex)</p>
<p>
	　　PushButton Click, &quot;Text=新增(N)&quot; &#39;单击新增按钮</p>
<p>
	　　InputKeys &quot;{TAB}&quot;</p>
<p>
	　　InputKeys dep &#39;输入部门</p>
<p>
	　　InputKeys &quot;{TAB}&quot;</p>
<p>
	　　InputKeys uname &#39;输入姓名</p>
<p>
	　　InputKeys &quot;{TAB}&quot;</p>
<p>
	　　InputKeys sex &#39;输入性别</p>
<p>
	　　&#39;以上用变量替换了实际输入值，如：</p>
<p>
	　　&#39;InputKeys &quot;{TAB}<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>部{TAB}张三{TAB}男&quot;</p>
<p>
	　　next i</p>
<p>
	　　Call SQADatapoolClose(dp_personnel) &#39;关闭datapool</p>
]]></description>
    <pubDate>Mon, 12 Dec 2011 11:02:17 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>Robot</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[使用Rational Robot测试含有数据关联的Web应用]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/2011/1212/203749.html</link>
    <description><![CDATA[<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/" target="_blank" >Rational</A></STRONG> <STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/" target="_blank" >Robot</A></STRONG>可被用来对包含数据关联的复杂Web应用进行<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/xncs/" target="_blank" >性能测试</A></STRONG>。这里所谓数据关联，是指Web页面之间存在的数据相关性，例如一个动态的页面URL或者个别输入参数需要从前一个页面中抽取出来，有时候还需要在抽取得到的结果的基础上做进一步处理。这就使得测试<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>员通常必须对Robot自动生成的VU脚本进行修改从而保证其能正确运行。简单情形下，VU语言库提供的一些库函数可以支持常见的抽取<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求</A></STRONG>。但在很多更复杂的情形中，往往需要通过更多的编程来处理页面之间的数据关联，包括进行模式匹配、模拟<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcskfyy/java/" target="_blank" >Java</A></STRONG> Script或者Java Applet的行为等。本文将介绍处理最常见的几种数据关联的方法，并提供了一系列很有用的功能函数，帮助测试开发员编写更具灵活性的VU脚本。</p>
<p>
	　　简介</p>
<p>
	　　随着越来越多的企业应用被移植到Web上，Web应用正变得日益复杂。它们被用来实现复杂的业务流程例如交易甚至工作流。一个业务流程通常包含若干步骤。这些步骤间自然地需要共享某些数据以完成一次连续的&ldquo;计算&rdquo;。例如，某一个步骤的输出可能是下一个步骤所需的输入。在一个典型的Web应用实现中，业务流程的每个步骤对应为一个HTML页面，因而最终用户将与一系列连续的页面依次交互以完成一个完整的业务流程。由于Web的无状态特性，这些页面中通常需要存储一些信息来实现它们之间所需的数据共享，例如下一个页面的URL以及其他可能的输入参数等。这些信息常常是由<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>动态生成，因此每次的值都可能不同。但是，当Robot录制一个HTTP会话时，它只能记录这些数据在这个会话中的一个快照。尽管Robot采用了一种称为&ldquo;动态数据关联&rdquo;(Dynamic data correlation)的技术使得它能够关联部分动态的值，但还是无法找出所有需要关联的值并据此产生具备完善功能和足够灵活性的VU脚本。即使Robot可以简单地认为所有的数据都是动态的，如何在可用的HTML页面中抽取甚至构造这些数据的值则是一个更加复杂和困难的问题，因为Robot对这些数据后隐含的逻辑一无所知。因此，在Robot不能产生令人满意的VU脚本时，就需要手工修改进行完善。</p>
<p>
	　　下面将首先对Web应用中的数据关联作更进一步的剖析，接着介绍如何使用Robot的&ldquo;动态数据关联&rdquo;技术，然后详细讨论当Robot不能产生满意的脚本时一些可能的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/jjfa/" target="_blank" >解决方案</A></STRONG>，包括动态数据值的定制抽取和客户端数据构造的模拟等。</p>
<p>
	　　Web应用中数据关联的分析</p>
<p>
	　　在Web应用中，当一个特定的HTML页面的URL或者个别输入参数的值是动态产生因而必须从先于它返回的页面包含的数据中抽取或者构造出来时，就发生了数据关联。动态输入参数的一个很好的例子就是当前很普遍的&ldquo;Session ID&rdquo;，它由服务器生成并返回给用户的浏览器，在访问下一个页面时这个ID需要被发送回去以获取存储在服务器端的会话上下文。输入参数通常以四种方式提交：HTTP头参数、Cookie、URL参数和FORM参数。由于URL参数可被认为是URL的一部分，因此可以认为有四种可能发生关联的动态数据：HTTP头参数、Cookie、URL、FORM参数。在Robot的VU语言中，一个HTTP请求是通过调用库函数&ldquo;http_request&rdquo;发出的，列表1是给出了一个典型的用例。请注意列表1中各粗体部分，它们分别代表了四种可能发生关联的动态数据的形式中的一种。</p>
<p>
	　　列表1. 函数http_request的典型用例</p>
<p>
	　　http_request [&quot;t3079&quot;]</p>
<p>
	　　&quot;POST /pkmslogin.form HTTP/1.1\r\n&quot;</p>
<p>
	　　&quot;A<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>ept: image/gif, image/x-xbitmap, image/jpeg,image/pjpeg, applicat&quot;</p>
<p>
	　　&quot;ion/vnd.ms-excel, application/vnd.ms-powerpoint,application/msword, ap&quot;</p>
<p>
	　　&quot;plication/x-shockwave-flash, */*\r\n&quot;</p>
<p>
	　　&quot;Referer: &quot; SgenURI_009 &quot;\r\n&quot;</p>
<p>
	　　/* &quot;Referer: http://gclgtod.cn.ibm.com/wps/myportal?lang=en_US&quot; */</p>
<p>
	　　&quot;Accept-Language: en-us,zh-cn;q=0.5\r\n&quot;</p>
<p>
	　　&quot;Content-Type: application/x-www-form-urlencoded\r\n&quot;</p>
<p>
	　　&quot;Accept-Encoding: gzip, deflate\r\n&quot;</p>
<p>
	　　&quot;User-Agent: Mozilla/4.0 (compatible; MSIE 6.0;Windows NT 5.1)\r\n&quot;</p>
<p>
	　　&quot;Host: gclgtod.cn.ibm.com\r\n&quot;</p>
<p>
	　　&quot;Content-Length: 55\r\n&quot;</p>
<p>
	　　&quot;Connection: Keep-Alive\r\n&quot;</p>
<p>
	　　&quot;Cache-Control: no-cache\r\n&quot;</p>
<p>
	　　&quot;Cookie: w3sauid=d002000000001363710753854620000923482.0009B551AB;PBC_N LSP&quot;</p>
<p>
	　　&quot;=en_US; msp=a<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >lr</A></STRONG>eadyOffered;JSESSIONID=0000fRBw1aq9nolhnP9ZMKhaw2B:- 1; &quot;</p>
<p>
	　　&quot;PD-H-SESSION-ID=4_oxjUZgfvY4ToFOhh9cFnnAg54o4sndHOA6rRkqpxbT2NAAAA\r&quot;</p>
<p>
	　　&quot;\n&quot;</p>
<p>
	　　&quot;\r\n&quot;</p>
<p>
	　　&quot;username=admin</p>
]]></description>
    <pubDate>Mon, 12 Dec 2011 11:01:02 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>Robot</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[Rational Robot压力测试实例]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/2011/1212/203748.html</link>
    <description><![CDATA[<p>
	　　看到很多人在要这个,找到一篇,转过来给大家看看</p>
<p>
	　　第一贴内容是关于CS结构的基于socked协议的脚本录制,修改,设置,回放的</p>
<p>
	　　第二贴内容是关于自写SQL SERVER<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>压力脚本的</p>
<p>
	　　文章的出处没有看到作者的名字,非常抱歉</p>
<p>
	　　脚本与被测程序有关,直接运行这个脚本是不能回放成功的(因为你没有脚本运行的环境)</p>
<p>
	　　文章如下</p>
<p>
	　　第一步：设置<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/" target="_blank" >Robot</A></STRONG></p>
<p>
	　　Robot――Tools――Session Record options，Method选择API Recorder，Generater Filtering中Filtering选择Auto filtering，Select protocols只选择Socket;</p>
<p>
	　　第二步：录制VU脚本</p>
<p>
	　　在启动的Start Application窗口中，Executable输入被测程序的客户端程序的路径和文件名，Working Directory中输入被测程序的工作路径，Program Arguments如果没有就空着。被测程序程序启动后，执行需要的操作然后关闭程序，停止录制脚本，Robot会自动生成脚本。</p>
<p>
	　　脚本示例：</p>
<table width="80%">
	<tbody>
		<tr>
			<td bgcolor="#000000" class="content">
				<p>
					<font color="#ffffff">#include &lt;VU.h&gt;</font></p>
				<p>
					<font color="#ffffff">{</font></p>
				<p>
					<font color="#ffffff">push Timeout_scale = 200; /* Set timeouts to 200% of maximum response time */</font></p>
				<p>
					<font color="#ffffff">push Think_def = &quot;<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LR</A></STRONG>&quot;;</font></p>
				<p>
					<font color="#ffffff">Min_tmout = 120000; /* Set minimum Timeout_val to 2 minutes */</font></p>
				<p>
					<font color="#ffffff">push Timeout_val = Min_tmout;</font></p>
				<p>
					<font color="#ffffff">SERVER = sock_connect(&quot;123001&quot;, &quot;SERVER:2000&quot;);</font></p>
				<p>
					<font color="#ffffff">{ INFO SERVER &quot;SERVER&quot;=&quot;192.168.1.12&quot;; } /*1*/</font></p>
				<p>
					<font color="#ffffff">set Server_connection = SERVER;</font></p>
				<p>
					<font color="#ffffff">push Think_avg = 0;</font></p>
				<p>
					<font color="#ffffff">sock_send</font></p>
				<p>
					<font color="#ffffff">&quot;`45645651300000000001<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>00f701000002000000c3330100000000000000000001000000&quot; &quot;00000000000sdgsdfgfhjghjjdfhjhkjgfhjgfjjk000000000000hh0000000000000000000000&quot; &quot;000000000000000000000000000000000000000000000100`g2222`0012313546545465431&quot; &quot;`45641313000000000000000000000000000000000000`&quot;;</font></p>
				<p>
					<font color="#ffffff">sock_nrecv [&quot;123002&quot;] 200;</font></p>
				<p>
					<font color="#ffffff">sock_send &quot;`1321321656548745215599154654456546122132112313210000000000000001000000&quot; &quot;00000000021321215665654548879654654655562000000000000000000000000000000&quot; &quot;00000000000000000000000000000000000000000000012131132321213212111323213&quot; &quot;`123110000000`Z2&quot;;</font></p>
				<p>
					<font color="#ffffff">sock_recv [&quot;123003&quot;] &quot;$&quot;; /* 50 bytes */</font></p>
				<p>
					<font color="#ffffff">sock_disconnect(SERVER);</font></p>
				<p>
					<font color="#ffffff">pop [Think_def, Think_avg, Timeout_val, Timeout_scale];</font></p>
				<p>
					<font color="#ffffff">}</font></p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　这个脚本如果不能正确回放，可以将将sock_recv [&quot;123003&quot;] &quot;$&quot;; /* 50 bytes */改为</p>
<p>
	　　sock_nrecv [&quot;123003&quot;] 50; /* 50 bytes */</p>
<p>
	　　第三步：设置Suite，回放脚本</p>
<p>
	　　回放录制的脚本，Testmanager会自动创建Suite，如下所示：[attachment=1786]</p>
<p>
	　　默认脚本运行一次，为了长时间运行，修改增加脚本的运行次数(最大32767)，在Run properties中Iterations中设置。然后运行Suite，在Run Suite窗口中的&ldquo;Number of users&rdquo;上输入虚拟用户数，如200。</p>
<p>
	　　第四步：观察被测服务程序的运行情况，查看有无异常。</p>
<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/xncs/" target="_blank" >压力测试</A></STRONG>需要连续、高负载运行不少于72小时，运行完成服务程序需要无资源泄漏、无报错、无异常退出以及其他不正常情况。</p>
<p>
	　　ilovejolly 2006-05-20 16:43</p>
<p>
	　　数据库并发测试</p>
<p>
	　　数据库并发测试的必要性：</p>
<p>
	　　1、 与数据库连接的服务程序采用多线程同时开启多个数据库连接;</p>
<p>
	　　2、 与数据库连接的服务程序单线程，但是同时开启多套服务程序;</p>
<p>
	　　以上两种情况均会产生对数据库的并发访问操作。数据库并发访问会导致数据库数据错误、数据库死锁等故障，需要在测试阶段进行充分测试。</p>
<p>
	　　数据库并发测试测试方法：</p>
<p>
	　　1、 利用<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>模拟多个最终用户进行并发测试;</p>
<p>
	　　这种测试方法的缺点：最终用户往往并不是直接连接到数据库上，而是要经过一个和多个中间服务程序，所以并不能保证访问数据库时还是并发。其次，这种测试方法需要等到客户端程序、服务端程序全部完成才能进行;</p>
<p>
	　　2、 利用测试工具编写脚本，直接连接数据库进行并发测试;</p>
<p>
	　　这种方法可以有效的保证并发操作，而且在数据库访问程序完成即可测试，可以大大缩短测试时间，而且测试效果更好。</p>
<p>
	　　下面通过一个演示程序，演示使用Robot使用第二种测试方法进行数据库的并发测试：</p>
<p>
	　　第一步：创建演示程序：打开SQL SERVER查询分析器，在SQL SERVER测试数据库中执行下列脚本(脚本执行操作：创建表testtable，并插入一条记录;创建存储过程test)：</p>
<table width="80%">
	<tbody>
		<tr>
			<td bgcolor="#cccccc" class="content">
				<p>
					if exists (select * from dbo.sysobjects where id = object_id(N&#39;[dbo].[Test]&#39;) and OBJECTPROPERTY(id, N&#39;IsProcedure&#39;) = 1)</p>
				<p>
					drop procedure [dbo].[Test]</p>
				<p>
					GO</p>
				<p>
					if exists (select * from dbo.sysobjects where id = object_id(N&#39;[dbo].[testtable]&#39;) and OBJECTPROPERTY(id, N&#39;IsUserTable&#39;) = 1)</p>
				<p>
					drop table [dbo].[testtable]</p>
				<p>
					GO</p>
				<p>
					CREATE TABLE [dbo].[testtable] (</p>
				<p>
					[testid] [int] NULL ,</p>
				<p>
					[counts] [int] NULL</p>
				<p>
					) ON [PRIMARY]</p>
				<p>
					GO</p>
				<p>
					insert into testtable (testid,counts) values (1,0)</p>
				<p>
					GO</p>
				<p>
					SET QUOTED_IDENTIFIER ON</p>
				<p>
					GO</p>
				<p>
					SET ANSI_NULLS ON</p>
				<p>
					GO</p>
				<p>
					CREATE Procedure dbo.Test</p>
				<p>
					as</p>
				<p>
					declare @count int</p>
				<p>
					begin tran TEST</p>
				<p>
					select @count=counts from testtable where testid=1</p>
				<p>
					update testtable set counts=@count+1</p>
				<p>
					if (@@error &gt;0) begin</p>
				<p>
					rollback tran TEST</p>
				<p>
					end else begin</p>
				<p>
					commit tran TEST</p>
				<p>
					end</p>
				<p>
					GO</p>
				<p>
					SET QUOTED_IDENTIFIER OFF</p>
				<p>
					GO</p>
				<p>
					SET ANSI_NULLS ON</p>
				<p>
					GO</p>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　第二步：创建测试脚本：在Robot中新建VU脚本，输入以下内容：</p>
<table width="80%">
	<tbody>
		<tr>
			<td bgcolor="#cccccc" class="content">
				<p>
					#include &lt;VU.h&gt;</p>
				<p>
					{</p>
				<p>
					push Timeout_scale = 200; /* Set timeouts to 200% of maximum response time */</p>
				<p>
					push Think_def = &quot;LR&quot;;</p>
				<p>
					Min_tmout = 120000; /* Set minimum Timeout_val to 2 minutes */</p>
				<p>
					push Timeout_val = Min_tmout;</p>
				<p>
					ser=sqlconnect(&quot;server&quot;,&quot;sa&quot;,&quot;888&quot;,&quot;192.168.0.99&quot;,&quot;sqlserver&quot;);</p>
				<p>
					set Server_connection = ser;</p>
				<p>
					push Think_avg = 0;</p>
				<p>
					sync_point &quot;logon&quot;;</p>
				<p>
					sqlexec [&quot;sql_1000&quot;] &quot;testdb..test&quot;;</p>
				<p>
					sqldisconnect (ser);</p>
				<p>
					}</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　说明：</p>
<p>
	　　ser=sqlconnect(&quot;server&quot;,&quot;sa&quot;,&quot;888&quot;,&quot;192.168.0.99&quot;,&quot;sqlserver&quot;)</p>
<p>
	　　sa为数据库用户名，888为sa密码，192.168.0.99数据库IP地址</p>
<p>
	　　以上三项按实际的测试数据库设置更改，其他两项不用修改</p>
<p>
	　　sqlexec [&quot;sql_1000&quot;] &quot;testdb..test&quot;</p>
<p>
	　　testdb为新建存储过程test所在的数据库，按实际的数据库修改</p>
<p>
	　　第三步：执行测试：运行上一步创建的脚本(运行时自动创建Suite)，在Run Suite窗口中的&ldquo;Number of users&rdquo;上输入20。运行完脚本，打开数据库查看counts的数值。把counts值改为零多次运行脚本，观察每次运行后counts的结果。</p>
<p>
	　　测试说明</p>
<p>
	　　(1)、测试示例程序的目的是，存储过程test每执行一次，表testtable中的counts字段增加一;</p>
<p>
	　　(2)、第三步的测试可以发现每次执行后counts结果并不相同，而且不等于20，这说明这个程序是在并发时是问题的。</p>
<p>
	　　(3)、将存储过程中的select @count=counts from testtable where testid=1修改为select @count=counts from testtable with (UPDLOCK) where testid=1。再次进行并发测试，每次的结果应该都是20。</p>
<p>
	　　以上演示程序，仅仅演示了测试的方法。在实际的数据库并发测试中，首先要确定存在哪些并发情况、哪些数据受到并发影响，然后编写脚本，设置suite进行并发测试。</p>
]]></description>
    <pubDate>Mon, 12 Dec 2011 10:59:42 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>Robot</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[初识IBM Rational RobotJ]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/2011/1212/203747.html</link>
    <description><![CDATA[<p>
	　　Rational 公司邀请我看了看它们的新产品，Rational PobotJ。它们邀请我有两个原因。一个原因很明显，就是由于我长时间进行测试自动化的工作，了解大量的人们正确使用(以及误用)这些<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>的方式。第二个原因就是由于我从来没有使用过Rational <STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/" target="_blank" >Robot</A></STRONG>或者该公司的Test Manager模型，所以凭借我的自动化背景可以清晰地洞察出他们是如何设计软件测试自动化<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/jjfa/" target="_blank" >解决方案</A></STRONG>的。</p>
<p>
	　　简介</p>
<p>
	　　Rational 公司邀请我看了看它们的新产品，Rational PobotJ。它们邀请我有两个原因。一个原因很明显，就是由于我长时间进行测试自动化的工作，了解大量的人们正确使用(以及误用)这些测试工具的方式。第二个原因就是由于我从来没有使用过Rational Robot或者该公司的Test Manager模型，所以凭借我的自动化背景可以清晰地洞察出他们是如何设计软件测试自动化解决方案的。</p>
<p>
	　　我拿到了一份Rational RobotJ的&beta;版，然后就急于开始研究Rational 的最新工具会给软件测试带来什么样的变化。多年来，我已编写了很多Rational Visual Test自动化脚本，我很想看看这个工具在测试基于Web的应用程序领域中会取得什么样的成就。</p>
<p>
	　　我花了几分钟安装该工具，到处点击来熟悉界面的内容，主要是想看看这到底是个什么东西，最后我决定先使用一下工具栏中的Record new RobotJ script 按钮。这东西到底怎么样，我暗自思忖，且看看它会创建出什么样的冗长脚本来，既可以准确地记录我的操作，还可以保持同步，以保证回放功能确实好使。当使用记录和回放(record-and-playback)工具时，我稍稍有点嘲讽心理。</p>
<p>
	　　虽然更喜欢旧式优秀的匆匆编写代码的方式，但是我还是渴望了解这个工具的更多功能。不过，使用记录器是了解有关自动化工具以及正确使用该工具的最佳方式之一。您马上就会发现，记录器不仅仅曾经是(现在也是)深入学习RobotJ的伟大工具，它也是Rational所希望的帮助人们创建大量测试脚本的最佳方式。它也确实做得很棒!</p>
<p>
	　　背景</p>
<p>
	　　我曾经听到过有关测试自动化的传言，据说Rational 准备发布一种新产品，主要用于测试HTML与基于Java 的web 应用程序。而且，考虑到<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/mxdx/" target="_blank" >面向对象</A></STRONG>编程语言的特有优点，准备使用Java 作为其编程语言。我很想看到它的面世，越快越好。这肯定是一种新型有关编程的玩具语言，我已经等不及要使用它了。</p>
<p>
	　　多年来我一直选择Rational Visual Test 编写软件测试自动化的脚本。它使用类似Visual Basic 的语言，编程进行起来简单直接，同时它也具备使用指针处理复杂数据结构的高级功能，这也使它成为一种真正的语言。Visual Test 甚至在版本6.0中加入了测试网页的功能。该功能确实好使，而且一直在发挥着作用，但是在测试工具中加入此功能的最初目的是用来测试Microsoft 的Windows 程序的。Visual Test 一直努力成为终极的、无所不能的软件测试自动化工具，而且可以肯定地说，多年来它一直如此。</p>
<p>
	　　现在，我仍然使用VT ，即使对于那些非测试的解决方案。但是，当一种主要用于测试web应用程序的新型工具即将发布的时候，我确实想看看它到底能够实现什么功能，而且我也十分喜欢使用Java 作为<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/zdcsjbyy/" target="_blank" >脚本语言</A></STRONG>。</p>
<p>
	　　我一直尽力将良好的编程实践教授给我的学生和客户，同时还有创建类似面向对象脚本的方法，以及使用并不是那么面向对象的语言完成数据隐藏、封装和简单形式的继承。这些方法都十分有效，但是如果使用面向对象语言的话，就不仅仅是鼓励使用这些方法那么简单了，而是可以加强进行这些实践。这就是我为什么喜欢RobotJ 使用Java 作为其脚本语言的原因了。</p>
<p>
	　　测试</p>
<p>
	　　我想我还是从简单的地方开始吧：单击一些链接来看看它在屏幕显示不下时是否较好地处理了浏览器窗口的滚动以及页面加载的滞后时间是否较长。但是，随后我又从另一个角度进行了一下思考：如果测试驾驶一辆承诺具有强大发动机和超速悬挂装置的新型轿车，我能仅仅坐在那里来验证转弯信号是否好使吗?或者来检验车载音响中的噪声程度吗?好，是的，确实如此。但是除此之外，我肯定想要亲自驾驶它，经过大量的弯道，同时收听广播中的Talk of the Nation。</p>
<p>
	　　显然，我不会第一次驾驶就经过太多的弯道，因为我不想撞到墙上。我只想让我记录的源代码确实可以进行工作;我还是对记录的脚本有点怀疑，不知道它是否能够正常工作。于是，我单击了记录按钮，并且按照下述步骤进行操作：</p>
<p>
	　　我运行了选定的浏览器(Microsoft Internet Explorer 6.0)</p>
<p>
	　　将我的测试命名为First_one (您可以在源代码的引用中看到)</p>
<p>
	　　使用相关URL 运行我的应用程序(www.xtenddev.com)</p>
<p>
	　　单击链接进入Xtend Development 的搜索引擎</p>
<p>
	　　键入我正在寻找的文本(Rational)</p>
<p>
	　　浏览我想要的产品(VT6 InDepth Videos)</p>
<p>
	　　向我的购物车添加项目(buy.gif graphic)</p>
<p>
	　　点击Check Out 按钮完成交易</p>
<p>
	　　填写客户与付款信息</p>
<p>
	　　向交易<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>提交产品订单</p>
<p>
	　　退出浏览器</p>
<p>
	　　预期效果</p>
<p>
	　　作为一名测试自动化程序员，我对于使用RobotJ 记录器预想了很多概念。这些概念都是通过使用Visual Test 和其他测试自动化工具得出的。我预先考虑了许多问题，尤其是：</p>
<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/jrxcs/" target="_blank" >兼容性</A></STRONG>：最初，我有点担心它与Microsoft Internet Explorer 6.0的兼容性问题。Microsoft 不断快速地推出其浏览器的更新版本，我不知道RobotJ 是否能够跟得上节奏。Rational 肯定在使用IE API 提供的内部对象模型，Visual Test 团队也是如此，但是Microsoft 的内部二进制数字并不总是如预期那样的有效，还需要<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>团队再进行大量的工作。我设想对于RobotJ 开发人员也是如此。</p>
<p>
	　　脚本长度：我担心可能会创建出很长的脚本，里面还带有大量的延迟或者休眠语句，用来模拟我在键入和单击过程中的实际延迟。我也在期待着有大量的命令检验浏览器窗口的大小和位置、屏幕分辨度以及其他有时可能造成致命故障的错误，并且创建出很长的脚本。</p>
<p>
	　　延迟的问题：我预想脚本仅仅可以在理想状态下运行，服务器可以在记录创建时或者比其更快地进行响应。在服务器滞后时，我预想肯定需要在特定点暂停，例如在单击链接以跳离当前页时，并使用附加源代码调整脚本。#p#分页标题#e#</p>
<p>
	　　实际效果</p>
<p>
	　　不过，我所得到的给了我一个惊喜，让我非常高兴：</p>
<p>
	　　兼容性：点击链接，键入多个<input type="text" />输入框控件、<textarea> 控件、&lt;select&gt;&lt;option&gt;下拉列表框、&lt;input type=submit&gt;按钮，使用post和get方法提交表单，所有这些都工作正常，没有问题。我还没有使用其他的浏览器进行测试，但是我很高兴地发现它正确地识别了测试状态下网页上的许多不同控件，而且更重要的是，回放功能也成功运行。&lt;/p&gt;
&lt;p&gt;　　简洁的源代码：源代码是简洁的，并且具有良好的可读性。通过使用Helper 的基类，所有的外部源代码都从视图中隐藏起来，只剩下我感兴趣的源代码。正如预料的那样，加入了注释帮助指导自动化程序员了解源代码中的每行都进行了什么操作。不过，还有些我没有预料到的附加信息也包括于注释中，特别是按下Place Order Now 按钮所提交的信息。&lt;/p&gt;
&lt;p&gt;　　同步性：由于源代码中没有明显地加入休眠或者延迟信息，同时Helper 基类也可以处理所有的控件识别问题，所以操作只有在单击控件时才得以执行。如果是这样的话，脚本就不会记录填写表单和点击恰当控件的信息。不过，如果页面仍处于装载状态或者仍在识别页面上的控件和链接时，它也可以耐心等待。&lt;/p&gt;
&lt;p&gt;　　为了让您更加明白，我尝试在本文档的开始几页中创建一些示例脚本。创建的源代码展示于下一页的清单1 中。(注意：必须进行一些细小的格式操作，使本文档中的代码更加可读，包括移去一些自动创建的注释)。在随后几页中，我会教您如何使用RobotJ 创建这些脚本，并讨论一些有关创建脚本的关键问题，然后研究运行脚本得到的结果。&lt;/p&gt;
&lt;p&gt;　　清单1&lt;/p&gt;
&lt;center&gt;&lt;img src=&quot;http://www.uml.org.cn/Test/images/image002.jpg&quot; alt=&quot;清单1&quot; width=&quot;592&quot; height=&quot;817&quot; border=&quot;1&quot;&gt;&lt;/center&gt;
&lt;p&gt;　　如何生成脚本&lt;/p&gt;
&lt;p&gt;　　既然您已经了解了通过上述步骤所得的脚本的内容(参见Listing1(清单1))，我将在本文档的剩余部分解释我是如何创建这些脚本的，同时指出该过程中的有趣部分。&lt;/p&gt;
&lt;p&gt;　　欢迎使用Rational RobotJ&lt;/p&gt;
&lt;p&gt;　　我已经提到了，RobotJ 是Rational 的最新解决方案，用来测试在Microsoft Windows 和Unix 平台4上的Java 或者Web 应用程序环境。RobotJ 使用IBM 开放源代码的集成开发环境(IDE)，称为Eclipse。通过使用IBM 的IDE，如图1所示，RobotJ 将与由Rational 和其他供应商创建的其他开发工具并驾齐驱，并允许把简单的工具集成于同一界面中。&lt;/p&gt;
&lt;p&gt;　　图1 ：RobotJ使用IBM 的开发源代码的IDE，称为Eclipse&lt;/p&gt;
&lt;center&gt;&lt;img src=&quot;http://www.uml.org.cn/Test/images/image004.jpg&quot; alt=&quot;图1 ：RobotJ使用IBM 的开发源代码的IDE，称为Eclipse&quot; width=&quot;553&quot; height=&quot;267&quot; border=&quot;1&quot;&gt;&lt;/center&gt;
&lt;p&gt;　　要创建RobotJ 的测试脚本，必须首先创建存储这些脚本的容器。这被称为数据存储。在做任何修改之前，必须创建这样一种项目文件。在图1中，您可以看到我已经创建了一个数据存储，称为tomsrobotjdatastore(很有创意吧，嗯?)。我的第一个记录脚本First_One将存储于此，参见清单1。我没有讲述创建数据存储的步骤，因为我想直接进入RobotJ 的实际内容。&lt;/p&gt;
&lt;p&gt;　　准备好进行记录&lt;/p&gt;
&lt;p&gt;　　创建自动脚本的第一步就是进入 Configuration Editor(配置编辑器)，请见下页的图2。选择RobotJ中Configure菜单，在其中的Testing菜单项中选择Configure Applications 可以访问到该对话框。在对话框中，单击Add 按钮，选择进入Java application、HTML application或者Windows executable。&lt;/p&gt;
&lt;p&gt;　　在本例中，将测试我的网站 www.xtenddev.com。我将在记录界面显示时从应用程序列表中选择我的应用程序，该列表由Configuration Editor 进行维护。&lt;/p&gt;
&lt;p&gt;　　图2：必须输入由RobotJ进行测试的应用程序的启动信息。供记录器使用并且允许您指定将要进行测试的应用程序。&lt;/p&gt;
&lt;center&gt;&lt;img src=&quot;http://www.uml.org.cn/Test/images/image006.jpg&quot; alt=&quot;图2：必须输入由RobotJ进行测试的应用程序的启动信息。供记录器使用并且允许您指定将要进行测试的应用程序。&quot; width=&quot;553&quot; height=&quot;321&quot; border=&quot;1&quot;&gt;&lt;/center&gt;
&lt;p&gt;　　记录新的RobotJ脚本&lt;/p&gt;
&lt;p&gt;　　在完成内部设置之后，就可以开始进行关于我的网站的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/zdcs/" target="_blank" >自动测试</A></STRONG>了。早先提及的目标是浏览到我的网站，搜索产品信息，向电子商务购物车中添加项目，然后检查客户订货与付帐信息的输入页面，提交订单，最后关闭浏览器。&lt;/p&gt;
&lt;p&gt;　　图3：Script菜单正下方的工具栏上的红色按钮用来激活记录器&lt;/p&gt;
&lt;center&gt;&lt;img src=&quot;http://www.uml.org.cn/Test/images/image008.jpg&quot; alt=&quot;图3：Script菜单正下方的工具栏上的红色按钮用来激活记录器&quot; width=&quot;362&quot; height=&quot;164&quot; border=&quot;1&quot;&gt;&lt;/center&gt;
&lt;p&gt;　　单击Script菜单正下方的Record New RobotJ 工具栏按钮(如图3所示)，开始进行上述过程。随后出现一个对话框提示输入脚本的名称。键入例中的First_One(不允许输入空格或者字母数字的混和字符)，然后点击Finish 按钮，启动记录会话。如图4所示，出现一个总在最前的标题为Recording 的窗口，工具栏中的按钮看上去十分有趣。该窗口用来控制有关记录脚本的关键内容。&lt;/p&gt;
</textarea></p>
]]></description>
    <pubDate>Mon, 12 Dec 2011 10:55:03 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>Robot</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[对 Rational Performance Tester 数据池的改进]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/performerancetest/2011/1209/203741.html</link>
    <description><![CDATA[<p>
	　　Rational Performance Teser(RPT)是专门针对 B/S架构和专用系统(SAP，Citrix 等)进行压力测试的工具。RPT 基于开放的 TPTP 平台和 Java 语言其实对我们的测试提供了很大的扩展性。本文从数据池的角度出发，结合实际环境中遇到的一些问题，来扩展 RPT 的数据驱动能力。</p>
<p>
	　　前言</p>
<p>
	　　在性能测试中，我们往往遇到这样的一些问题，比如需要通过不同的用户进行登录操作，或者需要动态的输入数据，在测试工具中往往我们是通过数据池来进行完成的。比较全面的数据池的设计往往会考虑用户数据的来源，比如文件，数据库等多种形式，但其实如果采用直接映射数据库中的某些列来进行实现，虽然在操作上会省下很多数据加工的时间，但在实际运行过场中会有诸多缺点，主要体现在每个用户每次获取数据时就需要消耗大量的时间，因为往往数据库在远程的服务器上而非本地，如果频繁的交互会使真正需要了解的响应时间大打折扣。出于测试尽可能反映真实的应用响应时间的考虑，Rational Performance Tester 采用了文件的方式来进行数据的导入。</p>
<p>
	　　Rational Performance Tester 内置的 DataPool 的实现机制</p>
<p>
	　　Rational Performance Tester 内置的数据池采用了 TPTP 的前身 Hyades 测试框架的实现方式，也就是通过 EMF 进行实现。其设计图为：</p>
<p>
	　　图 1: 设计图</p>
<center>
	<img alt="" border="1" height="177" src="http://www.ltesting.net/uploads/allimg/111209/09491T425-0.jpg" width="554" /></center>
<p>
	　　其中比较主要的几个概念是：</p>
<p>
	　　Variable： 主要指一个列，通常包含一个名字和建议的类型</p>
<p>
	　　Record： 行，包含多列的数据</p>
<p>
	　　Cell： 数据块，对应的是某行某列</p>
<p>
	　　EquivalenceClass： 等价类，数据池中记录的逻辑组合</p>
<p>
	　　Datapool： 数据池</p>
<p>
	　　往往我们在通过 RPT 的界面建立数据池或者从 CSV 文件导入数据池时，会发现在我们的 workspaces 项目的根目录下中生成了一个 .datapool 的文件，把文件通过 winrar 解开，可以看到是一个 xmi 文件，格式如下：</p>
<p>
	　　xmlns:Common_Datapool=&quot;http://www.eclipse.org/hyades/models/common/datapool.xmi&quot;</p>
<p>
	　　id=&quot;E123A884D00625FC60097F300AD111DC&quot; name=&quot;aa&quot;&gt;</p>
<p>
	　　variable= &quot;E123A884D00625FC600C8C700AD111DC &quot;/&gt;</p>
<p>
	　　variable=&quot;E123A884D00625FC602062900AD111DC&quot;/&gt;</p>
<p>
	　　variable=&quot;E123A884D00625FC600C8C700AD111DC&quot;/&gt;</p>
<p>
	　　variable=&quot;E123A884D00625FC602062900AD111DC&quot;/&gt;</p>
<p>
	　　variable=&quot;E123A884D00625FC600C8C700AD111DC&quot;/&gt;</p>
<p>
	　　variable=&quot;E123A884D00625FC602062900AD111DC&quot;/&gt;</p>
<p>
	　　type=&quot;String&rdquo;/&gt;</p>
<p>
	　　#p#分页标题#e#</p>
<p>
	　　这个 xmi 文件实际就是我们数据池实例 aa 的序列化后的形式，系统在实际调用时会将其反序列化同时将相关的数据 load 到内存中去。在 Rational Performance Tester 中打开这个 xmi 文件，可以清晰的看到它的层次结构，同时可以对它进行修改。</p>
<p>
	　　图 2: 层次结构</p>
<center>
	<img alt="" border="1" height="307" src="http://www.ltesting.net/uploads/allimg/111209/09491Ra8-1.jpg" width="509" /></center>
<p>
	　　采用 EMF 设计的一个很直接的好处是，系统可以自动的根据模型生成代码，同时实现了 UML 模型，XML Schema， 注释过的 Java 接口表现模型的统一。但在实际环境中，采用 Rational Performance Tester 内置的 DataPool 还是有很多不太方便的地方，比如：</p>
<p>
	　　要经常对文件中的数据进行变化，然后再重新测试时</p>
<p>
	　　很多时候测试完后，数据就暂时没用了，因为状态已经更新了，为此需要对测试数据进行替换，但在 RPT 目前的这种序列化反序列化的机制中，要实现这一点并不容易，所以体现在界面中的操作实际上是比较繁琐的，表现为：</p>
<p>
	　　要重新加入一个新的 Pool</p>
<p>
	　　需要对原来的变量去掉关联</p>
<p>
	　　关联新的 Pool 中的变量</p>
<p>
	　　如果你的变量比较多，还是非常繁琐的，而且不是一种最好的解决办法。</p>
<p>
	　　当测试数据很大，比如文件大概 50M 或更多时</p>
<p>
	　　这时候内置的机制会产生一些问题，装载数据时比较慢。这在早期的 6.x 版本中经常遇到，但现在 70 有没有这个问题倒是需要看看底层机制是否有更改。</p>
<p>
	　　正因为上面的问题，同时还频繁在实际的测试过程中遇到，因此找到一种更好的替代方案对于实际的项目更加迫切，好在 RPT 建立在 TPTP 的架构上，也就意味着建立在纯粹的 Java 的实现机制下，因此提供了让人很方便的插入 Java 代码的方式，使得很多的扩展和增强成为可能。下面我们就来谈谈如何解决这两个问题。</p>
<p>
	　　Rational Performance Tester DataPool 的扩展</p>
<p>
	　　为了扩展 DataPool 我们决定对这个环节进行重新的设计，原则如下：</p>
<p>
	　　考虑对真实测试性能影响最小的原则，我们把所有的数据都放在文本文件中，变量间通过逗号来进行分隔。</p>
<p>
	　　考虑到内存的开销，同时不需要把所有的数据都读入到 JVM 中进行处理的原则，我们通过了一个 ArrayList 来存放一次读入的数据，这些数据会分配给每个 Virtual User， 同时如果读到最后行时，会重新调用方法进行对 ArrayList 中数据的刷新。</p>
<p>
	　　通过变量来控制一次读入的文件行数。</p>
<p>
	　　一开始的时候考虑把通过二维数组来进行变量的读取，但后来在调试过程中发现，很难解决不同的变量读取同一行的问题，往往在一次读完后就指针就指到下一行去了，而因 RPT 本身并不是全部的 Java 脚本，而是 Java 脚本和页面表示的混合，Java 脚本和页面间其实是通过变量来进行沟通的，这造成的一个很现实的问题是，如果我们仅仅获取一个变量而不是每行的时候，无法控制在哪条语句后移动 cursor。后来就改变了设计，采用了一起获取一行的方式，对于变量的返回通过对行的解析得到。</p>
<center>
	<img alt="" border="1" height="197" src="http://www.ltesting.net/uploads/allimg/111209/09491U1S-2.gif" width="432" /></center>
<p>
	　　通过 PoolLoad 定义静态的数据池类</p>
<p>
	　　通过 getLine 返回当前 VU 对应的行</p>
<p>
	　　通过 getVar 解析返回行，从而返回需要的变量</p>
<p>
	　　经过设计的类图如下：</p>
<p>
	　　图 4: 经过设计的类图</p>
<p>
	　　关键代码的解释：</p>
<p>
	　　RPTDataPool.java：主要用于将记录以分页的形式从文件中读入到 ArrayList 中</p>
<p>
	　　首先定义需要的变量：</p>
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table3" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
Private String DataPoolFileName;// 定义数据池文件存放的位置，运行时会由 PoolLoad.java 装入
        private ArrayList DataPool;// 存放每次从数据池中读出的记录
        private int cursor = 0;// 当前记录的光标
        static private int pageno = 1;// 根据每页的大小 (PageSize), 目前光标停在哪页
        private int pagesize = 500;// 每次 load 进 DataPool 的记录数量
</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　构造函数 RPTDataPool：</p>
<p>
	　　调用 fillPageByLine 方法，把文件的第一个页面存入到变量 DataPool 中来。</p>
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table4" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
public RPTDataPool(String fileName ) {
    
    &hellip;&hellip;
    
    fillPageByLine( DataPoolFileName, DataPool, 1);
}        
</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　fillPageByLine： 每次到了页面的记录末尾，都会被调用，从而把相关的记录读到 DataPool 中来。</p>
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table5" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
private boolean fillPageByLine(String fileName, ArrayList FileLines, int Pageno) {
    // 通过 ReadLine 读文件 ;
    while (line !=null) {
    // 当前行数在关注的页面中, pageno 通过参数传入
    if ((lineno&gt;=pagesize*(Pageno-1))&amp;&amp;(lineno&lt;pagesize*Pageno)) {
        FileLines.add(line);// 把当前记录加入 ArrayList
        line=br.readLine();// 记录下移
        lineno++;// 行数增加
    } else if (lineno&lt;pagesize*(Pageno-1)) {// 当前行数还没到关注的页面
        line=br.readLine();// 记录下移
        lineno++;// 行数增加
    } else if (lineno &gt;= pagesize*(Pageno)) {// 当前行数超过关注的页面
        break;// 退出
    }
}
</pre>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#
<p>
	　　PoolLoad.java： 传入文件位置，初始化 RPTDataPool</p>
<p>
	　　文件只包括一行，就是调用 RPTDataPool 的构造函数：</p>
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table6" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
static RPTDataPool pool1 = new RPTDataPool(&quot;c:\\pool1.txt&quot;);
</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　getLine.java： 每个 RPT 的 Test 中，在需要数据池前需要插入的代码，用于把当前用户对应的数据池记录通过一行返回给 Test</p>
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table7" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
public String exec(ITestExecutionServices tes, String[] args) {
    // 调用 PoolLoad 中初始化的 pool1 的 getDataPoolItemLine 的方法返回当前行然后把 line 返回给 Test
    String line = PoolLoad.pool1.getaDataPoolItemLine();
    return line;
}
</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　getName.java： 从返回的行中取出需要的字段 ，每个变量对应着一个 get 方法，比如 getName， getPassword 等 。</p>
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table8" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
public String exec(ITestExecutionServices tes, String[] args) {
    // 从参数中读出记录行到 line
    StringTokenizer st = new StringTokenizer(line,&quot;,&quot;);// 转换成 StringTokenizer
    while (st.hasMoreTokens()) {
    if (i == index) { // 匹配需要的字段
        name = st.nextToken(); // 把相应的字段赋值
        break;
    }
    i++;
}
</pre>
			</td>
		</tr>
	</tbody>
</table>
<center>
	<img alt="" border="1" height="479" src="http://www.ltesting.net/uploads/allimg/111209/09491UJ2-3.jpg" width="534" /></center>
<p>
	　　关键代码的解释：</p>
<p>
	　　RPTDataPool.java：主要用于将记录以分页的形式从文件中读入到 ArrayList 中</p>
<p>
	　　首先定义需要的变量：</p>
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table9" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
Private String DataPoolFileName;// 定义数据池文件存放的位置，运行时会由 PoolLoad.java 装入
        private ArrayList DataPool;// 存放每次从数据池中读出的记录
        private int cursor = 0;// 当前记录的光标
        static private int pageno = 1;// 根据每页的大小 (PageSize), 目前光标停在哪页
        private int pagesize = 500;// 每次 load 进 DataPool 的记录数量
</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　构造函数 RPTDataPool：</p>
<p>
	　　调用 fillPageByLine 方法，把文件的第一个页面存入到变量 DataPool 中来。</p>
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table10" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
public RPTDataPool(String fileName ) {
    
    &hellip;&hellip;
    
    fillPageByLine( DataPoolFileName, DataPool, 1);
}        
</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　fillPageByLine： 每次到了页面的记录末尾，都会被调用，从而把相关的记录读到 DataPool 中来。</p>
<table border="0" cellpadding="0" cellspacing="0" id="table11" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
private boolean fillPageByLine(String fileName, ArrayList FileLines, int Pageno) {
    // 通过 ReadLine 读文件 ;
    while (line !=null) {
    // 当前行数在关注的页面中, pageno 通过参数传入
    if ((lineno&gt;=pagesize*(Pageno-1))&amp;&amp;(lineno&lt;pagesize*Pageno)) {
        FileLines.add(line);// 把当前记录加入 ArrayList
        line=br.readLine();// 记录下移
        lineno++;// 行数增加
    } else if (lineno&lt;pagesize*(Pageno-1)) {// 当前行数还没到关注的页面
        line=br.readLine();// 记录下移
        lineno++;// 行数增加
    } else if (lineno &gt;= pagesize*(Pageno)) {// 当前行数超过关注的页面
        break;// 退出
    }
}
</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　PoolLoad.java： 传入文件位置，初始化 RPTDataPool</p>
<p>
	　　文件只包括一行，就是调用 RPTDataPool 的构造函数：</p>
<table border="0" cellpadding="0" cellspacing="0" id="table12" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
static RPTDataPool pool1 = new RPTDataPool(&quot;c:\\pool1.txt&quot;);
</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　getLine.java： 每个 RPT 的 Test 中，在需要数据池前需要插入的代码，用于把当前用户对应的数据池记录通过一行返回给 Test</p>
<table border="0" cellpadding="0" cellspacing="0" id="table13" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
public String exec(ITestExecutionServices tes, String[] args) {
    // 调用 PoolLoad 中初始化的 pool1 的 getDataPoolItemLine 的方法返回当前行然后把 line 返回给 Test
    String line = PoolLoad.pool1.getaDataPoolItemLine();
    return line;
}
</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　getName.java： 从返回的行中取出需要的字段 ，每个变量对应着一个 get 方法，比如 getName， getPassword 等 。</p>
<table border="0" cellpadding="0" cellspacing="0" id="table14" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
public String exec(ITestExecutionServices tes, String[] args) {
    // 从参数中读出记录行到 line
    StringTokenizer st = new StringTokenizer(line,&quot;,&quot;);// 转换成 StringTokenizer
    while (st.hasMoreTokens()) {
    if (i == index) { // 匹配需要的字段
        name = st.nextToken(); // 把相应的字段赋值
        break;
    }
    i++;
}
</pre>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#
<p>
	　　Rational Performance Tester 对编写脚本的调试</p>
<p>
	　　如何调试客户化的 RPT 脚本，因脚本在后端运行时，无法看到任何的控制台信息，运行完也无从发现，因为 log 信息也被序列化成 xmi 了，因此采用 System.out.println 基本是没有办法了，这里提供了两种方式：</p>
<p>
	　　式：</p>
<p>
	　　通过将调试信息写入文件的方式 。</p>
首先定义变量：
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table15" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
String mess = &ldquo;begin&rdquo;;
</pre>
			</td>
		</tr>
	</tbody>
</table>
然后在需要输出的位置，把信息附在 mess 中， 比如：
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table16" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
mess = mess +line + &quot;*******\r\n&quot;;
</pre>
			</td>
		</tr>
	</tbody>
</table>
在方法调用完后，把 mess 信息输出到文件，如下：
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table17" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
try {
FileWriter outFile = new FileWriter(&quot;C:\\response1.txt&quot;);
outFile.write(mess);
outFile.close();
} catch (Exception e) {
}
</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　最后直接打开文件，查看相关的内容 。</p>
<p>
	　　如果是在 RPT Test 中的代码，可以采用 TPTP 的 Log， 将相关信息输出到执行日志中 。</p>
<p>
	　　首先 import IVirtualUserInfo， 主要是为了得到当前的用户 id。</p>
然后调用 ITestExecutionServices 的 getTestLogManager 的 reportMessage 方法，把需要的信息记录到 TPTP Log 中 。
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table18" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
Tes.getTestLogManager().reportMessage(
        &quot;name =&quot; + Integer.toString(vui.getUID()) + &quot;==&quot; + name);
</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　调试方式的比较：</p>
<p>
	　　在第一种方式下，能直接以文件的方式一目了然所有的输出，但无法看到那个虚拟用户的 id 等信息，这是传统的，大家比较适应的方式。</p>
<p>
	　　通过 TPTP Log 的方式，查看起来比较麻烦，需要在执行日志中展开来看每个节点的返回，效率比较低，如果要象第一种方式下以文件的方式，需要用 winrar 解开 .execute 文件 ( 执行日志 )， 然后会看到 EMF 模型实例的序列化的 xmi 文件，然后通过 ultraedit 打开了就可以看到了。</p>
<p>
	　　总结</p>
<p>
	　　Rational Performance Tester 构建于 Eclipse 的 TPTP 的测试框架 ，它是 Eclipse 的一类项目 (Top Projects)之一，目前仍然在不断的发展，基于 TPTP 的框架，一方面能很方便的采用框架上已经提供的功能，比如 DataPool，TPTP Log 等，另外，因为 TPTP 本身基于 Java 架构，因此完全可以通过 Java 底层的提供的强大的 API 来客户化代码满足各种不同环境下的不同需求，本文就是对数据池进行改造的一个例子。大家在实际的使用过程中也可以采用各种新的 Eclipse 的技术，比如 EMF，BIRT 来对 RPT 进行各种扩展。开放的架构，灵活的扩展方式和丰富的接口，这也就是我们认为的开放的力量吧。</p>
]]></description>
    <pubDate>Mon, 26 Mar 2012 10:58:43 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111209/09491T425-0-lp.jpg</subImagePath>
     <category>PerformeranceTester</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[Rational Performance Tester 数据关联规则详解]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/performerancetest/2011/1209/203740.html</link>
    <description><![CDATA[<p>
	　　内容</p>
<p>
	　　1. 概述</p>
<p>
	　　2. 设置 RPT 的自动数据关联</p>
<p>
	　　3. HTTP 协议的 RPT 自动数据关联</p>
<p>
	　　4. 基于 Jazz 产品的数据关联算法</p>
<p>
	　　5. 数据关联规则扩展</p>
<p>
	　　总结</p>
<p>
	　　参考资料</p>
<p>
	　　简介： 利用 Rational Performance Tester(RPT)进行<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/xncs/" target="_blank" >性能测试</A></STRONG>的过程中，数据关联往往是测试脚本编辑和调试过程中最繁琐的工作，直接影响测试脚本调试的效率。基于使用中的最佳实践，RPT 提供了一套自动数据关联规则，能够满足大部分测试脚本的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求</A></STRONG>。在被测系统非常复杂的情况下，RPT 还提供了扩展数据关联规则的功能，可以最大限度的满足用户需求。本文详细描述了 RPT8.1 提供的自动数据关联规则及扩展数据关联规则的方法，旨在帮助读者了解 RPT 所能提供的数据关联，并根据业务需求扩展规则，提高测试脚本<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>的效率。</p>
<p>
	　　1. 概述</p>
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table1" summary="" width="70%">
	<tbody>
		<tr>
			<td scope="col">
				免费<STRONG><A href="http://www.ltesting.net/ceshi/down" target="_blank" >下载</A></STRONG>：IBM&reg; Rational&reg; Performance Tester 试用版&nbsp;&nbsp;|&nbsp;&nbsp; IBM&reg; Rational&reg; 测试人员资源工具包</td>
		</tr>
		<tr>
			<td>
				获取免费的 Rational 软件工具包系列，下载更多的 Rational 软件试用版。</td>
		</tr>
	</tbody>
</table>
<p>
	　　Rational Performance Tester(以下简称为 RPT)是由 IBM Rational 团队开发的性能测试产品。其内在支持的 HTTP 协议使得其广泛应用于 Web 应用程序，用于验证系统的性能，识别和解决各种性能问题。RPT 的测试分为五个阶段：测试脚本生成、脚本编辑、负载设计、测试执行和结果分析。</p>
<p>
	　　在 RPT 针对 web 应用录制生成的测试脚本中，某个 HTTP 请求中的数据常常依赖于前面请求的响应内容中的数据，如被测系统为每个新创建的资源(resource)分配一个 ID 并返回，以后对该资源的操作需要使用该唯一值来进行标识。为了保证测试在多用户和不同数据输入的情况下正常运行，该请求中的数据需要被替换为其所依赖的响应数据，我们称该响应数据为引用，这种脚本内部的链接称为数据关联。</p>
<p>
	　　数据关联往往是测试脚本编辑和调试阶段最繁琐的工作，直接影响测试脚本调试的效率。鉴于数据关联的复杂性，RPT 根据内嵌的算法提供了一套自动数据关联规则，在测试脚本生成阶段，当自动数据关联算法检测到一个请求值需要被前面的响应数据替换，会自动将该响应数据设置为引用，并将随后的请求值自动与该引用关联起来。该自动关联规则基于使用中的最佳实践，能够满足大部分测试脚本的需求。在被测系统非常复杂的情况下，RPT 还提供了扩展数据关联规则的功能，可以最大限度的满足用户需求。</p>
<p>
	　　本文详细描述了 RPT8.1 提供的根据算法生成的自动数据关联规则，并给出了 RPT 扩展数据关联规则的方法，旨在帮助读者了解 RPT 所能提供的数据关联，根据业务需求扩展规则，提高测试脚本开发的效率。</p>
<p>
	　　2. 设置 RPT 的自动数据关联</p>
<p>
	　　通过选择窗口&rarr;首选项&rarr;测试生成&rarr;HTTP 测试生成的数据关联和协议选项卡，可以修改或关闭 RPT 的自动数据关联功能，如图 1 为 HTTP 测试生成中数据关联的通用设置，图 2 为基于 HTTP 协议的具体应用的支持，其中包括对 IBM Rational 下一代协作软件交付平台&mdash;Jazz 的支持。本文中的自动数据关联规则基于如图的默认设置。</p>
<p>
	　　图 1. HTTP 测试生成的数据关联配置 1</p>
<center>
	<img alt="图 1. HTTP 测试生成的数据关联配置 1" border="1" height="394" src="/uploads/allimg/111209/09464HS2-0.png" width="572" /></center>
<p>
	　　图 2. HTTP 测试生成的数据关联配置 2</p>
<center>
	<img alt="图 2. HTTP 测试生成的数据关联配置 2" border="1" height="457" src="/uploads/allimg/111209/09464IZ4-1.png" width="572" /></center>
<p>
	　　3. HTTP 协议的 RPT 自动数据关联</p>
<p>
	　　3.1 主机和端口</p>
<p>
	　　基于 Web 的应用程序可能在一个测试，甚至在一个页面中会发起多个连接连接不同的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>。如图 3，在&ldquo;测试内容&rdquo;中，每个连接由相关联的请求下面的一个图标表示。选择连接，就可以看到具体连接信息和测试中使用这个连接的所有请求。由于最初录制的性能测试以后有可能需要在不同的系统环境中执行，可能有不同的主机或不同的端口，所以 RPT 提供了主机和端口的自动关联，图中该连接的主机自动关联到变量 192.168.0.27_Host，端口自动关联到变量 192.168.0.27_Port。</p>
<p>
	　　图 3. 主机和端口的自动数据关联</p>
<center>
	<img alt="图 3. 主机和端口的自动数据关联" border="1" height="211" src="/uploads/allimg/111209/09464LG4-2.png" width="572" /></center>
<p>
	　　3.2 Cookie</p>
<p>
	　　Cookie 由服务器生成，通常用来存储一些动态数据，如会话 ID、认证 token，从而辨别用户身份，进行会话跟踪等。用 Cookie 的形式提交动态数据的好处是其值往往来自 Cookie 自身。如果服务器选择使用 Cookie，会使用 Set-Cookie 语句在 HTTP 响应头中指定这些数据和值。当客户应用程序发出后续请求时，会将这些 Cookie 包含在 HTTP 请求头中发出。RPT 能够自动实现 cookie 的数据关联，在脚本回放时自动将请求中的 cookie 值替换为服务器实际返回的值。</p>
<p>
	　　3.3 URL</p>
<p>
	　　URL 的一般语法格式为 :</p>
<table border="0" cellpadding="0" cellspacing="0" id="table2" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
http[s]://hostname[:port]/path/[;parameters][?query]#fragment</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　query 字段通常是由 &amp; 符号连接的若干个&ldquo;name = value&rdquo;组成，RPT 首先从中分析出所有的 name 字段，将其放入特定列表，当生成测试脚本时，会搜索最近出现的响应头或相应内容中的 name=value，将 value 作为引用，自动与该 URL 中的 value 关联，如图 4 示例。</p>
<p>
	　　图 4. URL 自动数据关联</p>
<center>
	<img alt="图 4. URL 自动数据关联" border="1" height="90" src="/uploads/allimg/111209/09464IO2-3.png" width="572" />#p#分页标题#e#</center>
<p>
	　　3.4 重定向</p>
<p>
	　　当某请求的响应代码为 301，302，303，307 时，RPT 会自动将响应头中的 location 的真实路径作为引用，搜索后续请求的完整 URL，当发现匹配时进行自动关联，如图 5 示例：</p>
<p>
	　　图 5. 重定向 URL 自动数据关联</p>
<center>
	<img alt="图 5. 重定向 URL 自动数据关联" border="1" height="105" src="/uploads/allimg/111209/09464K632-4.png" width="572" /></center>
<p>
	　　3.5 请求内容</p>
<p>
	　　如果请求内容中出现由 &amp; 符号连接的&ldquo;name=value&rdquo;字段，则同 3.3 节，搜索最近出现的响应头或响应内容中的 name=value，进行自动关联，如图 6 示例：</p>
<p>
	　　图 6. 请求内容自动数据关联</p>
<center>
	<img alt="图 6. 请求内容自动数据关联" border="1" height="149" src="/uploads/allimg/111209/09464HB1-5.png" width="572" /></center>
<p>
	　　如果请求内容为 XML 文档格式，即以&ldquo;</p>
<p>
	　　图 7. XML 请求内容自动数据关联</p>
<center>
	<img alt="图 7. XML 请求内容自动数据关联" border="1" height="245" src="/uploads/allimg/111209/09464HU0-6.png" width="572" /></center>
<p>
	　　4. 基于 Jazz 产品的数据关联算法</p>
<p>
	　　IBM 基于 Jazz 平台的软件应用产品是 Jazz Foundation Services 的扩展实现，其基于 REST(Representational State Transfer)规范，以 REST API 的形式提供数据和服务的访问，也就是说可以通过 HTTP 的 POST/GET/PUT/DETELTE 方法来实现数据的 CREAT/READ/UPDATE/DELETE。</p>
<p>
	　　图 8. 基于 Jazz 产品的数据关联</p>
<center>
	<img alt="图 8. 基于 Jazz 产品的数据关联" border="1" height="322" src="/uploads/allimg/111209/09464KO5-7.png" width="534" /></center>
<p>
	　　RPT8.1 针对 Jazz 协议提供了在 HTTP 协议基础上的默认的数据关联规则支持，如图 2。</p>
<p>
	　　对于完整的请求 URL，除了自动实施上述 HTTP 协议的通用关联规则外，还要搜索最近的响应内容中出现的符合正则表达式 (?s)</p>
<link href="\&quot;[^\&quot;]*\&quot;" rel="\&quot;[^\&quot;]*\&quot;" title="" type="\&quot;[^\&quot;]*\&quot;" />
.*?src=\&quot;(.*?)\&quot;，将 src 字段的值作为引用，从而实现自动关联，如图 9 所示：
<p>
	　　图 9. Jazz URL 自动数据关联一</p>
<center>
	<img alt="图 9. Jazz URL 自动数据关联一" border="1" height="114" src="/uploads/allimg/111209/09464G347-8.png" width="572" /></center>
<p>
	　　对于请求头或请求内容中出现由 &amp; 符号连接的&ldquo;name=value&rdquo;字段，除了自动实施上述 HTTP 协议的通用关联规则外，还要对 name 匹配，如果 name 以&ldquo;id&rdquo;(不区分大小写)，&ldquo;Area&rdquo;，&ldquo;uuid_versionable&rdquo;，&ldquo;Values&rdquo;结尾，则向前在响应中搜索最近出现的 value 字段作为引用，实现自动关联，如图：</p>
<p>
	　　图 10. Jazz URL 自动数据关联二</p>
<center>
	<img alt="图 10. Jazz URL 自动数据关联二" border="1" height="85" src="/uploads/allimg/111209/09464H062-9.png" width="572" /></center>
<p>
	　　5. 数据关联规则扩展</p>
<p>
	　　然而在 Jazz 产品性能测试的实践过程中，我们发现，由于采用了 web2.0 等新技术，脚本的请求变得愈加复杂，使得目前的数据关联规则不能满足需要，数据关联成为测试脚本编辑和调试的瓶颈。因此在实际测试项目实践的基础上，借助 RPT 提供的数据关联扩展功能，我们在测试生成过程中实现了针对需求的 RPT 数据关联扩展规则。</p>
<p>
	　　首先需要了解测试生成阶段的数据关联原理。自动数据关联的实现类为 DataCorrelator 类。在测试生成阶段，RPT 数据关联引擎调用其方法 CorrelateAll()，该方法将遍历每个数据关联插件，调用插件中的 findSubs() 方法，找到需要替换的变量和位置，并将其加入列表 subSites 返回。之后扩展插件的 findReference() 方法搜索关联源并生成引用，默认从被替换的位置开始，向上搜索，直到找到最近的相匹配的引用。如图 11。</p>
<p>
	　　图 11. RPT 自动数据关联原理图</p>
<center>
	<img alt="图 11. RPT 自动数据关联原理图" border="1" height="266" src="/uploads/allimg/111209/09464IN3-10.png" width="398" /></center>
<p>
	　　因此，如果需要实现数据关联的扩展规则，则需要开发处符合自身被测试的应用需求的数据关联插件。本节将以自定义的插件 com.ibm.<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/" target="_blank" >rational</A></STRONG>.test.lt.datacorrelation.testgen.rta(简称 rta)为例进行阐述，该插件应用于基于 Jazz 产品的性能测试，主要功能是按照用户定制需求，将 RPT 自动生成的某些数据关联去掉，同时生成一些测试需要的关联。</p>
<p>
	　　RPT 提供了与数据关联相关的扩展点：</p>
<table border="0" cellpadding="0" cellspacing="0" id="table3" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
com.ibm.rational.test.lt.datacorrelation.testgen.DCTestgenProto</pre>
			</td>
		</tr>
	</tbody>
</table>
例子插件 rta 中，实现该扩展点的代码为：
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table4" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
&lt;extension
 point=&quot;com.ibm.rational.test.lt.datacorrelation.testgen.DCTestgenProto&quot;&gt;
 &lt;dcProtoAdapter
 class=&quot;com.ibm.rational.test.lt.datacorrelation.testgen.rta.RTAProtoAdapter&quot;
 generic=&quot;false&quot;
 protoType=&quot;com.ibm.rational.test.lt.models.behavior.http.HTTPRequest&quot;
 uniqueID=&quot;rtaProtoAdapter&quot;&gt;
 &lt;/extension&gt;</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　其中，point 为扩展点;protoType 为插件将要处理的协议的类型，例如 HTTP 协议为 com.ibm.rational.test.lt.models.behavior.http.HTTPRequest，因为基于 Jazz 的产品的性能测试是在 HTTP 协议的基础上处理的，所以该 rta 插件的协议类型亦声明为与 HTTP 协议相同;generic 是一个 boolean 型变量，如果取值为 True，在有多个插件共同处理同一协议类型时，此插件将会最后被调用;uniqueID 为该插件的唯一标识。#p#分页标题#e#</p>
<p>
	　　实现了该扩展点之后，当处理扩展中指定的协议的测试生成数据时，RPT 数据关联引擎会调用该扩展点声明的类中的相关代码，以例子插件为例，类的实现代码如下，完整代码请参见附件：</p>
<table border="0" cellpadding="0" cellspacing="0" id="table5" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="content">
public class RTAProtoAdapter extends HTTPProtoAdapter implements IProtoElementAdapter7_0 {
public RTAProtoAdapter() {
}

public List findSubs(ArrayList elem, int index) {
if (!(elem.get(index) instanceof HTTPRequest))
return null;
List subs = super.findSubs(elem, index);
RTASubSites subSites = new RTASubSites(elem, index);
subSites.processSites(subs);
return subSites.getList();
}

public void findReference(LTTest test, Substituter sub, ArrayList elem,
int index) {
if (!(elem.get(index) instanceof HTTPRequest))
return;
RTASource source = new RTASource();
source.findSource(sub, elem, index);
}

 ...
 
}</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　如图 12，在使用该插件之前，自动数据关联规则只实现了 processAreaUUID 的数据关联。</p>
<p>
	　　图 12. 使用 rta 插件前的自动数据关联</p>
<center>
	<img alt="图 12. 使用 rta 插件前的自动数据关联" border="1" height="89" src="/uploads/allimg/111209/09464IF0-11.png" width="572" /></center>
<p>
	　　在使用该插件之后，根据用户的配置需求，我们可以取消 processAreaUUID 的数据关联，增加 ItemID，StateID，TransactionID 这个几个关键词的数据关联。</p>
<p>
	　　图 13. 使用 rta 插件后的自定义动数据关联</p>
<center>
	<img alt="图 13. 使用 rta 插件后的自定义动数据关联" border="1" height="83" src="/uploads/allimg/111209/09464MP2-12.png" width="572" /></center>
<p>
	　　对于 rta 插件中关键词的设置，我们通过对 RPT 首选项的扩展实现，实现后的图形界面如图 14 所示，用户可方便地在界面上输入需要去除的数据关联和需要新增的数据关联。实现扩展点的代码如下所示，所涉及类的完整代码实现见附件。</p>
<table border="0" cellpadding="0" cellspacing="0" id="table6" width="100%">
	<tbody>
		<tr>
			<td class="code-outline">
				<pre class="displaycode">
<span class="content">&lt;extension
point=&quot;org.eclipse.ui.preferencePages&quot;&gt;
&lt;page
class=&quot;com.ibm.rational.test.lt.datacorrelation.testgen.rta.ui.preference.RTATest.GenPreferencePage&quot;
<span style="margin-top: 0px; font-size: 11px; margin-bottom: 0px; color: #ff0000; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace">|-------10--------20--------30--------40--------50--------60--------70--------80--------9|</span></span>
<span class="content" style="margin-top: 0px; font-size: 11px; margin-bottom: 0px; color: #ff0000; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace">|-------- XML error:  The previous line is longer than the max of 90 characters ---------|</span><span class="content">
category=&quot;com.ibm.rational.test.lt.testgen.ui.preference.RPTTestGenPreferencePage&quot;
name=&quot;RTA Test Generation&quot;
id=&quot;com.ibm.rational.test.lt.datacorrelation.testgen.rta.ui.preference.RTATestGenPreferencePage&quot;/&gt;
<span style="margin-top: 0px; font-size: 11px; margin-bottom: 0px; color: #ff0000; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace">|-------10--------20--------30--------40--------50--------60--------70--------80--------9|</span></span>
<span class="content" style="margin-top: 0px; font-size: 11px; margin-bottom: 0px; color: #ff0000; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace">|-------- XML error:  The previous line is longer than the max of 90 characters ---------|</span>
<span class="content">&lt;/extension&gt;</span><span class="content_a">
</span></pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　图 14. rta 设置界面</p>
<center>
	<img alt="图 13. rta 设置界面" border="1" height="578" src="/uploads/allimg/111209/09464J4M-13.png" width="572" /></center>
<p>
	　　总结</p>
<p>
	　　利用 Rational Performance Tester 进行性能测试的过程中，数据关联处理在测试脚本的编辑和调试中显得至关重要，其正确性直接影响加上负载后<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csgl/xtcs/" target="_blank" >系统测试</A></STRONG>的结果可信性。RPT 提供了脚本的自动数据关联功能，该自动关联规则基于使用中的最佳实践，能够满足大部分测试脚本的需求。但其规则内嵌于代码中，其不透明性决定了用户对自动关联结果的茫然，本文揭秘了 RPT 自动数据关联的详细规则，使得用户对自动生成的测试脚本更加了解、容易掌控。而且对于复杂的被测应用系统，RPT 还提供了扩充数据关联规则的方法，本文以实例说明了如何扩展数据关联规则，方便用户在了解具体待测试的应用的基础上，根据需求在此规则上加入自定义的规则，从而大大提高了脚本编辑和调试的效率。</p>
<p>
	　　参考资料</p>
<p>
	　　学习</p>
<p>
	　　仔细查 Rational Performance Tester 信息中心。</p>
<p>
	　　参考 Jazz.net 了解更多基于 Jazz 的产品，并下载使用 Jazz 产品：</p>
<p>
	　　Rational Team Concert(RTC)</p>
<p>
	　　Rational Quality Manager and Rational Test Lab Manager (<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/rqm/" target="_blank" >RQM</A></STRONG>)</p>
<p>
	　　Rational Requirements Composer (RRC)</p>
<p>
	　　Rational Project Conductor (RPC)</p>
<p>
	　　访问 developerWorks 中国网站的 Jazz 技术空间，这里汇集了丰富的 Jazz 平台中文技术资源。 您可以通过这里了解更多关于 Jazz 平台和 Jazz 技术发展趋势的最新信息。</p>
#p#分页标题#e#<p>
	　　访问 IBM developerWorks 中国网站 Rational 专区，获得关于 IBM Rational 软件交付平台(Rational Software Delivery Platform)产品的技术资源和最佳实践。</p>
<p>
	　　订阅 IBM developerWorks 时事通讯，一份关于 developerWorks 指南、文章、下载、社区活动、<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlzs/" target="_blank" >网络</A></STRONG>广播和技术讲座的电子周刊。</p>
<p>
	　　学习 Hello World 系列教程，这是学习 IBM 软件工具的快速通道。在每一篇教程中，都会有快速入门产品演示动画。您可以通过其中的动画演示快速浏览如何使用 IBM 软件完成开发任务。</p>
<p>
	　　获得产品和技术</p>
<p>
	　　访问 IBM Rational 软件交付平台 V7 <STRONG><A href="http://www.ltesting.net/ceshi/zhuanti/" target="_blank" >专题</A></STRONG>，了解 Rational V7 产品的方方面面。</p>
<p>
	　　查看 IBM&reg; Rational&reg; 测试人员资源工具包。</p>
<p>
	　　获取免费的 Rational 软件工具包系列，了解最新的 IBM Rational 软件开发工具技术文档和资源。</p>
<p>
	　　下载免费的 IBM Rational Performance Tester 试用版。</p>
<p>
	　　下载免费的 IBM Rational 试用版软件，了解 IBM Rational 软件的最新特性。</p>
<p>
	　　获取更多 IBM 试用版软件，并熟练掌握来自 DB2&reg;、Lotus&reg;、Tivoli&reg;，以及 <STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/zjj/websphe/" target="_blank" >WebSphere</A></STRONG>&reg; 的开发工具和<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/zjj/" target="_blank" >中间件</A></STRONG>产品，用这些试用版软件开发您的下一个项目。这些试用版软件可以免费直接从 developerWorks 下载。</p>
]]></description>
    <pubDate>Fri, 09 Dec 2011 09:45:34 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111209/09464HS2-0-lp.png</subImagePath>
     <category>PerformeranceTester</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[使用Functional Tester的一项测试技术]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/functionaltester/2011/1209/203739.html</link>
    <description><![CDATA[<table align="center" border="0" cellpadding="1" cellspacing="1" class="content" width="90%">
	<tbody>
		<tr>
			<td valign="top">
				<p>
					使用传统的制表格式介绍决策过程。 决策表提供了一个简单的，可视化的帮助，它可以在<STRONG><A href="http://www.ltesting.net/ask/" target="_blank" >知识</A></STRONG>库系统中被使用，来高效的执行验证过程。在软件<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>过程中，决策表能够帮助测试小组在软件应用程序中管理复杂的逻辑性。</p>
				<p>
					这篇文章介绍了一种基于决策表的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/" target="_blank" >测试技术</A></STRONG>，描述了一种使用 IBM Rational Functional Tester 和 IBM Rational Software Modeler 的实现方法。这项技术常常通过运行一系列复用测试脚本来详细描述非<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csgl/hgcs/" target="_blank" >回归测试</A></STRONG>套件。每一个测试脚本都是使用 Functional Tester 的 GUI 记录/回放技术产生的。</p>
				<p>
					这里，我的目标是&quot;概念证明&quot;。为此，我花费了5天的时间开发了一个<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcskfyy/java/" target="_blank" >Java</A></STRONG>类库，用来使用 IBM Rational 工具实现决策表技术。虽然这项技术还没有被部署到实际项目中，但是我会通过使用基于Eclipse框架的IBM Rational工具来论证这个方法的潜力。我计划的实现方法是完全基于标准的，文档化的接口，任何读者都可以很容易的理解。</p>
				<p>
					<strong>问题</strong></p>
				<p>
					非回归测试是基于数据驱动的测试技术，一个简单的测试脚本会根据输入数据的不同而反复的被使用，这在测试自动化方面是很常见的。 这项技术可以使用Functional Tester中的数据池来实现，这些数据池是在一个测试脚本建立期间或者建立之后关联在测试脚本上的。不幸的是，当测试应用程序陷入复杂的逻辑中时，数据驱动的测试在没有硬编码的情况下变得难以实现。一般来说，应用程序的行为是受组成测试套件的测试脚本的不同输入数据影响的。我们需要使用等值划分来区别输入的数据，它可以提供一个AUT(被测试的应用程序)的等价行为。在每一个测试套件中都要使用硬编码环境，它能帮助我们向着正确的测试路径前进，并且可以处理数据的变化。这个方法不仅适用于测试人员，同样对于开发人员来说也很&quot;有趣&quot;，特别是在使用自动化<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>时，因为在硬编码的测试脚本环境中，使得维护以及测试脚本的扩变得非常难以管理。此外，如果在头脑中没有一个清晰的策略，是很难优化测试脚本分解的。</p>
				<p>
					<strong>建议方法</strong></p>
				<p>
					当一个测试人员手动实现一个测试程序时，他会根据测试目的选择输入的数据，并根据AUT的行为作决策。问题是，我们怎样在不使用硬编码而使用<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/zdcs/" target="_blank" >自动化测试</A></STRONG>工具的决策制定过程中帮助测试人员?</p>
				<p>
					这个简单的问题使我们去考虑决策表技术，并开发一个Java类库来验证这个概念。决策表通过Functional Tester数据池实现。通过决策表提供的用于解释测试逻辑的决策脚本，被整合到测试套件的体系架构中，如图1所示。其他组成测试套件的可重用测试脚本是通过使用Functional Tester的GUI记录/回放技术产生的。一个测试片断被定义成一个测试脚本的序列，它可能是两个决策脚本之间的序列，或者是开始脚本和决策脚本的序列，再或者是决策脚本和结束脚本的序列。一个数据驱动表和测试套件连接在一起，它可以根据不同的输入数据重复运行测试套件，并把结果输入给不同的测试脚本。</p>
				<p>
					<img height="317" src="/uploads/allimg/111209/0944515Q5-0.gif" width="245" /></p>
				<p>
					图1：由测试脚本和决策脚本组成的测试套件。</p>
				<p>
					这项技术提供了以下好处：<br />
					　　一种详细描述测试套件和测试脚本的形式化方法<br />
					　　在决策脚本中封装测试套件逻辑<br />
					　　以决策点为中心的测试套件体系架构<br />
					　　测试逻辑可以很容易地使用决策表进行追踪与变更，这样可以被非程序员阅读和填写一个更加灵活的数据驱动的实现方法。</p>
				<p>
					<strong>基于决策表的测试技术</strong></p>
				<p>
					在测试过程中当达到一个决策点时，测试人员会检查AUT的状态并决定测试活动。每一个决策点都可以用一个决策表来指定。一个决策表由两部分组成：条件和活动。决策表列出了一个测试活动执行所需的条件。每一个条件表达了各种变量之间的关系是正确的还是错误的。所有可能的条件组合定义了一系列的选择。对于每一个选择，测试活动都要考虑到。选择的数量使得条件种类呈指数级增加，可能会显示为2NumberOfConditions。当决策表变得复杂时，一个新的决策表层级就会被创建。</p>
				<p>
					由于一些选择的情况是不存在的，所以一个测试策略应该是：1) 验证所有可能实现的选择。2) 描述AUT是如何在所有选择环境下运转的。有了决策表，我们就可以根据测试策略轻松的添加和删除条件。我们可以根据测试策率的需要，通过反复的添加新的测试条件来增加测试的覆盖率。</p>
				<p>
					如图2所示，决策表在指定，分析和测试复杂逻辑性时起到很重要的作用。它们可以很有效的描述不同条件产生不同的测试活动。它们还可以有效的查找到执行与规范中的错误。</p>
				<p>
					<img height="387" src="/uploads/allimg/111209/094451JT-1.gif" width="541" /></p>
				<p>
					图2：一个决策表的例子</p>
				<p>
					<strong>使用决策和数据驱动表</strong></p>
				<p>
					在每一个决策点，一个决策表要列出AUT(根据条件)需要校验哪些内容，以及下一个活动是什么。由于决策表中已经定义了逻辑，所以测试人员不需要硬编码任何测试逻辑。决策脚本只需在运行期间执行确认工作，比较决策表提供的验证结果，并且如果找到了<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/jjfa/" target="_blank" >解决方案</A></STRONG>，返回并运行下一个测试脚本。</p>
				<p>
					一个测试套件脚本包含很多决策脚本和测试脚本。一个测试套件的所有元素都在一个驱动表中被定义，在这个驱动表中列出了一系列无序的测试片断。每一个测试片断由在两个决策脚本之间顺序执行的测试脚本组成。对于每一个测试片断来说，驱动表列出了一个源测试脚本和一个目标测试脚本之间的转换。</p>
				<p>
					随着决策在执行期间被决策脚本动态的计算出来，需要为测试套件脚本实现一种通知机制，用来通过测试脚本通知下一个需要运行的测试脚本。当决策脚本通知测试套件脚本下一个应该运行的测试脚本时，测试套件脚本请求驱动表，查询下一个应该运行的测试片断。这个过程如图3所示：</p>
				<p>
					<img height="371" src="/uploads/allimg/111209/09445112W-2.gif" width="553" /></p>
				<p>
					图3：一个测试套件的元素</p>
				<p>
					一般情况下，一个测试套件中的任何测试脚本都需要为数据输入连接到一个数据池。当一个数据驱动表连接到测试套件时，我们就可以将输入的各种组合的数据记录列入到测试脚本和动态变化的AUT行为中。当AUT的行为发生变化时，每一个决策脚本提供的结果都会变化，因此通过AUT的测试路径就会变化。通过一个简单的测试套件脚本，我们可以验证很多测试路径。这样可以轻松的合并输入的数据和扩大测试套件的范围，并在决策表中添加新条件。</p>
				<p>
					这种方法清晰的将决策脚本中的测试逻辑封装与测试脚本中执行的测试动作和验证分离开来。AUT中决策点的识别，能够帮助我们形式化并且精化从测试套件到测试脚本的分解。</p>
				<p>
					这种方法清晰的将决策脚本中的测试逻辑封装与测试脚本中执行的测试动作和验证分离开来。AUT中决策点的识别，能够帮助我们形式化并且精化从测试套件到测试脚本的分解。</p>
				<p>
					<strong>使用 Functional Tester 实现此项技术</strong></p>
				<p>
					作为这个概念证明的一部分，我开发了一个Java库，用来使用Functional Tester实现基于决策表的技术。请按照下列步骤建立一个测试套件脚本：<br />
					　　重用测试套件代码模版并填写测试套件驱动表<br />
					　　使用一个代码模版建立决策脚本，并填写决策表<br />
					　　填写数据驱动表<br />
					　　基于决策表的测试库<br />
					　　基于决策表的测试库由Java类组成，它提供了下列服务：<br />
					　　初始化并重复的穿过在驱动表中定义的测试套件结构<br />
					　　浏览决策表并比较AUT中执行的验证选择</p>
				<p>
					决策脚本和测试套件脚本之间的事件侦听机制对于测试人员来说是透明的。它是通过库中的DecisionBuilder和 TestSuiteDriver类来实现的，如图4所示。为了使用库中的服务，测试人员建立的每一个测试套件脚本以及决策脚本都必须继承 TestSuiteHelper 4 类，因为它提供了一个连接到库的接口。为此，测试人员每次建立新测试套件或者决策脚本时都需要选择这个父帮助类。</p>
				<p>
					<img height="305" src="/uploads/allimg/111209/09445124Y-3.gif" width="570" /></p>
				<p>
					图4：基于决策表测试库的主类</p>
				<p>
					<strong>建立一个新的测试测试套件</strong></p>
				<p>
					测试套件可以在业务层面或者系统用例层面被用来实现自动化测试策略。在系统用例层面，一个测试套件实现用例场景。在页面层面，一个测试套件跨越几个用例追踪业务流程。对于一个给定的测试级别，测试套件可以根据回归<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csmb/csjh/" target="_blank" >测试计划</A></STRONG>中定义的测试目标来组织。例如，测试套件可以集中在业务规则验证或者服务传递或者数据完整性检查(创建，更改，删除)上。虽然理论上可以只使用一个测试套件，但是在实践中这种情况难以管理。因此，测试人员必须根据测试选择设计测试套件，并且拥有一个运行测试套件的测试套件是有意义的。</p>
				<p>
					为了建立一个新的测试套件，测试人员需要做以下工作：<br />
					　　使用Functional Tester建立一个空的测试脚本<br />
					　　在测试套件脚本中插入代码模版(测试套件的代码模版如图5所示。)<br />
					　　列出驱动表和数据驱动表的名</p>
				<p>
					<img height="324" src="/uploads/allimg/111209/0944511194-4.gif" width="570" /></p>
				<p>
					图5：测试套件脚本的代码模版</p>
				<p>
					如图6所示，每一个测试套件的结构都在测试套件驱动表中描述了，一个数据池定义了测试脚本(例如从源脚本到目标脚本的转换)。次序并不重要，因为TestSuiteDriver类可以解析驱动数据池并且在存储器中加载测试套间的结构。然而，你必须定义开始和结束脚本。测试人员可以填写这个表格，来指定测试套件或者从测试套件的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/uml/" target="_blank" >UML</A></STRONG>定义产生这个数据池(可以在稍后的章节查看&quot;使用IBM Rational Software Modeler模块化设计测试套件&quot;)。</p>
				<p>
					<img height="292" src="/uploads/allimg/111209/094451M37-5.gif" width="527" /></p>
				<p>
					图6：测试套件驱动表的实例</p>
				<p>
					<strong>建立一个数据驱动测试套件</strong></p>
				<p>
					一个数据驱动表可以被连接到测试套件脚本，用来1) 控制数据输入到不同测试脚本以及2) 建立通过AUT的不同路径。数据驱动表的标题包含测试套件的测试脚本所使用的数据池的名称。数据驱动表的每一行表示一种不同的输入数据记录的整合，这个输入数据记录用在每一个测试脚本数据池中。如图7所示，数据驱动表的第一列是一个测试套件的true/false标志位，这个标志位用来表示一行是否依靠于测试对象。</p>
				<p>
					<img height="192" src="/uploads/allimg/111209/0944513616-6.gif" width="570" /></p>
				<p>
					图7：测试套件数据驱动表的实例</p>
				<p>
					每一个测试脚本数据池通常包含一个标志，它用来显示测试脚本在数据池的完整回归过程中是否必须选择一项记录。当测试套件开始新的回归时， TestSuiteDriver类会读取测试套件驱动表，并设置测试脚本数据池选择标志位，所有测试脚本都会重复这项工作。因而，当一个测试脚本数据池记录发生回归时，只有驱动表中列出的记录会被考虑。这个机制被库文件管理，并且对于测试人员来说是完全透明的。唯一的约束就是所有数据池的 SelectRecord标志位。</p>
				<p>
					<strong>建立一个决策测试脚本</strong></p>
				<p>
					测试人员识别测试套件流中的决策点，并为每一个决策点建立一个决策测试脚本。当测试套件流通过UML实体图设计时，每一种条件(请查看&quot;使用IBM Rational Software Modeler 建模测试套件&quot;章节)都会建立一个决策测试脚本。</p>
				<p>
					为了执行一个决策点，测试人员需要完成以下工作：<br />
					　　建立并填写决策数据池<br />
					　　建立一个空决策测试脚本并插入代码模版<br />
					　　为每一个决策条件注册验证点</p>
				<p>
					首先，测试人员使用Functional Tester数据池建立一个决策表。决策表的实例如图8所示，它也可以通过测试套件的UML定义产生请查看&quot;使用IBM Rational Software Modeler 建模测试套件&quot;章节)。决策脚本把AUT执行的验证结果与条件入口相比较，以便识别执行的测试活动(例如下一个需要运行的测试脚本)。当一个合并不可能或者还没有被实现时，数据池中的行将会被排斥，并且测试活动是未定义的。</p>
				<p>
					<img height="228" src="/uploads/allimg/111209/0944513513-7.gif" width="543" /></p>
				<p>
					第二步，测试人员建立一个空的测试脚本，在测试脚本中插入代码模版(如图9所示)，并列出决策数据池的名称。测试人员使用Functional Tester插入确认点来捕获决策表所需信息。</p>
				<p>
					<img height="255" src="/uploads/allimg/111209/094451J44-8.gif" width="570" /></p>
				<p>
					图9：决策脚本的代码模版</p>
				<p>
					<strong>使用IBM Rational Software Modeler 建模测试套件</strong></p>
				<p>
					测试套件使用一个UML活动图来设计，图中每一个活动都和一个测试活动(测试脚本)通信，并且每一个决策都会和一个决策脚本通信，如图10所示。决策点列出的条件用来产生通讯的决策表。活动图很容易被非开发人员使用和理解。</p>
				<p>
					<img height="396" src="/uploads/allimg/111209/0944511301-9.gif" width="570" /></p>
				<p>
					一个&quot;datastore&quot;类型的目标节点可以被连接到一个测试活动，来指定这个测试活动需要的一个数据池。通过类指定数据池结构也是可行的方案。数据池的每一列都会和一个类的属性通信。一个UML解析器可以产生所有Functional Tester运行测试套件所需的数据池，包括驱动表，决策表和数据驱动表和测试脚本数据池的结构。活动图表和类图都可以在一个协作元素下组织起来，如图 11所示。可追溯的连接可以在测试套件定义和用例模块之间建立，如图12所示。一个更加成熟的方法可以使用IBM Rational Software Modeler提供的转换工具进行开发。</p>
				<p>
					<img height="553" src="/uploads/allimg/111209/0944515I3-10.gif" width="570" /></p>
				<p>
					图11：测试套件的定义被封装在一个协作之下。</p>
				<p>
					<img height="288" src="/uploads/allimg/111209/0944516315-11.gif" width="570" /></p>
				<p>
					图12：测试套件和其他模块元素之间的追踪连接</p>
				<p>
					我开发了一个UML解析器，它能够以XML格式产生测试套件驱动表，决策表以及数据池(例如数据驱动表和测试脚本输入数据表的结构)。当选择协作时，一个拥有上下文菜单的Eclipse插件程序将会被用来产生测试套件表，如图13所示。</p>
				<p>
					<img height="256" src="/uploads/allimg/111209/094451C95-12.gif" width="481" /></p>
				<p>
					图13：类库用来从UML定义产生测试套件表</p>
				<p>
					所有可能的选择都自动的产生在决策表数据池中，如图14所示。只产生了活动图中列出的测试活动。新的测试活动没有被列在活动图表中，但是可以在导入到Functional Tester测试项目之前添加到决策表中。</p>
				<p>
					<img src="/uploads/allimg/111209/094451D57-13.gif" /></p>
				<p>
					图14：决策表中产生的所有可能组合。</p>
				<p>
					<strong>结论</strong></p>
				<p>
					我相信这种基于决策表的测试技术能够极大得改进测试人员在自动化测试期间管理决策的能力。使用IBM Rational Functional Tester和IBM Rational Software Modeler，这项技术可以通过实现一个可复用的测试脚本来促进非回归测试套件。</p>
				<p>
					正如我在介绍中提到的，虽然这项技术还没有应用到实际项目中，但是使用出于此目的而建立的Java类库显示这项技术是可行的。</p>
				<p>
					进一步的工作现在正在进展中，它可以扩展测试建模方法的引入。IBM Rational Software Architect提供的模型转换服务将会用于测试自动化的辅助设计。</p>
			</td>
		</tr>
		<tr>
			<td valign="top">
				&nbsp;</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#]]></description>
    <pubDate>Fri, 09 Dec 2011 09:43:34 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111209/0944515Q5-0-lp.gif</subImagePath>
     <category>FunctionalTester</category>
    <author>娃娃</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[Robot中验证点的使用]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/2011/1208/203737.html</link>
    <description><![CDATA[<p>
	　　用<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/" target="_blank" >Robot</A></STRONG>进行<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/" target="_blank" >功能测试</A></STRONG>时，可以在录制好的脚本中添加验证点来判断脚本执行后程序是否达到了预期的结果。</p>
<p>
	　　验证点的思想是通过比较控件的基准值与回放脚本时的值来判断程序是否按照预期的设想在执行[基准值是指录制脚本时所选控件的某些属性，具体取哪些属性依赖于添加的验证点类型]。通常录制好验证点后，都会生成一个基线数据文件，此文件的值是录制脚本时控件的某些属性的值或者是控件的数据，可以手工修改。</p>
<p>
	　　创建验证点时，可以设置重新获取时间及超时时间。</p>
<p>
	　　重新获取时间：在回放脚本时如果验证点没有验证成功，Robot将会间隔一段时间去重新获取验证点信息，这个时间就是重新获取时间。</p>
<p>
	　　超时时间：在回放脚本时如果验证点没有验证成功，Robot会间隔一段时间去重新获取验证点信息，但是过了一定时间就会停止,接着执行下面的脚本。这个时间就是超时时间。</p>
<p>
	　　一般常用的验证点有以下几种类型：</p>
<p>
	　　一、 Alphanumeric</p>
<p>
	　　使用Alphanumeric验证点从单行或多行编辑框及其他Robot可以识别的对象中捕获并比较字母或数字的值。包括CheckBox,Generic,GroupBox,Label, PushButton,RadioButton,ToolBar,Window(只能处理Caption)。</p>
<p>
	　　使用此类验证点可以验证文本的改变，拼写错误，以及确保数值的准确。</p>
<p>
	　　增加此类验证点后，会生成一个基准数据文件，可以用Text Comparator打开基准文件进行编辑。(对于Numeric Equivalence和Numeric Range两类验证点不会生成基准文件，基准值直接生成在脚本的验证函数中，也可以修改)。</p>
<p>
	　　Alphanumeric细分为下面的类型：</p>
<p>
	　　1、Case-Sensitive：验证录制脚本时捕捉到的文字是否与回放脚本时捕捉到的文字匹配(大小写敏感)</p>
<p>
	　　2、Case-InSensitive：验证录制脚本时捕捉到的文字是否与回放脚本时捕捉到的文字匹配(大小写不敏感)</p>
<p>
	　　3、Find Sub String Case-Sensitive：录制脚本时捕捉到的文字是否是回放脚本时捕捉到文字的子串(大小写敏感)</p>
<p>
	　　4、Find Sub String Case-InSensitive：录制脚本时捕捉到的文字是否是回放脚本时捕捉到文字的子串(大小写不敏感)</p>
<p>
	　　5、Numeric Equivalence:验证录制脚本时捕捉到的值是否与回放脚本时捕捉到的值相等。</p>
<p>
	　　6、Numeric Range：验证录制脚本时捕捉到的值是否属于回放脚本时一个特定的范围。</p>
<p>
	　　7、Apply a User_Defined DLL test function：回放脚本时需要验证的值是经过用户自定义的函数运算出来的。在此将DLL名称与函数名称指定好，脚本回放时，Robot将捕捉到的值与函数运算的结果相比较。</p>
<p>
	　　8、Verify that selected field is blank：验证所选区域是否为空。如果所选区域不包含任何文字或数字，那么验证点将执行成功。对于ListBox,ComboBox，如果没有任何项被选中，Robot也认为所选区域是空的。</p>
<p>
	　　二、 Menu</p>
<p>
	　　使用此验证点捕获所选菜单的标题、菜单项、快捷键和状态(enable，disabled，grayed 或 checked)。Robot可以记录五级子菜单的信息。添加此类验证点时，可以根据需要选择部分菜单进行验证,也可以直接编辑菜单项的值来改变捕捉到的基准值。回放脚本时，Robot会检测所选菜单的内容、状态、快捷键是否与基准值一致,而对菜单项的位置不做检测。</p>
<p>
	　　三、 Object Data</p>
<p>
	　　使用ObjectData验证点对对象中的数据进行验证，这些对象包括：标准的Window控件、ActiveX控件、<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/vb/" target="_blank" >VB</A></STRONG>的Data控件、HTML及<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcskfyy/java/" target="_blank" >Java</A></STRONG>对象、PowerBuilder的DataWindow和DataStore控件、菜单。同Menu验证点一样，也可以只选择部分数据作为基准值进行测试。</p>
<p>
	　　四、 Object Properties</p>
<p>
	　　使用Object Properties验证点对标准<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/windows/" target="_blank" >Windows</A></STRONG>对象的属性进行验证(属性指控件的一些特征,比如编辑框的name、readonly、value等等)。也支持一些特殊的对象如ActiveX控件、VB的Data控件、HTML及Java对象、PowerBuilder的DataWindow。添加此类验证点后，Robot将显示出被捕获的对象及其相应属性的列表。你可以从对象的列表中选择你想要测试的属性。</p>
<p>
	　　五、 Window Existence</p>
<p>
	　　使用Windows Existence验证点来判断窗口是否存在以及验证窗口的状态。这些状态包括：正常、最小化、最大化或者是隐藏。此类验证点不生成基准数据文件。要修改基准数据必须重新录制脚本。最常用的是用来验证点击按钮后是否出现了预期的窗口。</p>
<p>
	　　六、Clipboard</p>
<p>
	　　对于用其他类型的VP不能捕获的对象文本，使用Clipboard类型。被测应用程序必须支持拷贝或剪切功能，这样才能将对象数据拷贝到Clipboard中进行比较。这种VP对于从电子表格和文字处理的应用程序捕获数据，是十分有效的。但它不能用于测试位图。</p>
<p>
	　　七、Menu</p>
<p>
	　　使用Menu VP可以捕获所选菜单的标题、菜单项、快捷键和状态(enable，disabled，grayed 或 checked)。Robot可以记录五级子菜单的信息。</p>
<p>
	　　八、Region Image</p>
<p>
	　　使用Region Image VP来选择屏幕的一个区域，Robot将其捕获并存成位图。该区域可以交迭多个窗体。要使该类VP通过验证，选择区域的位置和屏幕的分辨率在回放时应该与录制时保持一致。</p>
<p>
	　　九、Windows Image</p>
<p>
	　　使用Window Image VP来选择和捕获客户端窗体的一个区域。其菜单、标题栏和边框不在捕获的图象范围之内。Robot能够捕获整个窗体或是它的一部分，窗体可以与其他窗体或是部分屏幕重叠。在这种情况下，Robot捕获该窗体并将那些不可见的部分保存为黑色。被捕获的区域是一个象素图象，它包括颜色、高度和宽度。 要使该类VP通过验证，窗体的大小和屏幕的分辨率应该在回放时与录制时保持一致。</p>
<p>
	　　十、File Comparison</p>
<p>
	　　使用File Comparison VP在回放时来比较两个指定的文件。这种比较是基于文件的内容和大小，而不是文件的名称和日期。</p>
<p>
	　　在创建此类VP的时候，你需要指定驱动器、目录和文件名。在回放时，Robot按字节来比较该文件。</p>
<p>
	　　注意：File Comparison VP 的名称并不出现在Asset pane中。(File Comparison 验证点的文件比较原理同DOS下的FC命令相同，但是没有FC命令可扩展，即FC可以带参数，但File Comparison 验证点不能带参数，只是进行二进制比较;其中的例子就是：对两个相同的ACCESS文件进行比较，无论怎么执行File Comparison 验证点，比较结果都是不同的，但如果用FC命令结果是两文件相同，所以File Comparison 验证点没有DOS下的FC命令强大，所以它对DOC文件、TXT文件比较是没问题，一旦对MDB、XLS文件比较，File Comparison 验证点就不是我们想象的结果;)#p#分页标题#e#</p>
<p>
	　　十一、File Existence</p>
<p>
	　　使用File Existence VP在回放时来查找一个文件。在创建此类VP的时候，你需要指定该文件的驱动器、目录和文件名。在回放时，Robot在指定的位置检查文件是否存在。</p>
<p>
	　　注意：File Existence VP 的名称并不出现在Asset pane中。</p>
<p>
	　　十二、Module Existence</p>
<p>
	　　用于验证指定的模块是否被装载到了指定的环境或过程中来，或者是否被装如了内存。在Windows环境下，模块被定义为可执行程序(.exe)、动态连接库(.dll或其他扩展名)、设备驱动程序(.sys 或.drv)或者是显示字体(.fon)。</p>
<p>
	　　每一个过程都有属于自己的环境，它包括一系列被装载的模块。当你创建此类VP的时候，要选择模块的名称。你还可以选择环境(过程)的名称，在该环境下，VP验证模块是否被装载进了该过程。如果你没有指定环境，VP将验证该模块是否被装载进了内存(不论何处)。</p>
<p>
	　　注意：Module Existence VP 的名称并不出现在Asset pane中。</p>
<p>
	　　十三、Web Site Scan</p>
<p>
	　　当你回放一个Web Site Scan VP时，SiteCheck 启动运行并且根据你录制该VP时所选择的选项来浏览该站点。如果发现了任何的缺陷，该VP将失败。</p>
<p>
	　　在你回放一个Web Site Scan VP之后，你可以在<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/testmanager/" target="_blank" >TestManager</A></STRONG>的日志中查看回放的结果。</p>
<p>
	　　十四、Web Site Compare</p>
<p>
	　　当你回放一个Web Site Compare VP时，SiteCheck 启动运行并将你所选择的基线与你录制该VP时所选择的站点进行比较。如果发现了任何的缺陷，该VP将失败。</p>
<p>
	　　在你回放一个Web Site Compare VP 之后，你可以在TestManager的日志中查看回放的结果</p>
<p>
	　　下面通过一个实际的例子演示一下如何使用验证点。</p>
<p>
	　　数据准备：Forp办公资源系统 我的工作&mdash;目录维护模块</p>
<p>
	　　验证内容：选择一个目录，点击编辑后 是否出现了期望的编辑窗口。</p>
<p>
	　　操作步骤：</p>
<p>
	　　1、录制脚本，功能：选择一个目录，点击编辑，然后直接保存。(脚本忽略)。</p>
<p>
	　　2、在脚本的编辑代码下面，插入验证点Window Existence。出现如下对话框。可以给验证点命名、设置重新获取时间及超时时间、选择期待的验证结果。</p>
<p>
	　　3、设置各项参数后，点击OK，出现下图的对话框，在输入框中填写需要验证窗体的识别方式&ldquo; Caption=维护目录 &ndash; 网页对话框&rdquo;。如果不知道窗体的识别方式，可以点击Select按钮去选择窗体。</p>
<p>
	　　4、点击OK后，自动生成脚本</p>
<p>
	　　Result = WindowVP (Exists, &quot;Caption=维护目录 &ndash; 网页对话框&quot;, &quot;VP=Window Existence;Status=NORMAL&quot;)</p>
<p>
	　　5、执行脚本，结束后会在TestManager中生成日志文件来记录脚本及验证点的执行结果。</p>
]]></description>
    <pubDate>Thu, 08 Dec 2011 09:43:30 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>Robot</category>
    <author>领测软件测试网采编</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[浅谈Rational Robot自动化测试]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/2011/1208/203736.html</link>
    <description><![CDATA[<p>
	　　Ratoinal Robot是一种可扩展、灵活的功能<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>，它是<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/" target="_blank" >Rational</A></STRONG> Suites下的一个组件，对于比较熟悉它的测试人员可以修改测试脚本，改进测试的深度。Ratoinal Robot为菜单、列表、字母数字字符及位图等对象提供了<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csyl/" target="_blank" >测试用例</A></STRONG>。具体来说，它可以做到以下测试：</p>
<p>
	　　(1)基于GUI的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/" target="_blank" >功能测试</A></STRONG>：它可以记录用户软件的操作，将这些动作转换为脚本(脚本是不区分大小写的)，然后通过回放脚本，来验证软件的功能是否正确。</p>
<p>
	　　(2)对<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlzs/" target="_blank" >网络</A></STRONG>应用程序进行<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/xncs/" target="_blank" >性能测试</A></STRONG>：它可以模拟很多虚拟用户来应用网络应用程序，从而判断程序性能是否符合要求。当然，这也是通过录制和回放脚本来办到的。</p>
<p>
	　　根据功能的不同，Robot脚本也可以分为两类SQA Basic脚本与VU脚本。这两种脚本分别对应以上的基于GUI功能测试与网络应用程序的性能测试。它们不能互相换用，而且，不仅它们的用途不同，语法也大相径庭。SQA Basic用的是Basic语法，而VU脚本用的是C语言的语法。</p>
<p>
	　　目前达梦<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>客户端的功能采用Ratoinal Robot进行测试。对数据库客户端的操作、在需要进行对比验证的时候设置验证点，它都会记录下来并转换成SQA Basic脚本。当进行测试时，可以使用Ratoinal Robot的脚本的回放功能来达到<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/zdcs/" target="_blank" >自动化测试</A></STRONG>的目的，验证软件的功能是否正确。下面简单介绍一下Ratoinal Robot在测试达梦数据库的客户端当中的应用。</p>
<p>
	　　新建工程</p>
<p>
	　　第一次使用Ratoinal Robot时，它的Project项是空的，也就是说当前没有项目可用，需要进入到Rational Suites的另一个组件Rational Administrator中去新建一个项目，在Rational Administrator中选择File-&gt;New Project，可以打开新建工程的向导，根据向导可以建一个自己命名的项目，设置此项目的密码，密码可以为空。之后再次打开它时就可以使用已有的项目与用户了。</p>
<p>
	　　录制脚本</p>
<p>
	　　选择菜单Record GUI或是点击工具栏上的GUI图标按扭，可打开录制脚本对话框，在对话框中输入脚本名称，可以按测试步骤对数据库客户端进行操作，当前对电脑的任何操作都可以被录制进来，所以在测试的过程中尽量不要运行一些自动弹出窗口的软件，以免影响测试的脚本的正确性或增加修改脚本的工作量。录制脚本的过程当中Rational Robot在最高层会有一个小窗口，此窗口有四个图标按钮:pause Recording(暂停录制)、stop Recording(结束录制)、open Robot Window(打开Robot窗口)、Display GUI Insert Toolbar(显示)，使用pause Recording时，Robot事实上并没有退出，当前所做的任何操作也不会被录制成脚本;使用stop Recording时结束脚本录制;open Robot Window打开Robot窗口可以看到刚才录制的脚本，但打开Robot窗口的操作不录制成脚本;Display GUI Insert Toolbar会打开插入GUI验证点工具栏，需要作对比验证的时候可以使用这个图标按钮。</p>
<p>
	　　修改脚本</p>
<p>
	　　直接录制的脚本在实际中很少具有实用价值，一般都会对其进行或多或少的修改，如上面一个步骤录制的脚本如果放到另外一台机器上去运行，很有可能就会现在这个脚本跟本无法执行成功。如，达梦数据库安装的目录是可修改的，如果在录制脚本的过程中涉及到目录的时候，脚本中会出现绝对路径，在另外一台机器上安装达梦数据库的目录不同时，执行脚本就会不成功。如下例是一个录制的脚本，看看有哪些地方需要修改后才能到其它的机器上运行成功，下面的例子就是打开达梦数据库的客户端工具ISQL，登录数据库<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>，然后打开达梦数据库安装目录下的一个文件，由于下面需要多次使用到达梦数据库的安装路径，而且安装数据库时路径是可更改的，用一个常量来定义这个路径会比很多次书写这个路径来得方便，且修改起来工作量比较小：</p>
<p>
	&nbsp;</p>
<table align="center" border="0" cellpadding="6" cellspacing="0" class="content" id="table1" style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" width="95%">
	<tbody>
		<tr>
			<td bgcolor="#f3f3f3" style="word-wrap: break-word">
				<font style="font-weight: bold; color: #000000">以下是引用片段：</font><br />
				　　&lsquo;注释语句的语法是在要注释的语句前面加一个&rsquo;<br />
				　　Sub&nbsp;Main<br />
				　　Dim&nbsp;Result&nbsp;As&nbsp;Integer<br />
				　　&lsquo;在这里定义一个常量<br />
				　　&lsquo;Const&nbsp;dm_path=&rdquo;e:\dmdbms&rdquo;<br />
				　　&#39;Initially&nbsp;Recorded:&nbsp;2007-12-13&nbsp;15:46:20<br />
				　　&#39;Script&nbsp;Name:&nbsp;test<br />
				　　&lsquo;一般情况下打开可执行文件不要使用下面这种点击菜单的方式来<br />
				　　Window&nbsp;SetContext,&nbsp;&quot;Class=Shell_TrayWnd&quot;,&nbsp;&quot;&quot;<br />
				　　PushButton&nbsp;Click,&nbsp;&quot;Text=开始&quot;<br />
				　　Window&nbsp;SetContext,&nbsp;&quot;Caption=「开始」菜单&quot;,&nbsp;&quot;&quot;<br />
				　　PushButton&nbsp;Click,&nbsp;&quot;Text=所有程序(P)&quot;<br />
				　　Window&nbsp;SetContext,&nbsp;&quot;Class=BaseBar;Level=2&quot;,&nbsp;&quot;&quot;<br />
				　　Toolbar&nbsp;Click,&nbsp;&quot;ObjectIndex=1;\;ItemID=36&quot;,&nbsp;&quot;Coords=118,10&quot;<br />
				　　&lsquo;打开可执行文件采用STARTAPPLICATION(可执行文件路径与名称),这样一个语句就可以打开需要的文件了，那么中间的一段代码就可以用一个语句替换了：startapplication(dm_path+&rdquo;\dm\dmtools\bin\isql.exe&rdquo;)<br />
				　　Window&nbsp;SetContext,&nbsp;&quot;Class=BaseBar&quot;,&nbsp;&quot;&quot;<br />
				　　Toolbar&nbsp;Click,&nbsp;&quot;ObjectIndex=1;\;ItemText=交互式工具&nbsp;ISQL&quot;,&nbsp;&quot;Coords=101,16&quot;<br />
				　　Window&nbsp;SetContext,&nbsp;&quot;Caption=DM交互式工具&quot;,&nbsp;&quot;&quot;<br />
				　　TreeView&nbsp;DblClick,&nbsp;&quot;ObjectIndex=2;\;ItemText=达梦服务器组-&gt;本地服务器&quot;,&nbsp;&quot;&quot;<br />
				　　Window&nbsp;SetContext,&nbsp;&quot;Caption=登录&quot;,&nbsp;&quot;&quot;<br />
				　　EditBox&nbsp;Left_Drag,&nbsp;&quot;Label=用户名(U):&quot;,&nbsp;&quot;Coords=65,11,-60,-7&quot;<br />
				　　InputKeys&nbsp;&quot;^c&quot;<br />
				　　EditBox&nbsp;Click,&nbsp;&quot;Label=口令(W):&quot;,&nbsp;&quot;Coords=44,8&quot;<br />
				　　InputKeys&nbsp;&quot;^v&quot;<br />
				　　PushButton&nbsp;Click,&nbsp;&quot;Text=确定&quot;<br />
				　　Window&nbsp;SetContext,&nbsp;&quot;Caption=DM交互式工具&quot;,&nbsp;&quot;&quot;<br />
				　　MenuSelect&nbsp;&quot;文件(F)-&gt;打开(O)...&quot;<br />
				　　Window&nbsp;SetContext,&nbsp;&quot;Caption=打开&quot;,&nbsp;&quot;&quot;<br />
				　　ComboBox&nbsp;Click,&nbsp;&quot;Label=文件类型(T):&quot;,&nbsp;&quot;Coords=164,13&quot;<br />
				　　ComboListBox&nbsp;Click,&nbsp;&quot;Label=文件类型(T):&quot;,&nbsp;&quot;Text=Text&nbsp;file(*.txt)&quot;<br />
				　　ComboEditBox&nbsp;Click,&nbsp;&quot;ObjectIndex=3&quot;,&nbsp;&quot;Coords=18,1&quot;<br />
				　　InputKeys&nbsp;&quot;license_zh_cn.txt&quot;<br />
				　　&lsquo;在这里打开文件时采用的是默认的路径，如果需要打开达梦数据库目录下的一个文件可以采用这个方式：InputKeys&nbsp;dm_path+&quot;\license_zh_cn.txt&quot;<br />
				　　PushButton&nbsp;Click,&nbsp;&quot;Text=打开(O)&quot;<br />
				　　Window&nbsp;SetContext,&nbsp;&quot;Caption=DM交互式工具&quot;,&nbsp;&quot;&quot;<br />
				　　Window&nbsp;CloseWin,&nbsp;&quot;&quot;,&nbsp;&quot;&quot;<br />
				　　End&nbsp;Sub</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　打开已有版本执行脚本</p>
<p>
	　　在录制脚本的机器上打开脚本比较简单，选择菜单File-&gt;Open-&gt;Script，即可显示打开脚本的窗口，选择需要打开的脚本即可。在非录制脚本的机器上选择此菜单的话显示的打开脚本窗口中无法找要找开的脚本，选择菜单File-&gt;Open-&gt;SQABasic File找到要打开的脚本，脚本存放的目录为：..\ TestDatastore\DefaultTestScriptDatastore\TMS_Scripts(验证点存放的目录：..\ TestDatastore\DefaultTestScriptDatastore\TMS_Scripts\vp)用SQABasic File打开过的脚本再用菜单File-&gt;Open-&gt;Script方式在打开脚本窗口中有显示需要打开的脚本，选择脚本即可。</p>
<p>
	　　执行打开的脚本，选择菜单File-&gt;Compile可查看脚本是否有语法错误，在无语法错误的情况下选择菜单File-&gt;Playback可回放脚本，在回放脚本的过程中无需手动做操作，在执行完毕以后会有提示是否会执行成功，如下图：</p>
<center>
	<img alt="" border="1" height="306" src="/uploads/allimg/111208/0942445a3-0.jpg" width="557" /></center>
<p>
	　　Ratoinal Robot可以实现图形用户界面的功能自动化测试，但是它也会有一些不足的地方，比如有些控件它是识别不了的，有的时候没办法验证，对windows弹出式菜单的不支持，需要用startapplication来代替，回放脚本的时候也需要在Rational　Robot的环境下回放，不能单独执行等缺陷。因此需要回避一些缺陷来利用Rational　Robot来提高测试的效率与质量。</p>
]]></description>
    <pubDate>Thu, 08 Dec 2011 09:40:33 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111208/0942445a3-0-lp.jpg</subImagePath>
     <category>Robot</category>
    <author>领测软件测试网采编</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[Rational Robot压力测试实例]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/2011/1208/203735.html</link>
    <description><![CDATA[<p>
	　　看到很多人在要这个,找到一篇,转过来给大家看看</p>
<p>
	　　第一贴内容是关于CS结构的基于socked协议的脚本录制,修改,设置,回放的</p>
<p>
	　　第二贴内容是关于自写SQL SERVER<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>压力脚本的</p>
<p>
	　　文章的出处没有看到作者的名字,非常抱歉</p>
<p>
	　　脚本与被测程序有关,直接运行这个脚本是不能回放成功的(因为你没有脚本运行的环境)</p>
<p>
	　　文章如下</p>
<p>
	　　第一步：设置<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/" target="_blank" >Robot</A></STRONG></p>
<p>
	　　Robot――Tools――Session Record options，Method选择API Recorder，Generater Filtering中Filtering选择Auto filtering，Select protocols只选择Socket;</p>
<p>
	　　第二步：录制VU脚本</p>
<p>
	　　在启动的Start Application窗口中，Executable输入被测程序的客户端程序的路径和文件名，Working Directory中输入被测程序的工作路径，Program Arguments如果没有就空着。被测程序程序启动后，执行需要的操作然后关闭程序，停止录制脚本，Robot会自动生成脚本。</p>
<p>
	　　脚本示例：</p>
<p>
	&nbsp;</p>
<table width="80%">
	<tbody>
		<tr>
			<td bgcolor="#000000" class="content">
				<p>
					<font color="#ffffff">#include &lt;VU.h&gt;</font></p>
				<p>
					<font color="#ffffff">{</font></p>
				<p>
					<font color="#ffffff">push Timeout_scale = 200; /* Set timeouts to 200% of maximum response time */</font></p>
				<p>
					<font color="#ffffff">push Think_def = &quot;<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/" target="_blank" >LR</A></STRONG>&quot;;</font></p>
				<p>
					<font color="#ffffff">Min_tmout = 120000; /* Set minimum Timeout_val to 2 minutes */</font></p>
				<p>
					<font color="#ffffff">push Timeout_val = Min_tmout;</font></p>
				<p>
					<font color="#ffffff">SERVER = sock_connect(&quot;123001&quot;, &quot;SERVER:2000&quot;);</font></p>
				<p>
					<font color="#ffffff">{ INFO SERVER &quot;SERVER&quot;=&quot;192.168.1.12&quot;; } /*1*/</font></p>
				<p>
					<font color="#ffffff">set Server_connection = SERVER;</font></p>
				<p>
					<font color="#ffffff">push Think_avg = 0;</font></p>
				<p>
					<font color="#ffffff">sock_send</font></p>
				<p>
					<font color="#ffffff">&quot;`45645651300000000001<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>00f701000002000000c3330100000000000000000001000000&quot; &quot;00000000000sdgsdfgfhjghjjdfhjhkjgfhjgfjjk000000000000hh0000000000000000000000&quot; &quot;000000000000000000000000000000000000000000000100`g2222`0012313546545465431&quot; &quot;`45641313000000000000000000000000000000000000`&quot;;</font></p>
				<p>
					<font color="#ffffff">sock_nrecv [&quot;123002&quot;] 200;</font></p>
				<p>
					<font color="#ffffff">sock_send &quot;`1321321656548745215599154654456546122132112313210000000000000001000000&quot; &quot;00000000021321215665654548879654654655562000000000000000000000000000000&quot; &quot;00000000000000000000000000000000000000000000012131132321213212111323213&quot; &quot;`123110000000`Z2&quot;;</font></p>
				<p>
					<font color="#ffffff">sock_recv [&quot;123003&quot;] &quot;$&quot;; /* 50 bytes */</font></p>
				<p>
					<font color="#ffffff">sock_disconnect(SERVER);</font></p>
				<p>
					<font color="#ffffff">pop [Think_def, Think_avg, Timeout_val, Timeout_scale];</font></p>
				<p>
					<font color="#ffffff">}</font></p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　这个脚本如果不能正确回放，可以将将sock_recv [&quot;123003&quot;] &quot;$&quot;; /* 50 bytes */改为</p>
<p>
	　　sock_nrecv [&quot;123003&quot;] 50; /* 50 bytes */</p>
<p>
	　　第三步：设置Suite，回放脚本</p>
<p>
	　　回放录制的脚本，Testmanager会自动创建Suite，如下所示：[attachment=1786]</p>
<p>
	　　默认脚本运行一次，为了长时间运行，修改增加脚本的运行次数(最大32767)，在Run properties中Iterations中设置。然后运行Suite，在Run Suite窗口中的&ldquo;Number of users&rdquo;上输入虚拟用户数，如200。</p>
<p>
	　　第四步：观察被测服务程序的运行情况，查看有无异常。</p>
<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/xncs/" target="_blank" >压力测试</A></STRONG>需要连续、高负载运行不少于72小时，运行完成服务程序需要无资源泄漏、无报错、无异常退出以及其他不正常情况。</p>
<p>
	　　ilovejolly 2006-05-20 16:43</p>
<p>
	　　数据库并发测试</p>
<p>
	　　数据库并发测试的必要性：</p>
<p>
	　　1、 与数据库连接的服务程序采用多线程同时开启多个数据库连接;</p>
<p>
	　　2、 与数据库连接的服务程序单线程，但是同时开启多套服务程序;</p>
<p>
	　　以上两种情况均会产生对数据库的并发访问操作。数据库并发访问会导致数据库数据错误、数据库死锁等故障，需要在测试阶段进行充分测试。</p>
<p>
	　　数据库并发测试测试方法：</p>
<p>
	　　1、 利用<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>模拟多个最终用户进行并发测试;</p>
<p>
	　　这种测试方法的缺点：最终用户往往并不是直接连接到数据库上，而是要经过一个和多个中间服务程序，所以并不能保证访问数据库时还是并发。其次，这种测试方法需要等到客户端程序、服务端程序全部完成才能进行;</p>
<p>
	　　2、 利用测试工具编写脚本，直接连接数据库进行并发测试;</p>
<p>
	　　这种方法可以有效的保证并发操作，而且在数据库访问程序完成即可测试，可以大大缩短测试时间，而且测试效果更好。</p>
<p>
	　　下面通过一个演示程序，演示使用Robot使用第二种测试方法进行数据库的并发测试：</p>
<p>
	　　第一步：创建演示程序：打开SQL SERVER查询分析器，在SQL SERVER测试数据库中执行下列脚本(脚本执行操作：创建表testtable，并插入一条记录;创建存储过程test)：</p>
<p>
	&nbsp;</p>
<table width="80%">
	<tbody>
		<tr>
			<td bgcolor="#cccccc" class="content">
				<p>
					if exists (select * from dbo.sysobjects where id = object_id(N&#39;[dbo].[Test]&#39;) and OBJECTPROPERTY(id, N&#39;IsProcedure&#39;) = 1)</p>
				<p>
					drop procedure [dbo].[Test]</p>
				<p>
					GO</p>
				<p>
					if exists (select * from dbo.sysobjects where id = object_id(N&#39;[dbo].[testtable]&#39;) and OBJECTPROPERTY(id, N&#39;IsUserTable&#39;) = 1)</p>
				<p>
					drop table [dbo].[testtable]</p>
				<p>
					GO</p>
				<p>
					CREATE TABLE [dbo].[testtable] (</p>
				<p>
					[testid] [int] NULL ,</p>
				<p>
					[counts] [int] NULL</p>
				<p>
					) ON [PRIMARY]</p>
				<p>
					GO</p>
				<p>
					insert into testtable (testid,counts) values (1,0)</p>
				<p>
					GO</p>
				<p>
					SET QUOTED_IDENTIFIER ON</p>
				<p>
					GO</p>
				<p>
					SET ANSI_NULLS ON</p>
				<p>
					GO</p>
				<p>
					CREATE Procedure dbo.Test</p>
				<p>
					as</p>
				<p>
					declare @count int</p>
				<p>
					begin tran TEST</p>
				<p>
					select @count=counts from testtable where testid=1</p>
				<p>
					update testtable set counts=@count+1</p>
				<p>
					if (@@error &gt;0) begin</p>
				<p>
					rollback tran TEST</p>
				<p>
					end else begin</p>
				<p>
					commit tran TEST</p>
				<p>
					end</p>
				<p>
					GO</p>
				<p>
					SET QUOTED_IDENTIFIER OFF</p>
				<p>
					GO</p>
				<p>
					SET ANSI_NULLS ON</p>
				<p>
					GO</p>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　第二步：创建测试脚本：在Robot中新建VU脚本，输入以下内容：</p>
<p>
	&nbsp;</p>
<table width="80%">
	<tbody>
		<tr>
			<td bgcolor="#cccccc" class="content">
				<p>
					#include &lt;VU.h&gt;</p>
				<p>
					{</p>
				<p>
					push Timeout_scale = 200; /* Set timeouts to 200% of maximum response time */</p>
				<p>
					push Think_def = &quot;LR&quot;;</p>
				<p>
					Min_tmout = 120000; /* Set minimum Timeout_val to 2 minutes */</p>
				<p>
					push Timeout_val = Min_tmout;</p>
				<p>
					ser=sqlconnect(&quot;server&quot;,&quot;sa&quot;,&quot;888&quot;,&quot;192.168.0.99&quot;,&quot;sqlserver&quot;);</p>
				<p>
					set Server_connection = ser;</p>
				<p>
					push Think_avg = 0;</p>
				<p>
					sync_point &quot;logon&quot;;</p>
				<p>
					sqlexec [&quot;sql_1000&quot;] &quot;testdb..test&quot;;</p>
				<p>
					sqldisconnect (ser);</p>
				<p>
					}</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　说明：</p>
<p>
	　　ser=sqlconnect(&quot;server&quot;,&quot;sa&quot;,&quot;888&quot;,&quot;192.168.0.99&quot;,&quot;sqlserver&quot;)</p>
<p>
	　　sa为数据库用户名，888为sa密码，192.168.0.99数据库IP地址</p>
<p>
	　　以上三项按实际的测试数据库设置更改，其他两项不用修改</p>
<p>
	　　sqlexec [&quot;sql_1000&quot;] &quot;testdb..test&quot;</p>
<p>
	　　testdb为新建存储过程test所在的数据库，按实际的数据库修改</p>
<p>
	　　第三步：执行测试：运行上一步创建的脚本(运行时自动创建Suite)，在Run Suite窗口中的&ldquo;Number of users&rdquo;上输入20。运行完脚本，打开数据库查看counts的数值。把counts值改为零多次运行脚本，观察每次运行后counts的结果。</p>
<p>
	　　测试说明</p>
<p>
	　　(1)、测试示例程序的目的是，存储过程test每执行一次，表testtable中的counts字段增加一;</p>
<p>
	　　(2)、第三步的测试可以发现每次执行后counts结果并不相同，而且不等于20，这说明这个程序是在并发时是问题的。</p>
<p>
	　　(3)、将存储过程中的select @count=counts from testtable where testid=1修改为select @count=counts from testtable with (UPDLOCK) where testid=1。再次进行并发测试，每次的结果应该都是20。</p>
<p>
	　　以上演示程序，仅仅演示了测试的方法。在实际的数据库并发测试中，首先要确定存在哪些并发情况、哪些数据受到并发影响，然后编写脚本，设置suite进行并发测试。</p>
]]></description>
    <pubDate>Thu, 08 Dec 2011 09:33:48 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>Robot</category>
    <author>领测软件测试网采编</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[改进 Rational Functional Tester 启动应用程序的过程]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/functionaltester/2011/1208/203734.html</link>
    <description><![CDATA[<p>
	&nbsp;</p>
<p>
	　　本文介绍了一种改进的方法，在 IBM Rational Functional tester (RFT) 录制的脚本中采用代码和配置文件来启动应用程序，每次跑脚本前，测试人员只需要打开配置文件设好 build 运行程序的路径，就完成了配置过程。通过该方式也可以使用命令行来运行测试脚本，使<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/zdcs/" target="_blank" >自动化测试</A></STRONG>成为可能。</p>
<p>
	　　IBM&reg; Rational&reg; Functional Tester (RFT) 是 IBM 推出的自动化<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/" target="_blank" >测试工具</A></STRONG>，借助这一工具，用户可以录制测试过程产生测试脚本，或者自己编写测试脚本以获取更多的灵活性，然后回放这些脚本来自动化测试应用程序。在进行录制或者回放脚本前，为了能够启动要测试的应用程序，用户首先要打开 RFT 的界面，在配置窗口里设好应用程序的名称、种类、路径、工作目录等信息。在实际应用中，一个产品在 beta 或者 release 发布前，会根据项目进展推出一个个 build 。当脚本<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>好后，每次为了测试新 build 都要打开 RFT 重新配置，显得比较烦琐，尤其当计划只用命令行远程调用测试脚本，以实现自动化测试的时候。本文介绍了一种改进的方法，即采用代码和配置文件来启动应用程序，每次运行脚本前，用户只需要打开配置文件设好 build 运行程序的路径，就完成了配置过程。通过该方式也可以使用命令行来运行测试脚本，使自动化测试成为可能。</p>
<p>
	　　本文将首先介绍如何在 RFT 中设置要启动的应用程序，然后将其应用在一个实际的测试场景中，以此来说明采用默认设置方法在实际应用中会产生的问题。接着将提出一个改进的方法来取代默认方法，进而解决问题。该改进方法已经成功应用在 IBM Lotus Connection 2.0 的安装程序的自动化测试中，在本文的测试场景中，将采用此产品作为测试对象进行说明。</p>
<p>
	　　设置要启动的应用程序</p>
<p>
	　　本章将简述在 RFT 中如何设置要启动的应用程序，首先选择 RFT 主界面工具栏上的&ldquo;配置&rdquo;，然后选择&ldquo;配置应用程序进行测试&rdquo;，弹出如下对话框。如图 1 。</p>
<p>
	　　图 1. 配置应用程序对话框</p>
<center>
	<img alt="配置应用程序对话框" border="1" height="353" src="/uploads/allimg/111208/09311Q451-0.jpg" width="567" /></center>
<p>
	　　该对话框显示的是被测应用程序的相关信息，包括名称、种类、路径、工作目录等。</p>
<p>
	　　当要添加新的应用程序时，点击右侧&ldquo;添加&rdquo;按钮，然后在弹出对话框里选择应用程序的种类，有三个类型，一般的应用程序的启动文件都是可执行的 exe 或者 bat，这里我们选择&ldquo;可执行文件或批处理文件&rdquo;。如图 2 。</p>
<p>
	　　图 2. 添加应用程序的种类</p>
<center>
	<img alt="添加应用程序的种类" border="1" height="211" src="/uploads/allimg/111208/09311VA2-1.jpg" width="422" /></center>
<p>
	　　点击&ldquo;下一步&rdquo;。然后选择应用程序的 bat 或者 exe 的路径，本文以 Lotus Connections 2.0 的安装程序为例，选择 &lt; LC_installer_dir&gt;\install.bat，即 Lotus Connections 2.0 安装程序在本机上的文件路径。如图 3 。</p>
<p>
	　　图 3. 添加应用程序对话框</p>
<center>
	<img alt="添加应用程序对话框" border="1" height="211" src="/uploads/allimg/111208/09311S260-2.jpg" width="422" /></center>
<p>
	　　点击&ldquo;完成&rdquo;。然后可以得到以下的信息。如图 4 。</p>
<p>
	　　图 4. 配置应用程序对话框</p>
<center>
	<img alt="配置应用程序对话框" border="1" height="353" src="/uploads/allimg/111208/09311S5Q-3.jpg" width="567" /></center>
<p>
	　　默认名称为 install，类型为 executable，表示可执行的，路径和工作目录为应用程序在本地磁盘的路径，可执行的文件为选择的 bat 文件名。</p>
<p>
	　　用户可以点击右侧的&ldquo;运行&rdquo;按钮进行测试，如果看到 Lotus Connections 2.0 安装程序成功启动，如图 5 。则说明配置应用程序成功，接着便可以进行下一步操作，录制或者回放脚本。</p>
<p>
	　　图 5. Lotus Connections 安装界面</p>
<center>
	<img alt="Lotus Connections 安装界面" border="1" height="425" src="/uploads/allimg/111208/09311T111-4.jpg" width="567" /></center>
<p>
	　　分析启动应用程序脚本</p>
<p>
	　　当 Lotus Connections 2.0 安装程序在 RFT 中配置成功后，就可以录制操作，然后生成测试脚本。要录制操作，首先新建一个工程，点击&ldquo;文件&rdquo;，然后点击&ldquo;新建 Functional Tester 项目&rdquo;，填写项目名称和路径。</p>
<p>
	　　新建完工程后，需要新建一个空的脚本文件，在工程上右击，然后选择&ldquo;使用记录器添加脚本&rdquo;，输入脚本名称后点击&ldquo;完成&rdquo;按钮，会弹出一个&ldquo;正在记录对话框&rdquo;，接着点击上面的&ldquo;启动应用程序&rdquo;。如图 6 。</p>
<p>
	　　图 6. 正在记录对话框</p>
<center>
	<img alt="正在记录对话框" border="1" height="420" src="/uploads/allimg/111208/09311U632-5.jpg" width="300" /></center>
<p>
	　　点击后弹出&ldquo;启动应用程序对话框&rdquo;，从下拉列表里可以看到前面已经配置好的应用程序，选择 install &ndash; excutable 。如图 7 。</p>
<p>
	　　图 7. 启动应用程序对话框</p>
<center>
	<img alt="启动应用程序对话框" border="1" height="225" src="/uploads/allimg/111208/09311Q611-6.jpg" width="220" /></center>
<p>
	　　点&ldquo;确定&rdquo;后将会启动前面所见的 Lotus Connections 2.0 安装程序界面，用户接下来在应用程序上进行的操作都会被 RFT 记记录并自动产生相应脚本。点击&ldquo;正在记录对话框&rdquo;(图 6 )上面的&ldquo;停止记录&rdquo;按钮，可以完成录制的行为。</p>
<p>
	　　查看生成的脚本，testMain(Object[] args) 是主函数，作为脚本执行的起始点，可以看到里面第一行的代码是 startApp(&quot;install&quot;)，传递的参数正是前面配置的 Lotus Connections 2.0 安装程序的名称，后面是记录用户操作所生成的测试代码。如清单 1 。</p>
<p>
	　　清单 1. RFT 生成的测试脚本</p>
<p>
	&nbsp;</p>
<table border="0" cellpadding="0" cellspacing="0" id="table4" width="69%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="content">
public void testMain(Object[] args) { 

 startApp(&quot;install&quot;); 

 next_btn().click(); 
 createDB_option().click(); 
 next_btn().click(); 
 DB2_option().click(); 

 ...... 
 }</pre>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　当开始回放脚本时，RFT 将首先启动应用程序，然后再进行自动化测试。由此可以得知 startApp 是 RFT 用于启动应用程序的函数，它会根据获得的参数去配置文件 configurations.<STRONG><A href="http://www.ltesting.net/a/FunctionalTester/" target="_blank" >rft</A></STRONG>cfg 中映射详细的配置信息，如可执行文件、路径、类型等，这些信息将真正决定应用程序如何启动。</p>
<p>
	　　对于前文描述的 Lotus Connections 2.0 安装文件的配置，startApp 会根据名称 install 去匹配并获取详细的信息，从而启动该程序，在 configurations.rftcfg 可以找到对应的代码。如清单 2 。</p>
<p>
	　　清单 2. RFT 生成的配置文件代码</p>
<p>
	&nbsp;</p>
<table border="0" cellpadding="0" cellspacing="0" id="table5" width="69%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="content">
&lt;Application L=&quot;.Application&quot;&gt; 
	 &lt;Name&gt;install&lt;/Name&gt; 
	 &lt;Kind&gt;executable&lt;/Kind&gt; 
	 &lt;Path&gt;C:\Build\LC2.0_20080427&lt;/Path&gt; 
	 &lt;Command&gt;dbWizard_RFT.bat&lt;/Command&gt; 
	 &lt;Jvm/&gt; 
	 &lt;Classpath&gt;&lt;/Classpath&gt; 
 &lt;Args&gt;&lt;/Args&gt; 
	 &lt;WorkingDir&gt;C:\Build\LC2.0_20080427&lt;/WorkingDir&gt; 
 &lt;/Application&gt;</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　configurations.rftcfg 文件通常存放在本地硬盘上的 C :\Documents and Settings\All Users\Application Data\IBM\RFT\configuration 目目录下。</p>
<p>
	　　实际应用中的问题</p>
<p>
	　　在实际应用中，一个软件产品在 beta 版或者 release 版发布前，会根据项目进展推出一个个 build，这些 build 经常是每日构建，构建好后放在按一定规则命名的(如日期)的文件内，然后统一存放在 build <STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlfwq/" target="_blank" >服务器</A></STRONG>上，留待测试团队<STRONG><A href="http://www.ltesting.net/ceshi/down" target="_blank" >下载</A></STRONG>测试。本文的测试对象 Lotus Connections 2.0 安装程序正是如此。</p>
<p>
	　　针对实际情况，在搞清楚了 RFT 如何配置和启动应用程序之后，我们会发现一些不便之处。</p>
<p>
	　　在分工精细的项目团队里，开发脚本的人员和使用脚本的人往往不是一个人，让使用脚本的人经常打开 RFT 去配置容易出错。</p>
<p>
	　　脚本开发好后，每次为了测试新的 build 都要打开 RFT 重新配置信息，显得比较烦琐。</p>
<p>
	　　同时，RFT 支支持命令行方式运行脚本。其中 -datastore 后面指定工程路径，-playback 后面指定脚本的全名称。如清单 3 。</p>
<p>
	　　清单 3. RFT 命令行脚本</p>
<p>
	&nbsp;</p>
<table border="0" cellpadding="0" cellspacing="0" id="table9" width="69%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="displaycode">
 <span class="content">&quot;C:\Program Files\IBM\SDP70\jdk\bin\<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcskfyy/java/" target="_blank" >java</A></STRONG>&quot; -classpath 
 &quot;C:\Program Files\IBM\SDP70\<STRONG><A href="http://www.ltesting.net/a/FunctionalTester/" target="_blank" >FunctionalTester</A></STRONG>\bin\<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/" target="_blank" >rational</A></STRONG>_ft.jar&quot;
     com.rational.test.ft.rational_ft</span></pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　-datastore &quot;C:\ workspace\Project1&quot; -playback <STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csyl/" target="_blank" >testcase</A></STRONG>s.install.Script1</p>
<p>
	　　使用命令行方式不仅摆脱了要打开 RFT 界面运行脚本的限制，而且也可以让用户轻易的实现自动化测试，如在 Unix 环境下使用 cron，在 Windows 下使用&ldquo;任务计划&rdquo;来自动调用测试脚本。</p>
<p>
	　　如此，又出现了一个新的问题：</p>
<p>
	　　当用户希望用命令行方式启动脚本测试每个 build，然后进一步实现自动化测试时，由于 build 的信息改变，就不得不打开 RFT 界面重新配置 build 信信息。造成了自动化测试的实现上的困难。</p>
<p>
	　　一种改进的启动应用程序方式</p>
<p>
	　　针对实际应用中的问题，我们提出了一种改进的启动应用程序的方式，即扩展 RFT 的 startApp 函数，用代码读取配置文件获得 build 信信息，然后进行启动。以图摆脱 RFT 本身的配置步骤。</p>
<p>
	　　由此，我们可以写出自定义的启动函数。如清单 4 。</p>
<p>
	　　清单 4. 自定义启动函数</p>
<p>
	&nbsp;</p>
<table border="0" cellpadding="0" cellspacing="0" id="table13" width="68%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="content">
// 启动应用程序
 public static boolean execApp(String appName) { 
	
	 try { 
 appName = appName.replace(&quot;\\&quot;, &quot;/&quot;); 
		 String directory = appName.substring(0, appName.lastIndexOf(&quot;/&quot;)); 
		 String[] command = {appName}; 
		 String workDir = directory; 
		 String outputPath = directory; 
		 int status = -1 ; 
		
		 if (!&quot;Linux&quot;.equals(System.getProperty(&quot;os.name&quot;))) { 
 // Windows 平台启动应用程序
			 status = runCommand(command, workDir, null, outputPath); 
		 } else { 
 // Linux 平台启动应用程序
			 String auth = &quot;chmod +x &quot; + appName; 
             status = runCommand(new String[] { auth }, null, null,outputPath);
             status = runCommand(command, workDir, null, outputPath); 
		 } 
		
		 if(status == 0){ 
			 return true; 
		 }else{ 
			 return false; 
		 } 
	 } catch (Exception e){ 
		 e.printStackTrace(); 
		 return false; 
	 } 
 } 

 // 执执行命令
 public static int runCommand(String[] command, String workDir, 
 Map environment, String outputPath) { 
	
	 ProcessBuilder builder = new ProcessBuilder(command); 
	 builder.redirectErrorStream(true); 
	 Process process = null; 
	 int status = -1; 
	
	 if (workDir != null) 
		 builder.directory(new File(workDir)); 
	
	 if (environment != null) 
		 builder.environment().putAll(environment); 
	
	 try { 
		 process = builder.start(); 
	 } catch (Exception e) { 
		 e.printStackTrace(); 
	 } 
	
	 if (process != null) { 
		 try { 				
			 status = process.waitFor(); 
		 } catch (Exception e) { 
			 e.printStackTrace(); 
		 } 
	 } 
	 return status; 
 }</pre>
			</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　runCommand 函数用于执行传递的命令，execApp 函数通过参数获得应用程序路径，然后调用 runCommand 函数来启动应用程序。</p>
<p>
	　　接着就可以更新 testMain 函数，使用 execApp 函数代替 startApp 。如清单 5 。</p>
<p>
	　　清单 5. testMain 函数</p>
<p>
	&nbsp;</p>
<table border="0" cellpadding="0" cellspacing="0" id="table14" width="68%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="content">
public void testMain(Object[] args) { 
		
 // 启动应用程序
 execApp(sAPPPath); 

 ...... 
 }</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　传递给 execApp 的变量可以通过读取配置文件获得应用程序路径。下面添加读取配置文件代码和相关变量。如清单 6 。</p>
<p>
	　　清单 6. 读取配置文件代码</p>
<p>
	&nbsp;</p>
<table border="0" cellpadding="0" cellspacing="0" id="table15" width="68%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="content">
 // 配配置文件
 public static String sFileLocation=&quot;C:\\workspace\\Project1\\conf.properties&quot;; 
 // 应应用程序路径变量
 public static String sDBAPPPath; 
 // 读读取配置文件
 public static String getPropertyFromFile(String sKey, String fileName){ 
	
	 Properties prop = new Properties(); 
	 File file = new File(fileName); 
	 FileInputStream fis=null; 
	 String sPropVal = &quot;&quot;; 
	
	 try{ 	
		 fis= new FileInputStream(file); 
		 prop.load(fis); 
		 sPropVal = prop.getProperty(sKey); 
		 fis.close(); 
	 }catch(Exception e) { 
		 e.printStackTrace(); 
	 } 
	 return sPropVal; 	
 }</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　getPropertyFromFile 函数根据配置文件里的键值对返回相应的值。配置文件 conf.properties 里添加键值对为 AppLocation = &lt; 应应用程序路径 &gt; 。对于本文的测试场景，&lt; 应应用程序路径 &gt; 就就是 Lotus Connections 2.0 安装程序在本机上的文件路径，如 C :\Build\LC2.0_20080427\install.bat 。</p>
<p>
	　　然后给 sAPPPath 变变量赋予 getPropertyFromFile 的返回值，将其传递给 execApp 。如清单 7 。</p>
<p>
	　　清单 7. 更新后的 testMain 函数</p>
<p>
	&nbsp;</p>
<table border="0" cellpadding="0" cellspacing="0" id="table16" width="68%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="content">
public void testMain(Object[] args) { 
		
 // 读读取配置文件里的路径
 <i>sAPPPath</i>=<i>getPropertyFromFile</i>(&quot;AppLocation&quot;,<i>sFileLocation</i>); 
 // 启动应用程序
	 execApp(sDBAPPPath);</pre>
			</td>
		</tr>
	</tbody>
</table>
<table border="0" cellpadding="0" cellspacing="0" class="content" id="table17" width="68%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="displaycode">
...... 
 }</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　同时，为了使命令行调用脚本更方便，我们可以将应用程序路径做为命令行的一个参数传递。</p>
<p>
	　　进一步修改 testMain，使之既可以读取配置文件获得应用程序路径，也可以通过命令行来获取。如清单 8 。</p>
<p>
	　　清单 8. 添加 testMain 获取命令行参数代码</p>
<p>
	&nbsp;</p>
<table border="0" cellpadding="0" cellspacing="0" id="table18" width="68%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="content">
public void testMain(Object[] args) { 
	
	 if(args.length &gt; 0 &amp;&amp; args.length == 1){ 
 // 通过命令行方式读取应用程序路径
		 sDBAPPPath = args[0].toString(); 
		 System.out.println(&quot;Read App Info with command&quot;); 
	 }else{ 
 // 通过配置文件方式读取应用程序路径
		 sDBAPPPath=getPropertyFromFile(&quot;AppLocation&quot;,sFileLocation); 
		 System.out.println(&quot;Read App Info with properties&quot;); 
	 } 
	
 // 启动应用程序
	 execApp(sDBAPPPath); 
	
	 ...... 
 }</pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　如此，就可以在命令行中加上应用程序路径参数。当需要测试新 build 时候，通过改变此参数，可以使调用更灵活。如清单 9 。</p>
<p>
	　　清单 9. 传递参数的 RFT 命令行代码</p>
<p>
	&nbsp;</p>
<table border="0" cellpadding="0" cellspacing="0" id="table19" width="68%">
	<tbody>
		<tr>
			<td bgcolor="#f9f9f9" class="code-outline">
				<pre class="displaycode">
 <span class="content">&quot;C:\Program Files\IBM\SDP70\jdk\bin\java&quot; -classpath 
 &quot;C:\Program Files\IBM\SDP70\FunctionalTester\bin\rational_ft.jar&quot;
     com.rational.test.ft.rational_ft 
     -datastore &quot;C:\workspace\Project1&quot; 
     -playback testcases.install.Script1&lt;App location&gt;
			</span></pre>
			</td>
		</tr>
	</tbody>
</table>
<p>
	　　总结</p>
<p>
	　　通过以上的做法，解决了现实应用中出现的问题：</p>
<p>
	　　当有新 build 需要测试的时候，用户只需要在配置文件里改变一下路径，就完成了配置过程。不需要重新打开 RFT 的配置应用程序窗口进行配置。</p>
<p>
	　　当需要自动化测试的时候，用户可以使用命令行方式来调用测试脚本，并且在命令行里传递新 build 的路径信息。除了可以采用计划任务来触发 RFT 命令行外，也可以使用 STAF (Software Testing Automation Framework) 来实现 RFT 的自动化框架。关于自动化<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/zdcs/zdcskj/" target="_blank" >测试框架</A></STRONG>实现的话题超出了本文的讨论范围。但是这一切得以实现来源于本文所讨论的改进 RFT 启动应用程序的过程。</p>
<p>
	　　免责声明</p>
<p>
	　　本文仅代表本人观点，并非代表 IBM 的立场、策略和观点。#p#分页标题#e#</p>
<p>
	　　参考资料</p>
<p>
	　　学习</p>
<p>
	　　通过 developerWorks 中国网站的 Rational Functional Tester 产品专题 了解更多关于自动化<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/" target="_blank" >功能测试</A></STRONG>相关技术的信息。</p>
<p>
	　　访问 UML 资源中心，获得关于统一建模语言(Unified Modeling Language，UML)的入门<STRONG><A href="http://www.ltesting.net/ask/" target="_blank" >知识</A></STRONG>、技术资源和最佳实践。</p>
<p>
	　　访问 IBM developerWorks 中国网站 Rational 专区，获得关于 IBM Rational 软件交付平台(Rational Software Delivery Platform)产品的技术资源和最佳实践。</p>
<p>
	　　订阅 Rational Edge 中文版，获取软件开发领域的最佳实践。</p>
<p>
	　　订阅 IBM developerWorks 时事通讯，一份关于 developerWorks 指南、文章、下载、社区活动、<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/wlzs/" target="_blank" >网络</A></STRONG>广播和技术讲座的电子周刊。</p>
<p>
	　　学习 Hello World 系列教程，这是学习 IBM 软件工具的快速通道。在每一篇教程中，都会有快速入门产品演示动画。您可以通过其中的动画演示快速浏览如何使用 IBM 软件完成开发任务。</p>
<p>
	　　获得产品和技术</p>
<p>
	　　访问 IBM Rational 软件交付平台 V7 专题，了解 Rational V7 产品的方方面面。</p>
<p>
	　　获取免费的 Rational 软件工具包系列，了解最新的 IBM Rational 软件开发工具技术文档和资源。</p>
<p>
	　　下载免费的 IBM Rational 试用版软件，了解 IBM Rational 软件的最新特性。</p>
<p>
	　　获取更多 IBM 试用版软件，并熟练掌握来自 DB2&reg;、Lotus&reg;、Tivoli&reg;，以及 <STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/zjj/websphe/" target="_blank" >WebSphere</A></STRONG>&reg; 的开发工具和<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/zjj/" target="_blank" >中间件</A></STRONG>产品，用这些试用版软件开发您的下一个项目。这些试用版软件可以免费直接从 developerWorks 下载。</p>
<p>
	　　讨论</p>
<p>
	　　参加 Rational 大学，与 IBM Rational 专家一起分享 Rational 产品最佳实践。</p>
<p>
	　　查看 developerWorks 博客 并加入 developerWorks 社区。</p>
]]></description>
    <pubDate>Thu, 08 Dec 2011 09:03:40 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111208/09311Q451-0-lp.jpg</subImagePath>
     <category>FunctionalTester</category>
    <author>领测软件测试网采编</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[Robot中验证点的使用]]></title>
    <link>http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/2011/1207/203731.html</link>
    <description><![CDATA[<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/robot/" target="_blank" >Robot</A></STRONG>进行<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/" target="_blank" >功能测试</A></STRONG>时，可以在录制好的脚本中添加验证点来判断脚本执行后程序是否达到了预期的结果。</p>
<p>
	　　验证点的思想是通过比较控件的基准值与回放脚本时的值来判断程序是否按照预期的设想在执行[基准值是指录制脚本时所选控件的某些属性，具体取哪些属性依赖于添加的验证点类型]。通常录制好验证点后，都会生成一个基线数据文件，此文件的值是录制脚本时控件的某些属性的值或者是控件的数据，可以手工修改。</p>
<p>
	　　创建验证点时，可以设置重新获取时间及超时时间。</p>
<p>
	　　重新获取时间：在回放脚本时如果验证点没有验证成功，Robot将会间隔一段时间去重新获取验证点信息，这个时间就是重新获取时间。</p>
<p>
	　　超时时间：在回放脚本时如果验证点没有验证成功，Robot会间隔一段时间去重新获取验证点信息，但是过了一定时间就会停止,接着执行下面的脚本。这个时间就是超时时间。</p>
<p>
	　　一般常用的验证点有以下几种类型：</p>
<p>
	　　一、 Alphanumeric</p>
<p>
	　　使用Alphanumeric验证点从单行或多行编辑框及其他Robot可以识别的对象中捕获并比较字母或数字的值。包括CheckBox,Generic,GroupBox,Label, PushButton,RadioButton,ToolBar,Window(只能处理Caption)。</p>
<p>
	　　使用此类验证点可以验证文本的改变，拼写错误，以及确保数值的准确。</p>
<p>
	　　增加此类验证点后，会生成一个基准数据文件，可以用Text Comparator打开基准文件进行编辑。(对于Numeric Equivalence和Numeric Range两类验证点不会生成基准文件，基准值直接生成在脚本的验证函数中，也可以修改)。</p>
<p>
	　　Alphanumeric细分为下面的类型：</p>
<p>
	　　1、Case-Sensitive：验证录制脚本时捕捉到的文字是否与回放脚本时捕捉到的文字匹配(大小写敏感)</p>
<p>
	　　2、Case-InSensitive：验证录制脚本时捕捉到的文字是否与回放脚本时捕捉到的文字匹配(大小写不敏感)</p>
<p>
	　　3、Find Sub String Case-Sensitive：录制脚本时捕捉到的文字是否是回放脚本时捕捉到文字的子串(大小写敏感)</p>
<p>
	　　4、Find Sub String Case-InSensitive：录制脚本时捕捉到的文字是否是回放脚本时捕捉到文字的子串(大小写不敏感)</p>
<p>
	　　5、Numeric Equivalence:验证录制脚本时捕捉到的值是否与回放脚本时捕捉到的值相等。</p>
<p>
	　　6、Numeric Range：验证录制脚本时捕捉到的值是否属于回放脚本时一个特定的范围。</p>
<p>
	　　7、Apply a User_Defined DLL test function：回放脚本时需要验证的值是经过用户自定义的函数运算出来的。在此将DLL名称与函数名称指定好，脚本回放时，Robot将捕捉到的值与函数运算的结果相比较。</p>
<p>
	　　8、Verify that selected field is blank：验证所选区域是否为空。如果所选区域不包含任何文字或数字，那么验证点将执行成功。对于ListBox,ComboBox，如果没有任何项被选中，Robot也认为所选区域是空的。</p>
<p>
	　　二、 Menu</p>
<p>
	　　使用此验证点捕获所选菜单的标题、菜单项、快捷键和状态(enable，disabled，grayed 或 checked)。Robot可以记录五级子菜单的信息。添加此类验证点时，可以根据需要选择部分菜单进行验证,也可以直接编辑菜单项的值来改变捕捉到的基准值。回放脚本时，Robot会检测所选菜单的内容、状态、快捷键是否与基准值一致,而对菜单项的位置不做检测。</p>
<p>
	　　三、 Object Data</p>
<p>
	　　使用ObjectData验证点对对象中的数据进行验证，这些对象包括：标准的Window控件、ActiveX控件、<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/vb/" target="_blank" >VB</A></STRONG>的Data控件、HTML及<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcskfyy/java/" target="_blank" >Java</A></STRONG>对象、PowerBuilder的DataWindow和DataStore控件、菜单。同Menu验证点一样，也可以只选择部分数据作为基准值进行测试。</p>
<p>
	　　四、 Object Properties</p>
<p>
	　　使用Object Properties验证点对标准<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcshjdj/windows/" target="_blank" >Windows</A></STRONG>对象的属性进行验证(属性指控件的一些特征,比如编辑框的name、readonly、value等等)。也支持一些特殊的对象如ActiveX控件、VB的Data控件、HTML及Java对象、PowerBuilder的DataWindow。添加此类验证点后，Robot将显示出被捕获的对象及其相应属性的列表。你可以从对象的列表中选择你想要测试的属性。</p>
<p>
	　　五、 Window Existence</p>
<p>
	　　使用Windows Existence验证点来判断窗口是否存在以及验证窗口的状态。这些状态包括：正常、最小化、最大化或者是隐藏。此类验证点不生成基准数据文件。要修改基准数据必须重新录制脚本。最常用的是用来验证点击按钮后是否出现了预期的窗口。</p>
<p>
	　　六、Clipboard</p>
<p>
	　　对于用其他类型的VP不能捕获的对象文本，使用Clipboard类型。被测应用程序必须支持拷贝或剪切功能，这样才能将对象数据拷贝到Clipboard中进行比较。这种VP对于从电子表格和文字处理的应用程序捕获数据，是十分有效的。但它不能用于测试位图。</p>
<p>
	　　七、Menu</p>
<p>
	　　使用Menu VP可以捕获所选菜单的标题、菜单项、快捷键和状态(enable，disabled，grayed 或 checked)。Robot可以记录五级子菜单的信息。</p>
<p>
	　　八、Region Image</p>
<p>
	　　使用Region Image VP来选择屏幕的一个区域，Robot将其捕获并存成位图。该区域可以交迭多个窗体。要使该类VP通过验证，选择区域的位置和屏幕的分辨率在回放时应该与录制时保持一致。</p>
<p>
	　　九、Windows Image</p>
<p>
	　　使用Window Image VP来选择和捕获客户端窗体的一个区域。其菜单、标题栏和边框不在捕获的图象范围之内。Robot能够捕获整个窗体或是它的一部分，窗体可以与其他窗体或是部分屏幕重叠。在这种情况下，Robot捕获该窗体并将那些不可见的部分保存为黑色。被捕获的区域是一个象素图象，它包括颜色、高度和宽度。 要使该类VP通过验证，窗体的大小和屏幕的分辨率应该在回放时与录制时保持一致。</p>
<p>
	　　十、File Comparison</p>
<p>
	　　使用File Comparison VP在回放时来比较两个指定的文件。这种比较是基于文件的内容和大小，而不是文件的名称和日期。</p>
<p>
	　　在创建此类VP的时候，你需要指定驱动器、目录和文件名。在回放时，Robot按字节来比较该文件。</p>
<p>
	　　注意：File Comparison VP 的名称并不出现在Asset pane中。(File Comparison 验证点的文件比较原理同DOS下的FC命令相同，但是没有FC命令可扩展，即FC可以带参数，但File Comparison 验证点不能带参数，只是进行二进制比较;其中的例子就是：对两个相同的ACCESS文件进行比较，无论怎么执行File Comparison 验证点，比较结果都是不同的，但如果用FC命令结果是两文件相同，所以File Comparison 验证点没有DOS下的FC命令强大，所以它对DOC文件、TXT文件比较是没问题，一旦对MDB、XLS文件比较，File Comparison 验证点就不是我们想象的结果;)#p#分页标题#e#</p>
<p>
	　　十一、File Existence</p>
<p>
	　　使用File Existence VP在回放时来查找一个文件。在创建此类VP的时候，你需要指定该文件的驱动器、目录和文件名。在回放时，Robot在指定的位置检查文件是否存在。</p>
<p>
	　　注意：File Existence VP 的名称并不出现在Asset pane中。</p>
<p>
	　　十二、Module Existence</p>
<p>
	　　用于验证指定的模块是否被装载到了指定的环境或过程中来，或者是否被装如了内存。在Windows环境下，模块被定义为可执行程序(.exe)、动态连接库(.dll或其他扩展名)、设备驱动程序(.sys 或.drv)或者是显示字体(.fon)。</p>
<p>
	　　每一个过程都有属于自己的环境，它包括一系列被装载的模块。当你创建此类VP的时候，要选择模块的名称。你还可以选择环境(过程)的名称，在该环境下，VP验证模块是否被装载进了该过程。如果你没有指定环境，VP将验证该模块是否被装载进了内存(不论何处)。</p>
<p>
	　　注意：Module Existence VP 的名称并不出现在Asset pane中。</p>
<p>
	　　十三、Web Site Scan</p>
<p>
	　　当你回放一个Web Site Scan VP时，SiteCheck 启动运行并且根据你录制该VP时所选择的选项来浏览该站点。如果发现了任何的缺陷，该VP将失败。</p>
<p>
	　　在你回放一个Web Site Scan VP之后，你可以在<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/testmanager/" target="_blank" >TestManager</A></STRONG>的日志中查看回放的结果。</p>
<p>
	　　十四、Web Site Compare</p>
<p>
	　　当你回放一个Web Site Compare VP时，SiteCheck 启动运行并将你所选择的基线与你录制该VP时所选择的站点进行比较。如果发现了任何的缺陷，该VP将失败。</p>
<p>
	　　在你回放一个Web Site Compare VP 之后，你可以在TestManager的日志中查看回放的结果</p>
<p>
	　　下面通过一个实际的例子演示一下如何使用验证点。</p>
<p>
	　　数据准备：Forp办公资源系统 我的工作&mdash;目录维护模块</p>
<p>
	　　验证内容：选择一个目录，点击编辑后 是否出现了期望的编辑窗口。</p>
<p>
	　　操作步骤：</p>
<p>
	　　1、录制脚本，功能：选择一个目录，点击编辑，然后直接保存。(脚本忽略)。</p>
<p>
	　　2、在脚本的编辑代码下面，插入验证点Window Existence。出现如下对话框。可以给验证点命名、设置重新获取时间及超时时间、选择期待的验证结果。</p>
<p>
	　　3、设置各项参数后，点击OK，出现下图的对话框，在输入框中填写需要验证窗体的识别方式&ldquo; Caption=维护目录 &ndash; 网页对话框&rdquo;。如果不知道窗体的识别方式，可以点击Select按钮去选择窗体。</p>
<p>
	　　4、点击OK后，自动生成脚本</p>
<p>
	　　Result = WindowVP (Exists, &quot;Caption=维护目录 &ndash; 网页对话框&quot;, &quot;VP=Window Existence;Status=NORMAL&quot;)</p>
<p>
	　　5、执行脚本，结束后会在TestManager中生成日志文件来记录脚本及验证点的执行结果。</p>
]]></description>
    <pubDate>Wed, 07 Dec 2011 09:36:26 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>Robot</category>
    <author>领测软件测试网采编</author>
    <comments>未知</comments>
</item>

</channel>
</rss>
