共同探讨QTP相关问题

发布新日志

  • [转贴]什么时候应该进行自动化测试?(源创文章【翻译】)

    2008-06-09 10:31:18

    我希望可以自动化实现尽可能多的测试。如果只跑一次测试会使我很不舒服。如果一个程序员改变了代码并引进了一个bug,怎么办?如果我没抓住那个缺陷,只是因为我在变化之后没有进行新的测试,怎么办?我将不感到可怕吗?所以我需要使用自动化测试工具来实现多次的重复测试工作。
    恩,是这样的,当我使用了自动化测试后也没有觉得舒服。测试花费了很长的时间,最终发现是我过度的使用了自动化测试。在我定义的测试里其实只有少量的测试需要自动化测试来帮助完成。多余的自动化测试在运行时是不会发现任何有价值的bug的,毫无意义!
    现在的问题是怎样做合理的自动化测试呢?当我从事测试这项工作,作为一个测试员我一般会为一些产品功能设计一系列的测试。对他们中的每个来说,我需要决定哪个测试应该使用自动化测试来进行。这篇文章描述了我在权衡测试中的看法。

    设想
    为了使我的论点清楚,我一定要避免一次去尝试描述所有可能的测试设想。如果我挑选一个很有用的设想,清楚的描述它,你作为一个读者会很好的了解。然后留下你把论点用于你具体的项目中。下面是我的设想:
    1. 首先,你应该拥有一个固定的自动化的支持。即,自动化工具是可用的。你可以不是一位专家,但是你必须知道怎样使用他们。写好配置文件。我设想你使用已有的工具进行工作,不会去使用新的工具,将一些简单的功能放到配置文件中,或者了解更多的测试自动化。问题是:凭你现有的这些可以证明你的自动化测试一定是正确地吗?现在给你这个答案还为时过早。
    在其他情况下,你可能赞同在一个工程后期增加自动化测试。在本文中没有对到好与不好做辩论,但通过上下文,你会知道自动化测试的价值所在。
    2. 这里只有两种可能性:完全的自动化测试,没有一点的人为操作;全手工进行的自动化测试,使用一次测试后就该扔掉了。这是一个事务上的两个极端。你可以自动化测试那些组织起来很麻烦的部分,但是其余留下的部分做手工。你可能有足够用的很仔细的文献证明能容易再跑一次手动测试。当你深刻理解了从一个极端到另一个极端的时候,你将会清楚的认识到在一个连续的统一体上特殊的测试点应该在哪里。
    3. 自动化测试和手工测试是似是而非的。当然也不是总是这种情况。例如,负载测试经常需要创造大量的使用者的同时操作的情况。如果需要300个测试员同时使用一个产品,很明显是很低效的。所以负载测试需要被自动化。
    4. 通过外部接口所做的测试(“黑箱测试”)。相同的analysis applies在代码级测试——在文章的后面会给出一个简短的例子——但是我将不描述全部细节。
    5. 没有必要必须什么情况都使用自动化测试。经验告诉我们在测试中需要把自动化测试和手工测试完美的结合。
    6. 首先你需要设计好测试然后决定它是否需要被自动化执行。实际上,自动化的需要对设计的影响是很普遍的。这让人很伤心,因为有些时候测试会被减弱只是因为使用了自动化。但是,如果你理解了自动化测试并正确地使用它,它可以给程序带来无害的调整甚至改进。
    7. 你有一定量时间完成你的测试。你应该尽力在规定时间内做更好的测试。在测试开始时,会在是否要测试不那么普通的情况和需要的时间上有一些争论。

    Overview
    我的解决过程用到了这些问题。
    1. 如果自动化执行一次测试需要的时间多于其做简单的手工测试的时间,会多多少时间?
    2. 一个自动化测试过程有一个生命周期,在其生存期它必须赔偿那额外的成本。迟早这次试验可能死吗?什么事件很可能结束它?
    3. 在它的生存期内,它测试出额外bug的可能性(是否在测试的第一时间内发现了bug)?怎样平衡这些不可预测的问题和代价之间的关系?
    如果这些问题没有被彻底的解决,其他小的问题就没有平衡可言。
    第3个问题是必要的,这个我将在大多数细节里继续探索。令人遗憾,一个好的答案需要对一个产品有更好的理解,我将解释应该怎样去把握一个准确的理解。

    使用自动化测试会失去什么?
    通常创造一个自动化测试往往要比手工的进行一次测试所要花费的时间多。(注释一)而费用上的微小的变化取决于这个产品和它的自动化设计。
    l 如果产品需要经过一个GUI(图形用户接口)被测试,那么你的自动化测试计划手稿中就需要准备驱动GUI接口的部分(本质上要有简单的计划),在很多时候一个自动化测试其花费会和手工测试差不多。
    l 如果你使用GUI capture/replay工具来记录产品内部接口间的交互并通过这些构建一个脚本的话,自动化测试相对来说是便宜的。但是,当因为错误导致需要重头安排自动化测试的时候,当需要组织整理测试的一些文档记录的时候,当测试进程陷入到bug中并且不断恶化的时候,等等这些,自动化测试就不像人工测试那样的廉宜。这些小细节下引起的成本的追加往往会不容易使人们注意它。
    l 如果你现在正在对一个编译器进行测试,那么使用自动化测试的成本就会比使用手工的要多一些,应为大部分的时间会为编译器写测试计划,来使编译器根据计划进行编译。这些计划无论会不会被重复使用都的编写。而往往这些计划都不会被重复使用。
    如果你的测试环境对使用自动化测试非常适合,而使用自动化测试的花费只比手工测试多的10%的话。(我认为这种情况很罕见。)这意味着,一旦你自动化实行了十次测试,做一次手工测试——对产品做一次独特的测试——这在用户提出要求前是不可能实行的。如果自动化测试的花费是更大的,那十个自动化测试可以替代运行十个、二十个或者更多的手工测试的话,应该如何掌握和处理呢,我们会发现什么?
    所以,我们第一个测试自动化的问题应该是这样的:
    如果我对它进行自动化测试,我会失去手工测试中的什么?我会丢掉多少bug,自动化测试的严格性?
    依赖于你的设计,其答案是会变化的。假设你是一个电信系统的测试人员,在这里对其质量要求是很高的而且测试的预算会是非常充足的。你的答案可能是“如果我用自动化执行这个测试,我将或许会失去三个手工测试点。但是,我做好了非常漂亮的完整的测试设计工作,我清楚的认识到那些额外的测试只会对现有的测试产生一些价值不高的变化。严格的说,他们应该分别的执行,因为我真的怀疑他们也许会发现新的严重的bug。”对你来说,自动化测试的价值是很低的。
    或者你正在测试一个产品需求和代码在最近几个月内在不停变化的工程的1.0版本。你的答案可能是“嘿!我没有时间去尝试为每一个明显的变化都重新做一次测试。这种情况下,我将会使用自动化来进行测试,同时我要保证其发现新的严重的bug的机会降到最低。”对你来说,自动化测试的价值是很高的。
    这是我衡量自动化测试价值的标准——可以第一时间或预先发现bug——这看上去似乎有些古怪。人们通常是用做这项工作所花费的时间来衡量自动化测试的代价的。我之所以使用这样一个衡量标准是因为自动化测试的目的是在下一次运行中能够发现更多的bug。发现bug的数目体现了自动化测试的价值,因此衡量自动化测试价值的标准也因该统一到这个上面来。(注释2)
    ________________________________________________________________________________________
    (注释1:有一些例外。例如,或许测试可以被制成模板。用一个工具可以通过处理这些模板中的表单来驱动产品的测试。而向模版表格中填入数据做自动化测试要比做手工测试快的多。看看[Pettichord96]和[Kaner97]的风格,如果用手工测试的花费会很大,我们就不会去牵扯它。但是需要小心:人们往往会低估自动化测试的花费。举个例子来说,将需要输入的数据填写到表单中会是一件非常easy的事,但是自动化测试的结果的验证却会是一件花费很大的事情。感谢Dave Gelperin在这个问题上给我的提示。)
    (注释2:在我和Cem Kaner的谈话中,第一次让我感到应该这样衡量自动化测试的价值。Noel Nyman指出这是约翰 Daly规则的一个特别的情形,就像你总是问题:“我在做测试的时候还有哪些bug没有发现?”)

    在预算上需要注意的地方
    我想让你尽可能的准确估计在你的自动化测试中平均会出现的bug数是多少,并将结果告诉我。你的答案不应该是“0.25”或是“0.25±0.024”。你的答案应该象这样“我会努力减少bug数的出现”或者“我的bug决不会再次出现”。
    稍后,你会被要求估计一个测试的生命周期(生存时间)。这个答案应该是这个样子的:"不会超过软件的发布时间" 或者 "a long time" than "34.6 weeks".
    然后,你会被要求估计在测试生命周期内可以找到多少个bug?答案依然是模糊的。
    最后,你会被要求对自动化测试和手工测试模糊估计的结果做一个比较并做一个结论。
    这样做有用吗?
    回答是肯定的。当你考虑选择谁的时候,需要做出这样的比较——也许不是在表面上做的——尽管是一些少的比较模糊的数据。我的经验是快速的回答这些问题希望可以引导一次优秀的测试,不去管答案是否精确。我在这里倾向于不需要精确的去回答这些问题,但是有用的问题和容易被误解的问题必须要做精确的回答,不要给别人带来误导。

    How Long Do Automated Tests Survive?(一次自动化测试的生命期会有多久?)
    当代码做了改动之后,自动化测试显示出它的价值所在。除了一些极少数类型的测试以外,在代码未作任何改动之前去做重复测试是一个浪费时间而且没有任何效果的做法:它会找出一些bug,但和你第一次做测试所发现的是一样的。(例外,像所用时间测试和压力测试可以概略的用同一中方式来分析。因为简单我忽略了它们。(I omit them for simplicity.))
    但是一个测试不会永远的持续下去。一些观点指出,产品上所做的变动很可能破坏一个测试。这个被破坏的测试将不得不做出修改或是被丢弃。我有一个很合理的近似值是这样的,我们去做一个测试的修改和抛弃已有的测试而重新编写一个新的测试的价值是同样的(注释3)。但是无论在变化后你做什么补救,如果修改和重新编写都不能达到要求的话,我认为放弃它而使用手工测试会比较好一些。
    简而言之,测试的有用寿命看起来像是这一样:

    当决定是否做自动化测试的时候,你必须估计出存在多少会影响测试的代码。如果你的答案是“不多”,那么自动化测试在发现bug上的表现会特别的出色。
    你需要一些背景知识来估计一个测试的寿命。你还需要了解一些代码影响测试的途径。在这里我们从一个特别简单的图表开始:

    ________________________________________________________________________________________
    (注释3:如果你使用录制工具能够将一次测试重放,那样的价值将会比在开始测试时记录其预期结果要有价值的多。花一些时间和精力在这个上面是在一次测试中是很有必要的。如果你要修改测试脚本,你需要正确地理解这个脚本,修改它测试它,确定你没有可能揭露的所有问题。你会发现新的测试脚本不可能完成老脚本能做的所有功能,所以可以将一个修改测试保留新旧两个测试脚本。如果你的testing effort已经确定下来,那么去修改一个测试要比从头开始写一个测试要好的多。这些将会不影响你在纸上做的工作;那样做会减少自动化测试所需要的花费。这一切的前提是你要清楚的认识和把握一次修复所需要的代价,人们往往会把代价估计不足。)
    假设你的工作是要写一组测试来检测用户是否输入了正确的电话号码,那么你就需要检查是否是输入了有效地阿拉伯数字而非其它字符等等。如果你清楚其中的代码(据我了解很少人会这样)你可以设计一个规划列表将校验电话号码的代码使用高亮显示做出标记。通常称它为 the code under test。这部分代码可以更加完善你的测试任务。
    在大多数时候,你不可能有机会直接运用the code under test。例如:你不可能直接得到确认电话号码的那部分代码,因为它通常会是一个用户的一部分属性,就需要通过用户接口来测试,将与其关联的那部分代码组织起来,使这部分转变到内部程序的数据,并会按照常规将这部分数据表现出来。当然,你也不能直接对表现出来的数据进行检测,因为转变会通过其他的代码来将其转变成在用户界面可见的最后的数据(就像非法的数据会转换成错误信息)。我称这些代码为intervening code——介于测试本身和code under test之间的代码。

    Changes to the intervening code(对介入其间的代码进行变化)
    介入其间的代码是导致测试死亡的主要因素。而且用户图形界面接口较上文提到的那个接口和一些硬件驱动接口相比更是这个样子。例如:假设用户接口要求你输入电话号码,但是现在变化为要求提供一个电话按键区的视觉表现。这时你要使用鼠标敲击号码模拟使用真实的电话。(这是个非常愚蠢的主意,但是这怪异的事情已经发生了。)尽管接口传给了code under test一个正确的值,但是用户界面的变化很可能破坏一次自动化测试,是因为很可能使用者再没有地方输入电话号码了。
    就像另外的一个例子,一个输入的错误用户界面会用其它的方法来告诉用户。它可能会刷新主窗体使其显示红色同时发出特殊的声音来代替弹出的提示信息来告知你不能完成这次操作。但是,如果你的测试是通过测试是不是弹出提示信息来判定的,那么将视这种正常的运行为一个bug。很显然这个测试就没有效果了。
    "Off the shelf "测试自动化工具能做避免测试死亡的有限制的工作。例如:大多数的GUI自动化测试工具都可以忽视文本框大小、位置和颜色的改变。从而把握像上面两段所提到的那些大的改变,但是需要事先定制。这需要在你的工程中有一些人去创建test libraries。这样就要求你,一个测试人员,在编写好测试的特殊术语,尽可能多的忽略用户接口的细节。例如,你的自动化测试可能包含这样一行定制的信息:try 217-555-1212  try是test library程序,它的作用是将电话号码翻译成接口可以知道的术语。如果用户界面接受在输入框中输入字符,try会在其中输入电话号码。如果需要通过显示在屏幕上的特定图形区域键入电话号码时,try也会做到。

    test library 可以有效地将那些不相关信息过滤掉。这样我们就可以详细的准确的测试那些与功能相关的数据。在输入上,增加这些附加信息是intervening code所必须的。在输出上,它们将intervening code中的信息全部压缩到一个很重要的模块中,其中的信息实际上可以当作是Code Under Test的一个延伸。这种过滤可以用左图来描述:
    多数用户界面的变化不会需要对测试做更改,而只需要对test library做相应的修改。应为test Code要比library Code多的多,所以只修改library Code的代价会很低。
    但是,尽管我们有更好的补偿性的代码也不可能将测试从所有的变化中隔离出来。它仅仅是尽可能的去预期所有的事情。所以其中有很多可能性,将来很可能出现一些问题破坏你的测试。你必须问自己这样一个问题:
    在变化中Intervening Code会把测试保护到什么程度?
    你需要估计intervening Code的改变对测试造成影响的可能性。要保证用户界面永远的不会改变是一件不可能的事情,这就使你需要不停的改变自动化测试的脚本以保证测试可以自动的执行。(我不会相信界面冻结后永远不会变化,除非manager答应如果以后每做一个新的修改将会给我100美元)
    如果变化是可能的,你一定会被询问对你的test Library保护你的测试不受其影响正常执行有多大的信心。如果说test Library不能保护测试,那么起码它可以很容易的做出改动以适应变化。如果花费一个半小时的时间可以拯救300个测试,那么所做的一切是值得的。但是,小心:很多人往往低估了维护test Library的困难,特别是在变化后需要手工的对测试test Library进行反复的修改。不应该马上就放弃,抛弃所有的测试类和test Library,从头开始,因为很可能只需要简单的修改就可以完成需要的测试。
    如果你没有test Library——如果你正在使用自动化GUI测试工具来捕获和重放模式——你不要期待会有任何保护。一次对界面的修改会让你的大部分的测试“死亡”。往往不会有足够的时间来允许我们完成对发生变化的测试进行修改,我们不得不在少的花费和短的生命生存期之间做出选择。
    Changes to the code under test(改变测试下的代码)
    Intervening Code不是唯一可以变化的代码,code under test同样可以变化。特别的是,它可以改变使其完全不同的去做某件事。
    例如,假设几年前某个人写了一个关于点话号码的校验测试,为了检查那些不符合要求的电话号码,就像1-888-343-3533。在当时,没有888这样的电话号码,但是现在却存在这样的号码。这样就导致了测试拒绝888号码给出提示,尽管现在这个号码是合法的,但是测试脚本会按照先前的规则进行测试从而拒绝它。解决这件事情可能很简单也可能很复杂。如果你了解问题所在那么这件事是一件很容易的事情:只需要将“888”改为“889”。但是可能很困难对测试做足够的解释去了解测试电话号码整个的方法。或者你没有意识到“888”再现在来说是一个合法的号码,所以你会认为测试理所应当的测出这条Bug。测试在你使用一些假的“Bug”来骚扰开发人员之前是不会固定不变的。
    所以,在决定是否要进行自动化测试之前你同样需要问自己这样的几个问题:
    code under test 行为的稳定行如何?
    注意强调的“稳定性”——只要他们保持外部可试行为相同代码的代码就OK!
    不同类型的产品,不同类型的code under test有不同的稳定性。电话号码实际上还是相当稳定的。再如一个银行帐目管理系统可以说是一个相当稳定的系统,如果每次存100元需要收取30元的手续费那么记录到帐的就是130元,这种关系是稳定的(除非银行改变了收费的标准)。而用户的界界面是相当的不稳定的一个因素。
    增加行为往往是无害的。例如,可能有这样一个检查,测试从一个帐户撤回 $100 由于 $30 生产错误导致操作失败但是帐户余款方面的没有改变。但是,现在测试被重写,增加了一个新的特性:顾客可以根据需要确定是否需要“自动透支保护”功能,它允许用户提取多余他帐户内存在的钱数。这种变化不会破坏现有的测试,只要默认的帐户测试保持原来的行为。(当然,新的测试必须依*新的行为来运行。)
    我们的立足点在哪里呢?
    现在我们知道了自动化测试应该跳远的障碍:必须保证自动化测试的价值要大于采用手工测试的价值。我们需要估计一个测试的生命周期,它可以有机会创造出价值的时间段。现在,我们需要询问一下它可以创造出价值的实际可能性。我们可以期待它能发现什么样的Bug?
    测试会延续它的价值吗?
    这里的争论比较复杂,所以我先给出一个大纲。
    1. The code under test has structure。如一个有用的近似值,我们能把code under test分为功能代码和支持代码。
    2. 测试人员编写那些有业务特色的脚本代码,其它support code对测试人员来说是不可见的。
    3. 对业务代码的变动会对测试的行为产生影响。因此,因为它导致测试的死亡的可能性要比导致测试显示出一个Bug的可能性要大得多。
    4. 测试的价值主要体现在当support code发生变化后发现Bug的能力。
    5. 我们不知道support code的任何事情!我们怎样去知道将来测试会不会把它当作是Bug被捕获?当找到一些Bug的时候我们怎样推测整个的测试过程是正确的?
    ----一般情况下如果某个地方做了变动那么那里就会出现Bug。如果那里在过去做了变化那么将来这里会有更多的变更。
    ----我们很难知道测试是否正常的工作,但是可以说明有一个功能没有正常的进行工作。这样的测试不会自动的执行。
    6. 测试下的代码同其它的产品互相的影响,这些对support code的影响比较多。我们希望由于support code导致的Bug我们可以及时发现。
    ----我们再来认识一个低价值测试的特征。高价值的测试不可能是一个feature-driven的测试;而通常会是一个task-driven。
    次要的考虑
    当我在思考做自动化测试的时候我需要在头脑中留意这样一些事情:
    l 人们(用户)可以会发现自动化测试没有发现的bug。我们用来过滤掉界面上不相关的变化的工具和测试库可能同样的也会过滤掉一些古怪的bug。我曾亲眼看到一个测试员和偶然的发现当他移动鼠标的时候鼠标会不停的闪动而且这个现象不会经常的出现,对这个现象进行了深入的研究后我们发现了一个严重的bug。我听说过这样的一组测试,测试在屏幕上以X,Y为坐标显示一个图形,而这个图形测试人员在界面上无法看到,可是测试工具却可以发现它,并给出了正常的报告。
    l 但是,如果测试人员非常的注意那些古怪的bug,那么会非常的辛苦而且还不会得到准确的检测结果。如果潜藏一个精确度为0.0000001的bug,人是难以发现它的,而工具就不会。注意Nyman指出工具可能分析出来人们无法见到的东西。测试工具不会紧紧局限到屏幕上可见的那一部分内容,他可以发现表明下数据结构上的问题。
    l 事实上,人们不可能保证反复的以手工的方式重复输入相同数据来完成同样测试的过程丝毫不差,相反的都会有些细小的差别。例如,人们的操作犯了错误、后退、重新输入,这样有时偶然会发现在错误操作处理和support code交互之间的bug。
    l 需要在不同外部配置下进行的测试尽可能多的使用自动化测试。如果需要在其它的操作系统、驱动或者第三方的函数库等情况下运行程序,理论上等同于使用不同的support code来运行程序。如果你知道将来会有这些变化,自动化测试将有很高的价值。但是,编写一个对外部配置敏感的测试其实是一个骗局。因为这样很可能使这组测试没有多少对bug的判断力而只是可以在不同的环境下运行。
    l 如果在第一次运行测试的时候找到了一个bug,你清楚你应该在对bug进行修改后需要重新的对它进行测试。但是可能仅仅对这一个bug做自动化测试是不充足的。可以对这部分代码做一个标记,说明将来会对这部分做更改,这样还可以提醒你对这部分进行更多的自动化测试,如果bug出现在support code里,尤其应该这样。
    l 如果你的自动化测试设计的支持性非常的出色,开发人员可以很容易的使用它,让他们做一次测试观察结果要比你把bug通过仔细的描述来再现给开发人员要快的多也好的多。这中测试的自动化执行的级别会很高。开发人员通常使用测试工具会很困难,或者没有在他们的机器上安装这些工具,再或者有一个环境对测试造成不可思议的破坏等等。如果真的让开发来运行测试有可能会阻止了他们正常的工作,浪费了当量的时间,而这些的目的只是为了避免书写详细的bug报告。
    l 最让人恶心的是在手工测试中找到了bug,但是没有办法再现。可能你做了些什么,可是根本没有记住是怎么做的。自动化测试很少会出现这样的情况(尽管有时候你没有注意到它们依*了已经变化了的环境)。产品中的跟踪和日志可以给我们很大的帮助,这些对开发人员是非常有用的。如果这些东西不存在,自动化测试的工具可以用来创造类似日志的文档记录键盘和鼠标的操作信息。这种日志的使用价值以来它的可读性是怎么样的,在程序内部产生的日志文档是非常好的。根据我所见到的,大部分的测试人员可以在用来做记录的便签儿上得到很多东西。
    l 一组自动化测试每天都可以对整个的项目进行一次探测。一个手工测试的努力可能保持长久的时间来对所有的功能进行重复的测试。但是在做过不正确的修改之后自动化测试会很迅速的发现它。如果原先正常工作的部分现在被破坏了,首先的一个问题是“最后修改的代码是哪一部分?”调试一天内所做的修改是一件很没有必要的事情,那么使用自动化测试来查看修改的情况是一件很高兴的事情。
    注意,真正有威胁性的调试是在处理于子系统之间的关系。如果产品很大,内容很繁琐很难进行调试,这样自动化测试会有很高的价值。对任务驱动的测试更是如此(尽管他的生命周期不是很长)。
    l 在程序开发者做了一个修改后,测试人员要进行检查。可以包含原有测试的主要框架,再根据具体情况做相应变化。有时候交流很贫乏,测试人员不可能及时的被告知已经修改的地方。我们运气好,往往这样做的结果是自动化测试不会正常的继续进行,导致测试者开始注意修改的地方。自动化测试组越少,发生这种可能的机会越小。(我发现自动化测试是一个拐弯抹角的花费昂*的一个基本交流的替代品。)
    l 因为施行自动化测试需要时间,所以你不可能像手工测试那样在出现bug的第一间告知开发人员。如果你的最终测试报告在两个星期后发布,而这段时间开发人员又在原先的基础上做了新的功能,这样就是一个问题。
    l 我们要尽力避免只是因为实现自动化测试比较容易而不是考虑发现bug的能力来组织测试。你可能会发现你自己设计的测试太过简单,而已清醒的知道因为过于简单你的测试会在产品发生变化的时候被破坏。这样简单的测试也很少会发现support code下的bug。
    l 假设产品改变了它的部分功能,导致自动化测试给出不真实错误报告。我们可以通过更改我们的测试来屏蔽掉这些虚假的报告,但同时我们的做法可能降低测试发现bug的能力。这样测试功能在无形之中是衰退了的。
    l 一个好的自动化测试的测试类可以按照一定的顺序执行,并且可以每日改变之间的次序。这可能是从一套特征测试创造任务驱动测试的一个廉价的方法。这是Edward L. Peters当看完这篇文章的草稿后提醒我注意的地方。Noel Nyman指出,自动化测试在利用偶然性(测试过程的顺序和输入的数据)的方面比人要好。
    l 在准备开始测试之前需要做好自动化测试的准备。那样的话,写测试脚本的时间就不会占用测试时间,就不需要在手工测试和它之间困难的选择。当这种产品准备测试时,你仍然应该考虑实际上使那些脚本工作的费用。
    l 一次自动化的试验可能不会有任何发现直到下一版本出现之前。.手动测试将会发现一个版本中存在的任何bug。 在当前版本发现bug要比在下一个才发现版本bug有价值的多。(如果当前版本没有成功那么就不会有下一个版本。)
  • QTP中常用的VBS函数

    2008-06-02 20:12:05

    转自:http://bbs.51testing.com/thread-116486-1-1.html

    Left 函数
    返回 Variant (String),其中包含字符串中从左边算起指定数量的字符。
    语法
    Left(string, length)
    Left 函数的语法有下面的命名参数:

    部分        说明          
    string        必要参数。字符串表达式其中最左边的那些字符将被返回。如果 string 包含 Null,将返回 Null。          
    length        必要参数;为 Variant (Long)。数值表达式,指出将返回多少个字符。如果为 0,返回零长度字符串 ("")。如果大于或等于 string 的字符数,则返回整个字符串。         

    说明
    欲知 string 的字符数,使用 Len 函数。
    注意    LeftB 函数作用于包含在字符串中的字节数据。所以 length 指定的是字节数,而不是要返回的字符数。


    Mid 函数
    从字符串中返回指定数目的字符。
    Mid(string, start[, length])
    参数
    string
    字符串表达式,从中返回字符。如果 string 包含 Null,则返回 Null。
    Start
    string 中被提取的字符部分的开始位置。如果 start 超过了 string 中字符的数目,Mid 将返回零长度字符串 ("")。
    Length
    要返回的字符数。如果省略或 length 超过文本的字符数(包括 start 处的字符),将返回字符串中从 start 到字符串结束的所有字符。
    说明
    要判断 string 中字符的数目,可使用 Len 函数。
    下面的示例利用 Mid 函数返回字符串中从第四个字符开始的六个字符:
    Dim MyVar
    MyVar = Mid("VB脚本is fun!", 4, 6) 'MyVar 包含 "scrīpt"。
    注意   MidB 函数与包含在字符串中的字节数据一起使用。其参数不是指定字符数,而是字节数。

    Len 函数
    返回字符串内字符的数目,或是存储一变量所需的字节数。
    Len(string | varname)
    参数
    string
    任意有效的字符串表达式。如果 string 参数包含 Null,则返回 Null。
    Varname
    任意有效的变量名。如果 varname 参数包含 Null,则返回 Null。
    说明
    下面的示例利用 Len 函数返回字符串中的字符数目:
    Dim MyString
    MyString = Len("VBscrīpt") 'MyString 包含 8。
    注意   LenB 函数与包含在字符串中的字节数据一起使用。LenB 不是返回字符串中的字符数,而是返回用于代表字符串的字节数。

    Right 函数
    从字符串右边返回指定数目的字符。
    Right(string, length)
    参数
    string
    字符串表达式,其最右边的字符被返回。如果 string 参数中包含 Null,则返回 Null。
    Length
    数值表达式,指明要返回的字符数目。如果为 0,返回零长度字符串;如果此数大于或等于 string 参数中的所有字符数目,则返回整个字符串。
    说明
    要确定 string 参数中的字符数目,使用 Len 函数。
    下面的示例利用 Right 函数从字符串右边返回指定数目的字符:
    Dim AnyString, MyStr
    AnyString = "Hello World"      ' 定义字符串。
    MyStr = Right(AnyString, 1)    ' 返回 "d"。
    MyStr = Right(AnyString, 6)    ' 返回 " World"。
    MyStr = Right(AnyString, 20)   ' 返回 "Hello World"。
    注意   RightB 函数用于字符串中的字节数据,length 参数指定返回的是字节数目,而不是字符数目。

    InStr 函数
    返回某字符串在另一字符串中第一次出现的位置。
    InStr([start, ]string1, string2[, compare])
    参数
    start
    可选项。数值表达式,用于设置每次搜索的开始位置。如果省略,将从第一个字符的位置开始搜索。如果 start 包含 Null,则会出现错误。如果已指定 compare,则必须要有 start 参数。
    string1
    必选项。接受搜索的字符串表达式。
    string2
    必选项。要搜索的字符串表达式。
    compare
    可选项。指示在计算子字符串时使用的比较类型的数值。有关数值,请参阅“设置”部分。如果省略,将执行二进制比较。
    设置
    compare 参数可以有以下值:

    常数        值        描述          
    vbBinaryCompare        0        执行二进制比较。          
    vbTextCompare        1        执行文本比较。         
    返回值
    InStr 函数返回以下值:

    如果        InStr 返回          
    string1 为零长度        0          
    string1 为 Null        Null          
    string2 为零长度        start          
    string2 为 Null        Null          
    string2 没有找到        0          
    在 string1 中找到 string2        找到匹配字符串的位置          
    start > Len(string2)        0         
    说明
    下面的示例利用 InStr 搜索字符串:
    Dim SearchString, SearchChar, MyPos
    SearchString ="XXpXXpXXPXXP"   ' 要搜索的字符串。
    SearchChar = "P"   ' Search for "P".
    MyPos = Instr(4, SearchString, SearchChar, 1)   ' 在位置 4 进行的文本比较。返回 6。
    MyPos = Instr(1, SearchString, SearchChar, 0)   ' 在位置 1 进行的二进制比较。返回 9。
    MyPos = Instr(SearchString, SearchChar)   ' 默认情况下,进行的是二进制比较(省略了最后的参数)。返回 9。
    MyPos = Instr(1, SearchString, "W")   ' 在位置 1 进行的二进制比较。返回 0(找不到 "W")。
    注意   InStrB 函数使用包含在字符串中的字节数据,所以 InStrB 返回的不是一个字符串在另一个字符串中第一次出现的字符位置,而是字节位置。

    LTrim、RTrim与 Trim 函数
    返回不带前导空格 (LTrim)、后续空格 (RTrim) 或前导与后续空格 (Trim) 的字符串副本。
    LTrim(string)
    RTrim(string)
    Trim(string)
    string 参数是任意有效的字符串表达式。如果 string 参数中包含 Null,则返回 Null。
    说明
    下面的示例利用 LTrim, RTrim, 和 Trim 函数分别用来除去字符串开始的空格、尾部空格、 开始和尾部空格:
    Dim MyVar
    MyVar = LTrim("   vbscrīpt ")   'MyVar 包含 "vbscrīpt "。
    MyVar = RTrim("   vbscrīpt ")   'MyVar 包含 "   vbscrīpt"。
    MyVar = Trim("   vbscrīpt ")   'MyVar 包含 "vbscrīpt"。

    Rnd 函数
    返回一个随机数。
    Rnd[(number)]
    number 参数可以是任意有效的数值表达式。
    说明
    Rnd 函数返回一个小于 1 但大于或等于 0 的值。number 的值决定了 Rnd 生成随机数的方式:

    如果 number 为        Rnd 生成          
    小于零        每次都相同的值,使用 number 作为种子。          
    大于零        序列中的下一个随机数。          
    等于零        最近生成的数。          
    省略        序列中的下一个随机数。         
    因每一次连续调用 Rnd 函数时都用序列中的前一个数作为下一个数的种子,所以对于任何最初给定的种子都会生成相同的数列。
    在调用 Rnd 之前,先使用无参数的 Randomize 语句初始化随机数生成器,该生成器具有基于系统计时器的种子。
    要产生指定范围的随机整数,请使用以下公式:
    Int((upperbound - lowerbound + 1) * Rnd + lowerbound)
    这里, upperbound 是此范围的上界,而 lowerbound 是此范围内的下界。
    注意   要重复随机数的序列,请在使用数值参数调用 Randomize 之前,立即用负值参数调用 Rnd。使用同样 number 值的 Randomize 不能重复先前的随机数序列。

    Randomize 语句
    初始化随机数生成器。
    语法
    Randomize [number]
    可选的 number 参数是 Variant 或任何有效的数值表达式。
    说明
    Randomize 用 number 将 Rnd 函数的随机数生成器初始化,该随机数生成器给 number 一个新的种子值。如果省略 number,则用系统计时器返回的值作为新的种子值。
    如果没有使用 Randomize,则(无参数的)Rnd 函数使用第一次调用 Rnd 函数的种子值。
    注意 若想得到重复的随机数序列,在使用具有数值参数的 Randomize 之前直接调用具有负参数值的 Rnd。使用具有同样 number 值的 Randomize 是不会得到重复的随机数序列的。
    Rnd 函数示例
    本示例使用 Rnd 函数随机生成一个 1 到 6 的随机整数。
    本示例用 Randomize 语句初始化随机数生成器。由于忽略了数值参数, 所以 Randomize 用 Timer 函数的返回值作为新的随机数种子值。

    Dim MyValue
    Randomize   ' 对随机数生成器做初始化的动作。

    MyValue = Int((6 * Rnd) + 1)   ' 生成 1 到 6 之间的随机数值。
    Split函数
    描述
    返回一个下标从零开始的一维数组,它包含指定数目的子字符串。
    语法
    Split(expression[, delimiter[, count[, compare]]])
    Split函数语法有如下几部分:

    部分        描述          
    expression        必需的。包含子字符串和分隔符的字符串表达式 。如果expression是一个长度为零的字符串(""),Split则返回一个空数组,即没有元素和数据的数组。          
    delimiter        可选的。用于标识子字符串边界的字符串字符。如果忽略,则使用空格字符(" ")作为分隔符。如果delimiter是一个长度为零的字符串,则返回的数组仅包含一个元素,即完整的 expression字符串。          
    count        可选的。要返回的子字符串数,–1表示返回所有的子字符串。          
    compare        可选的。数字值,表示判别子字符串时使用的比较方式。关于其值,请参阅“设置值”部分。         

    设置值
    compare参数的设置值如下:

    常数        值        描述          
    vbUseCompareOption        –1        用Option Compare语句中的设置值执行比较。          
    vbBinaryCompare        0        执行二进制比较。          
    vbTextCompare        1        执行文字比较。          
    vbDatabaseCompare        2        仅用于Microsoft Access。基于您的数据库的信息执行比较。         

    Replace 函数
    返回字符串,其中指定数目的某子字符串被替换为另一个子字符串。
    Replace(expression, find, replacewith[, compare[, count[, start]]])
    参数
    expression
    必选项。字符串表达式包含要替代的子字符串。
    Find
    必选项。被搜索的子字符串。
    Replacewith
    必选项。用于替换的子字符串。
    Start
    可选项。expression 中开始搜索子字符串的位置。如果省略,默认值为 1。在和count 关联时必须用
    count
    可选项。执行子字符串替换的数目。如果省略,默认值为 -1,表示进行所有可能的替换。在和 start 关联时必须用。
    Compare
    可选项。指示在计算子字符串时使用的比较类型的数值。有关数值,请参阅“设置”部分。如果省略,缺省值为 0 ,这意味着必须进行二进制比较。
    设置
    compare 参数可以有以下值:

    常数        值        描述          
    vbBinaryCompare        0        执行二进制比较。          
    vbTextCompare        1        执行文本比较。         
    返回值
    Replace 返回以下值:

    如果        Replace 返回          
    expression 为零长度        零长度字符串 ("")。          
    expression 为 Null        错误。          
    find 为零长度        expression 的副本。          
    replacewith 为零长度        expression 的副本,其中删除了所有由 find 参数指定的内容。          
    start > Len(expression)        零长度字符串。          
    count 为 0        expression 的副本。         
    说明
    Replace 函数的返回值是经过替换(从由 start 指定的位置开始到 expression 字符串的结尾)后的字符串,而不是原始字符串从开始至结尾的副本。
    下面的示例利用 Replace 函数返回字符串:
    Dim MyString
    MyString = Replace("XXpXXPXXp", "p", "Y")   '二进制比较从字符串左端开始。返回 "XXYXXPXXY"。
    MyString = Replace("XXpXXPXXp", "p", "Y", '文本比较从第三个字符开始。返回 "YXXYXXY"。3,, -1, 1)

    StrComp 函数
    返回一个表明字符串比较结果的值。
    StrComp(string1, string2[, compare])
    参数
    string1
    必选项。任意有效的字符串表达式。
    string2
    必选项。任意有效的字符串表达式。
    Compare
    可选项。指示在计算字符串时使用的比较类型的数值。如果省略,则执行二进制比较。有关数值,请参阅“设置”部分。
    设置
    compare 参数可以有以下值:

    常数        值        描述          
    vbBinaryCompare        0        执行二进制比较。          
    vbTextCompare        1        执行文本比较。         
    返回值
    StrComp 函数有以下返回值:

    如果        StrComp 返回          
    string1 小于 string2        -1          
    string1 等于 string2        0          
    string1 大于 string2        1          
    string1 或 string2 为 Null        Null         
    说明
    下面的示例利用 StrComp 函数返回字符串比较的结果。如果第三个参数为 1 执行文本比较;如果第三个参数为 0 或者省略执行二进制比较。
    Dim MyStr1, MyStr2, MyComp
    MyStr1 = "ABCD": MyStr2 = "abcd"   '定义变量。
    MyComp = StrComp(MyStr1, MyStr2, 1)   ' 返回 0。
    MyComp = StrComp(MyStr1, MyStr2, 0)   ' 返回 -1。
    MyComp = StrComp(MyStr2, MyStr1)   ' 返回 1。

    CInt 函数
    返回表达式,此表达式已被转换为 Integer 子类型的 Variant。
    CInt(expression)
    expression 参数是任意有效的表达式。
    说明
    通常,可以使用子类型转换函数书写代码,以显示某些操作的结果应被表示为特定的数据类型,而不是默认类型。例如,在出现货币、单精度或双精度运算的情况下,使用 CInt 或 CLng 强制执行整数运算。
    CInt 函数用于进行从其他数据类型到 Integer 子类型的国际公认的格式转换。例如对十进制分隔符(如千分符)的识别,可能取决于系统的区域设置。
    如果 expression 在 Integer 子类型可接受的范围之外,则发生错误。
    下面的示例利用 CInt 函数把值转换为 Integer:
    Dim MyDouble, MyInt
    MyDouble = 2345.5678      ' MyDouble 是 Double。
    MyInt = CInt(MyDouble)    ' MyInt 包含 2346。
    注意   CInt 不同于 Fix 和 Int 函数删除数值的小数部分,而是采用四舍五入的方式。当小数部分正好等于 0.5 时, CInt 总是将其四舍五入成最接近该数的偶数。例如, 0.5 四舍五入为 0, 以及 1.5 四舍五入为 2.

    CStr 函数
    返回表达式,该表达式已被转换为 String 子类型的 Variant。
    CStr(expression)
    expression 参数是任意有效的表达式。
    说明
    通常,可以使用子类型转换函数书写代码,以显示某些操作的结果应被表示为特定的数据类型,而不是默认类型。例如,使用 CStr 强制将结果表示为 String。
    CStr 函数用于替代 Str 函数来进行从其他数据类型到 String 子类型的国际公认的格式转换。例如对十进制分隔符的识别取决于系统的区域设置。
    expression 根据下表决定返回的数据:

    如果 expression 为        CStr 返回          
    Boolean        字符串,包含 True 或 False。          
    Date        字符串,包含系统的短日期格式日期。          
    Null        运行时错误。          
    Empty        零长度字符串 ("")。          
    Error        字符串,包含跟随有错误号码的单词 Error。          
    其他数值        字符串,包含此数字。         
    下面的示例利用 CStr 函数把数字转换为 String:
    Dim MyDouble, MyString
    MyDouble = 437.324         ' MyDouble 是双精度值。
    MyString = CStr(MyDouble)  ' MyString 包含 "437.324"。

    LCase 函数
    返回字符串的小写形式。
    LCase(string)
    string 参数是任意有效的字符串表达式。如果 string 参数中包含 Null,则返回 Null。
    说明
    仅大写字母转换成小写字母;所有小写字母和非字母字符保持不变。

    下面的示例利用 LCase 函数把大写字母转换为小写字母:
    Dim MyString
    Dim LCaseString
    MyString = "VBscrīpt"
    LCaseString = LCase(MyString)   ' LCaseString 包含 "vbscrīpt"。
    UCase 函数
    返回字符串的大写形式。
    UCase(string)
    string 参数是任意有效的字符串表达式。如果 string 参数中包含 Null,则返回 Null。
    说明
    只有小写字母被转换成大写字母;所有大写字母和非字母字符均保持不变。
    下面的示例利用 UCase 函数返回字符串的大写形式:
    Dim MyWord
    MyWord = UCase("Hello World")   ' 返回"HELLO WORLD"。

    MsgBox 函数
    在对话框中显示消息,等待用户单击按钮,并返回一个值指示用户单击的按钮。
    MsgBox(prompt[, buttons][, title][, helpfile, context])
    参数
    prompt
    作为消息显示在对话框中的字符串表达式。prompt 的最大长度大约是 1024 个字符,这取决于所使用的字符的宽度。如果 prompt 中包含多个行,则可在各行之间用回车符 (Chr(13))、换行符 (Chr(10)) 或回车换行符的组合 (Chr(13) & Chr(10)) 分隔各行。
    Buttons
    数值表达式,是表示指定显示按钮的数目和类型、使用的图标样式,默认按钮的标识以及消息框样式的数值的总和。有关数值,请参阅“设置”部分。如果省略,则 buttons 的默认值为 0。
    Title
    显示在对话框标题栏中的字符串表达式。如果省略 title,则将应用程序的名称显示在标题栏中。
    Helpfile
    字符串表达式,用于标识为对话框提供上下文相关帮助的帮助文件。如果已提供 helpfile,则必须提供 context。在 16 位系统平台上不可用。
    Context
    数值表达式,用于标识由帮助文件的作者指定给某个帮助主题的上下文编号。如果已提供 context,则必须提供 helpfile。在 16 位系统平台上不可用。
    设置
    buttons 参数可以有以下值:

    常数        值        描述          
    vbOKOnly        0        只显示确定按钮。          
    vbOKCancel        1        显示确定和取消按钮。          
    vbAbortRetryIgnore        2        显示放弃、重试和忽略按钮。          
    vbYesNoCancel        3        显示是、否和取消按钮。          
    vbYesNo        4        显示是和否按钮。          
    vbRetryCancel        5        显示重试和取消按钮。          
    vbCritical        16        显示临界信息图标。          
    vbQuestion        32        显示警告查询图标。          
    vbExclamation        48        显示警告消息图标。          
    vbInformation        64        显示信息消息图标。          
    vbDefaultButton1        0        第一个按钮为默认按钮。          
    vbDefaultButton2        256        第二个按钮为默认按钮。          
    vbDefaultButton3        512        第三个按钮为默认按钮。          
    vbDefaultButton4        768        第四个按钮为默认按钮。          
    vbApplicationModal        0        应用程序模式:用户必须响应消息框才能继续在当前应用程序中工作。          
    vbSystemModal        4096        系统模式:在用户响应消息框前,所有应用程序都被挂起。         
    第一组值 (0 - 5) 用于描述对话框中显示的按钮类型与数目;第二组值 (16, 32, 48, 64) 用于描述图标的样式;第三组值 (0, 256, 512) 用于确定默认按钮;而第四组值 (0, 4096) 则决定消息框的样式。在将这些数字相加以生成 buttons 参数值时,只能从每组值中取用一个数字。
    返回值
    MsgBox 函数有以下返回值:

    常数        值        按钮          
    vbOK        1        确定          
    vbCancel        2        取消          
    vbAbort        3        放弃          
    vbRetry        4        重试          
    vbIgnore        5        忽略          
    vbYes        6        是          
    vbNo        7        否         
    说明
    如果同时提供了 helpfile 和 context,则用户可以按 F1 键以查看与上下文相对应的帮助主题。
    如果对话框显示取消按钮,则按 ESC 键与单击取消的效果相同。如果对话框包含帮助按钮,则有为对话框提供的上下文相关帮助。但是在单击其他按钮之前,不会返回任何值。
    当MicroSoft Internet Explorer使用MsgBox函数时,任何对话框的标题总是包含"VBscrīpt",以便于将其与标准对话框区别开来。
    下面的例子演示了 MsgBox 函数的用法:
    Dim MyVar
    MyVar = MsgBox ("Hello World!", 65, "MsgBox Example")
       ' MyVar 包含 1 或 2,这取决于单击的是哪个按钮。

  • DotNetFactory 应用

    2008-06-01 13:35:33

    DotNetFactory对象使我们能够在qtp环境下创建一个.Net的实例,并访问它的方法和属性。而且,我们还可以通过这个对象去访问类的一些静态方法。

    DotNetFactory的CreatInstance方法 语法:

    Set var_CreateInstance = DotNetFactory.CreateInstance (TypeName [,Assembly] [,args])

    1。 Send keys to Active Window  

    Syntax: object.SendKeys( keys, wait )

  • keys - A String that defines the keys to send.
  • wait - Optional. A Boolean that specifies whether or not to wait for keystrokes to get processed before the application continues. True by default.
  • Example:

    Set Keyboard = DotNetFactory.CreateInstance( "Microsoft.VisualBasic.Devices.Keyboard", "Microsoft.VisualBasic" )

    Call Keyboard.SendKeys( "22", True )

     

  • C# Training

    2008-06-01 13:35:33

    Database:

    1. User Session table: UserId, LoginAddress

     

    Server:

    AddUserSession(string userName, IPAddress: ipAddress);

    RemoveUserSession(string userName);

    string GetUserList();

    SendMessage(string receiver, string messageContent);

     

    Client:

    ReceiveMessage(string sender, string messageContent);

     

  • WR 技巧

    2008-06-01 13:35:33

    个人在使用过程中总结的一点小小经验和技巧,希望能够对大家有用!
    一、通配符
    ![内容].* (空格)
    如: !Form.* ,表示为“Form”+任何字符串
    !.* Form,表示为任何字符串+“Form”

    二、文件路径
    \\
    TSL 语言中,文件路径要用“\\”表示


    三、控件识别问题
    有时录制脚本时发现有的控件识别不了(比如WEB页面中的标准控件识别不了),
    可能由以下情况造成:
    1. 启动WinRunner时没有加载相应的Addin;
    2. WinRunner在应用程序之后启动;

    四、建立数据库检查点
    有的人发现建立数据库检查点时不能建立新的查询,觉得很奇怪,这是因为系统中没有安装Microsoft Query
    的缘故。
    Office 2000 中有Microsoft Query的安装,不过缺省是不安装Microsoft Query的,只要运行Office 2000
    的安装程序,在更改安装中将Microsoft Query设为从本机运行,确定安装即可。


    五、自动加载GUI Map文件

    static test_Path = getvar("testname"); # 得到测试用例的路径
    static guifile_path = test_Path & "\\GUI_File.gui";
    # GUI Map文件名,建议将GUI Map文件保存在测试脚本的目录中,如果不是,
    将这里改为相应的绝对路径或相对路径

    GUI_unload_all(); # 清空已经加载的GUI Map
    GUI_load(guifile_path); # 加载GUI Map文件

    report_msg(test_Path); # 报告路径,调试脚本时用,正式执行可以不要
  • WR TSL 2-19-2008

    2008-06-01 13:35:33

    Winrunner Context Sensitive命令列表




    1.ActiveBar_combo_select_item ( band_tool , item_name );选择下拉菜单某一项,例如:


    set_window("Form1", 1);


    ActiveBar_combo_select_item("Format;Font", "Arial");


    In the following example, WinRunner selects the third item in the Format:Font tool.


    set_window("Form1", 1);


    ActiveBar_combo_select_item("Format;Font", "#3");


    2.ActiveBar_dump ( file_name );存储活动工具栏信息,包括标题、名称、ID等。

    file_name            参数包括路径,例如:

    set_window("Form1", 1);

    ActiveBar_dump ("d:Bardump.txt");

    3、ActiveBar_select_menu ( band_tool [, events_only ] ) ;选择菜单某一项,例如:

    in the following example, WinRunner selects the Cut menu item in the Edit toolbar.

    set_window("Form1", 1);

    ActiveBar_select_menu ("Edit;Cut",TRUE);

    4、ActiveBar_select_tool (band_tool [, events_only ] ) ;选择工具栏里某一项,例如:

    set_window("Form1", 1);

    ActiveBar_select_tool("Format;Center", TRUE);

    5、win_check_bitmap ( window, bitmap, time [, x, y, width, height ] );比较窗口位图,

    6、obj_check_bitmap ( object, bitmap, time [, x, y, width, height] );比较对象位图,

    7、button_check_info ( button, property, property_value );检查按钮属性的值

    8、button_check_state ( button, state );检查单选框或复选框的状态

    9、button_get_info ( button, property, out_value );返回按钮属性的值

    10、button_get_state ( button, out_state );返回单选框或复选框的状态

    11、button_press ( button );点击按钮

    12、button_set ( button, state );设置单选框或复选框的状态

    13、button_wait_info ( button, property, value, time );等待按钮的属性值变化

    14、calendar_activate_date ( calendar, date );双击日历某个日期

    15、db_check ( checklist, expected_results_file [ , max_rows [ , parameter_array ] ] );比较当前数据库数据和期待的数据库数据

    16、db_connect ( session_name, connection_string );建立一个数据库session并建立odbc连接

    17、db_disconnect ( session_name );断开连接结束session

    18、db_execute_query ( session_name, SQL, record_number );执行sql语句返回记录集

    19、db_get_field_value ( session_name, row_index, column );返回数据库特定区域的值

    20、db_get_headers ( session_name, header_count, header_content );返回数据库session的列的数量及列的内容并以tab分组

    21、db_get_last_error ( session_name, error );返回最后一条数据库session错误信息

    22、db_get_row ( session_name, row_index, row_content );返回特定行内容

    23、db_record_check ( ChecklistFileName , SuccessConditions, RecordNumber ); Compares information that appears in the application under test during a test run with the current values in the corresponding record(s) in your database.

    24、db_write_records ( session_name, output_file [ , headers [ , record_limit ] ] );把结果记录集写到一个文本文件

    25、ddt_close ( data_table_name );关闭数据表文件

    26、ddt_close_all_tables();关闭全部数据表

    27、ddt_export ( data_table_namename1, data_table_namename2 );把一个数据表信息导到另一个数据表文件

    28、ddt_get_current_row ( data_table_name, out_row );返回数据表当前所在行

    29、ddt_get_parameters ( table, params_list, params_num );返回数据表的参数和参数的个数

    30、ddt_get_row_count ( data_table_name, out_rows_count );返回数据表行数

    31、ddt_is_parameter ( data_table_name, parameter );返回一个参数是否在数据表里有效

    32、ddt_next_row ( data_table_name );指向数据表中到当前行的下一行

    33、ddt_open ( data_table_name [ , mode ] );打开或创建一个可以访问的数据表

    34、ddt_report_row ( data_table_name );报告当前行到测试结果

    35、ddt_save ( data_table_name );保存数据表信息

    36、ddt_set_row ( data_table_name, row );设置当前行为第几行

    37、ddt_set_val ( data_table_name, parameter, value );插入parameter列一个新值value

    38、ddt_set_val_by_row ( data_table_name, row, parameter, value  );插入特定行的parameter列一个新值value

    39、ddt_show ( data_table_name [ , show_flag ] );显示或隐藏数据表,1是显示,0是隐藏

    40、ddt_sort ( table_file, row1, col1, row2, col2, sort_by_rows, key1 [ , key2, key3 ]  );根据关键字将数据表特定区域的值排序,sort_by_rows            参数1是按行,0是按列

    41、ddt_update_from_db ( data_table_name, file, out_row_count [ , max_rows ] );从数据库往数据表里导数据;

    42、ddt_val ( data_table_name, parameter );返回数据表当前行的参数的值

    43、ddt_val_by_row ( data_table_name, row_number, parameter );返回数据表特定行的参数的值

    44、date_age_string ( date, years, month, days, new_date );将日期相应改变返回新值

    45、date_align_day ( align_mode, day_in_week );指定特定的日期给某天

    46、date_calc_days_in_field ( field_name1, field_name2 );计算两个日期间的天数

    47、date_calc_days_in_string ( string1, string2 );计算字符串格式的日期间的天数

    48、edit_check_info ( edit, property, property_value );检查对象属性的值

    49、edit_check_selection ( edit, selected_string );检查选择的字符串是否存在

    50、edit_check_text (edit, text, case_sensitive );检查编辑对象的文本内容

    51、edit_delete ( edit, start_column, end_column );删除编辑对象的文本内容

    52、edit_delete_block ( edit, start_row, start_column, end_row, end_column );删除文本区

    53、edit_get_block ( edit, start_row, start_column, end_row, end_column, out_string );返回文本区

    54、edit_get_info ( edit, property, out_value );返回编辑对象的属性值

    55、edit_get_row_length ( edit, row, out_length );返回编辑对象里行的长度

    56、edit_get_rows_count ( edit, out_number );返回编辑对象里行数

    57、edit_get_selection ( edit, out_string );返回编辑对象的选定字符串

    58、edit_get_selection_pos ( edit, out_start_row, out_start_column, out_end_row, out_end_column );返回选定区域的开始和结束位置

    59、edit_get_text ( edit, out_string );返回编辑对象的文本

    60、edit_insert ( edit, text, columnI );在编辑对象第一行插入文本

    61、edit_insert_block ( edit, text, row, column );在一个多行编辑对象插入文本

    62、edit_replace ( edit, text, start_column, end_column );替换一个编辑对象的内容

    63、edit_replace_block ( edit, text, start_row, start_column, end_row, end_column );替换一个编辑对象的多行内容

    64、edit_set ( edit, text );替换编辑对象的全部内容

    65、edit_set_insert_pos ( edit, row, column );把鼠标指针放到编辑对象特定位置

    66、edit_set_selection ( edit, start_row, start_column, end_row, end_column );选择编辑对象的文本

    67、edit_type ( edit, text );在编辑对象敲入字符串

    68、edit_wait_info ( edit, property, value, time );等待编辑对象属性的值

    69、obj_check_gui ( object, checklist, expected_results_file, time );比较当前的gui对象数据

    70、win_check_gui ( window, checklist, expected_results_file, time );对一个窗口比较当前的gui对象数据

    71、get_class_map ( custom_class, out_standard_class );返回和一个自定义的类相关的标准类

    72、get_record_attr ( class, out_obligatory, out_optional, out_selector );从一个对象类返回属性

    73、get_record_method ( class, out_method );返回一个对象类的方法

    74、set_class_map ( custom_class, standard_class );关联一个自定义类和一个标准类

    75、set_record_attr ( class, oblig_prop, optional_prop, selector );设置一个对象类的属性

    76、set_record_method ( class, method );设置对一个类的记录方法

    77、unset_class_map ( custom_class );解开一个自定义类和标准类的关联关系

    78、GUI_add ( file path, window, object, physical_desc );往gui map文件里加一个对象

    79、GUI_buf_get_desc ( file, window, object, out_desc );返回guimap文件里对象的物理描述

    80、GUI_buf_get_desc_attr ( file, window, object, property, out_prop_value ); 返回guimap文件里对象的属性的值

    81、GUI_buf_get_logical_name ( file, physical_desc, window, out_name ); 返回guimap文件里对象的逻辑名称

    82、GUI_buf_new ( file );创建新的gui对象文件

    83、GUI_buf_set_desc_attr ( file, window, object, property, value );设置guimap文件里对象的属性的值

    84、GUI_close ( file );关闭guimap文件

    85、GUI_close_all ();关闭全部guimap文件

    86、GUI_delete ( file, window, obj  );从guimap文件里删除一个对象

    87、GUI_desc_compare ( desc_1, desc_2 );比较两个物理描述

    88、GUI_desc_get_attr ( physical_desc, property, out_attr_value );从物理描述得到属性的值

    89、GUI_desc_set_attr ( physical_desc, property, value );设置属性的值

    90、GUI_get_name ( out_name, out_version );返回测试程序下gui对象的类型

    91、GUI_get_window ( );在guimap里返回当前窗口

    92、GUI_list_buf_windows ( file, out_windows, out_number );列举出guimap文件里所有的窗口

    93、GUI_list_buffers ( out_files, out_number );列举所有打开的guimap文件

    94、GUI_list_desc_attrs ( physical_desc, out_array );列举一个gui对象的属性值

    95、GUI_list_map_buffers ( out_file, out_number );列举所有载入的guimap文件

    96、GUI_list_win_objects ( file, window, out_objects, out_number );列举一个窗口的全部对象

    97、GUI_load ( file_name );载入一个guimap文件

    98、GUI_map_get_desc ( window, object, out_desc, out_file );返回guimap里对象的物理描述

    99、GUI_map_get_logical_name ( physical_desc, window, out_obj, out_file );返回guimap里对象的逻辑名称

    100、GUI_open ( file_name );打开guimap文件
     
    101、GUI_save ( file_name );保存guimap文件

    102、GUI_save_as ( current_file_name, new_file_name );另存为guimap文件

    103、GUI_set_window ( window_name );设置guimap里目标识别范围

    104、GUI_unload ( file );卸载guimap文件

    105、GUI_unload_all ( )卸载全部的guimap文件

    106、icon_move ( icon, x, y );移动图标到新位置

    107、icon_select ( icon );点击鼠标选择图标

    108、java_activate_method( object, method, retval [ , param1, ... param8 ] );调用请求的java方法

    109、java_fire_event ( object , class [ , constructor_param1,..., constructor_paramX ] );模拟一个java对象的事件

    110、jco_create ( object , jco , class [ , constructor_param1 , ... , constructor_param8 ] )创建一个现有java对象的上下文java对象

    111、jco_free ( object_name );释放内存里指定的jco对象

    112、jco_free_all();释放全部内存里的jco对象

    113、jdc_aut_connect ( in_timeout );建立一个winrunner和java应用程序的连接

    114、method_wizard ( [ object ] );打开java方法的向导

    115、obj_key_type ( object, keyboard_input );向java组件发送事件

    116、obj_set_info ( object, property, value );设置对象属性的值

    117、popup_select_item ( "menu component;menu item" );从java活动菜单选择一个选项

    118、list_activate_item ( list, item [, offset ] );激活列表里某一项

    119、list_check_info ( list, property, property_value );检查列表属性的值

    120、list_check_item ( list, item_num, item_content );检查列表某项的内容

    121、list_check_selected ( list, selected_items );检查选中的那项

    122、list_collapse_item ( list, item [, mouse_button ] );隐藏树型图里的选项

    123、list_deselect_item ( list, item [, mouse_button  [, offset ]] );取消选定列表的某一项

    124、list_deselect_range ( list, item1, item2 [, offset ] );取消选定2个选项

    125、list_drag_item ( source_list, item [, mouse_button ] );拖动源列表的某个选项

    126、list_drop_on_item ( target_list, target_item );把一个对象关联到目标列表的选项

    127、list_expand_item ( list, item [, mouse_button ] );显示隐藏的树型图选项

    128、list_extend_item ( list, item [, button  [, offset ] ] );往指定的列表里添加一个选项

    129、list_extend_multi_items ( list, item_list, [, mouse_button  [, offset ] ] );添加多个选项

    130、list_extend_range ( list, item1, item2 [, button  [, offset ] ] );添加一定范围的选项

    131、list_get_checked_items ( list, items, number );返回标记的选项的个数和值

    132、list_get_info ( list, property, out_value );返回列表属性的值

    133、list_get_item ( list, item_num, out_value );返回列表选项的内容

    134、list_get_item_coord ( list, item, out_x, out_y, out_width, out_height );返回列表选项的四个坐标

    135、list_get_item_info ( list, item, state, out_value );返回列表选项的状态

    136、list_get_item_num ( list, item, out_num );返回列表选项的位置

    137、list_get_selected ( list, out_item, out_num );返回列表里选定选项的数字和字符串值

    138、list_select_item ( list, item [,button  [, offset ] ]);选择一个列表选项

    139、list_select_multi_items ( list, item_list [, mouse_button  [, offset ] ] );选择一个列表的多个选项

    140、list_select_range ( list, item1, item2 [, button  [, offset ] ]);选定一定范围内全部选项

    141、list_wait_info ( list, property, value, time );等待列表属性的值

    142、menu_get_desc ( menu, oblig, optional, selector, out_desc );返回菜单的物理描述

    143、menu_get_info ( menu, property, out_value );返回菜单属性的值

    144、menu_get_item ( menu, item_number, out_contents );返回菜单选项的内容

    145、menu_get_item_num ( menu, item, out_position );返回菜单选项的位置

    146、menu_select_item ( menu;item [ x,y ] );选择一个菜单选项

    147、menu_wait_info ( menu, property, value, time );等待菜单属性的值

    148、obj_check_bitmap ( object, bitmap, time [, x, y, width, height] );比较对象的位图

    149、obj_check_gui ( object, checklist, expected_results_file, time );比较当前的gui对象数据

    150、obj_check_info ( object, property, property_value [, timeout ] );检查gui对象属性的值

    151、obj_click_on_text ( object, string [ ,search_area  [ , string_def  [ , mouse_button ] ] ] );在对象里点击文本

    152、obj_drag ( source_object, x, y [, mouse_button ] );从源对象拖动一个对象

    153、obj_drop ( target_object, x, y );拖动一个对象到目标对象

    154、obj_exists ( object [, time ] );检查对象是否显示在屏幕上

    155、obj_find_text ( object, string, result_array [, search_area  [, string_def ] ] );在对象里返回字符串的位置

    156、obj_get_desc ( object, oblig, optional, selector, out_desc );返回对象的物理描述

    157、obj_get_info ( object, property, out_value );返回对象属性的值

    158、obj_get_text ( object, out_text [, x1, y1, x2, y2 ] );读取对象的文本

    159、obj_highlight ( object [, flashes ] );高亮显示对象

    160、obj_mouse_click ( object, x, y [, mouse_button ] );点击一个对象

    161、obj_mouse_dbl_click ( object, x, y [, mouse_button ] );双击一个对象

    162、obj_mouse_drag ( object, start_x, start_y, end_x, end_y [,mouse_button ] );在对象上拖动鼠标

    163、obj_mouse_move ( object, x, y );在对象里移动鼠标指针

    164、obj_move_locator_text ( object, string [ , search_area  [ , string_def ] ] );在对象里移动鼠标到一个字符串

    165、obj_type ( object, keyboard_input );用键盘输入对象

    166、obj_wait_bitmap ( object, bitmap, time [, x, y, width, height] );等待对象位图出现在屏幕

    167、obj_wait_info ( object, property, value, time );等待对象属性的值

    168、scroll_check_info ( scroll, property, property_value );检查滚动条的属性值

    169、scroll_check_pos ( scroll, position );检查滚动条的当前位置

    170、scroll_drag ( scroll, orientation, position );滚动到指定位置

    171、scroll_drag_from_min ( scroll, orientation, position );从最小值开始滚动

    172、scroll_get_info ( scroll, property, out_value );返回滚动条的属性值

    173、scroll_get_max ( scroll, orientation, out_max );返回滚动条的最大位置

    174、scroll_get_min ( scroll, orientation, out_min );返回滚动条的最小位置

    175、scroll_get_selected ( slider, min_value, max_value );返回滚动条的最小和最大值

    176、scroll_get_pos ( scroll, orientation, out_pos );返回滚动条当前位置

    177、scroll_line ( scroll, orientation, [ +|- ] lines );滚动指定的几行

    178、scroll_max ( scroll, orientation );设置滚动条到最大位置

    179、scroll_min ( scroll, orientation );设置滚动条到最小位置

    180、scroll_page ( scroll, orientation, [+|-] pages );移动滚动条指定的页数

    181、scroll_wait_info ( scroll, property, value, time );等待滚动条属性的值

    182、spin_get_info ( spin, property, out_value );返回旋转属性的值

    183、spin_get_pos ( spin, out_value );返回旋转对象的位置

    184、spin_get_range ( spin, out_min_pos, out_max_pos );返回旋转对象的最小与最大位置

    185、spin_max ( spin [, index ] );设置旋转对象到最大值

    186、spin_min ( spin [, index ] );设置旋转对象到最小值

    187、spin_next ( spin [, index ] );设置旋转对象到下一个值

    188、spin_prev ( spin [, index ] ); 设置旋转对象到前一个值

    189、spin_set ( spin, item [, index ] );设置选择对象到一个选项值

    190、spin_wait_info ( spin, property, value, time );等待旋转属性等于指定的值

    191、static_check_info ( static, property, property_value );检查静态文本对象属性的值

    192、static_check_text ( static, text, case_sensitive );检查静态文本对象的内容

    193、static_get_info ( static, property, out_value );返回静态文本对象属性的值

    194、static_get_text ( static, out_string );返回静态文本对象的内容

    195、static_wait_info ( static, property, value, time );等待静态文本对象的属性值

    196、statusbar_get_field_num ( statusbar, field, field_index );返回状态栏区域的数字索引

    197、statusbar_get_info ( statusbar, property, out_value );返回状态栏的属性值

    198、statusbar_get_text ( statusbar, field_index, out_text );读取状态栏区域的文本

    199、statusbar_wait_info ( statusbar, property, value, time );等待状态栏属性的值

    200、tab_get_info ( tab, property, out_value );返回tab属性的值
     
    101、GUI_save ( file_name );保存guimap文件

    102、GUI_save_as ( current_file_name, new_file_name );另存为guimap文件

    103、GUI_set_window ( window_name );设置guimap里目标识别范围

    104、GUI_unload ( file );卸载guimap文件

    105、GUI_unload_all ( )卸载全部的guimap文件

    106、icon_move ( icon, x, y );移动图标到新位置

    107、icon_select ( icon );点击鼠标选择图标

    108、java_activate_method( object, method, retval [ , param1, ... param8 ] );调用请求的java方法

    109、java_fire_event ( object , class [ , constructor_param1,..., constructor_paramX ] );模拟一个java对象的事件

    110、jco_create ( object , jco , class [ , constructor_param1 , ... , constructor_param8 ] )创建一个现有java对象的上下文java对象

    111、jco_free ( object_name );释放内存里指定的jco对象

    112、jco_free_all();释放全部内存里的jco对象

    113、jdc_aut_connect ( in_timeout );建立一个winrunner和java应用程序的连接

    114、method_wizard ( [ object ] );打开java方法的向导

    115、obj_key_type ( object, keyboard_input );向java组件发送事件

    116、obj_set_info ( object, property, value );设置对象属性的值

    117、popup_select_item ( "menu component;menu item" );从java活动菜单选择一个选项

    118、list_activate_item ( list, item [, offset ] );激活列表里某一项

    119、list_check_info ( list, property, property_value );检查列表属性的值

    120、list_check_item ( list, item_num, item_content );检查列表某项的内容

    121、list_check_selected ( list, selected_items );检查选中的那项

    122、list_collapse_item ( list, item [, mouse_button ] );隐藏树型图里的选项

    123、list_deselect_item ( list, item [, mouse_button  [, offset ]] );取消选定列表的某一项

    124、list_deselect_range ( list, item1, item2 [, offset ] );取消选定2个选项

    125、list_drag_item ( source_list, item [, mouse_button ] );拖动源列表的某个选项

    126、list_drop_on_item ( target_list, target_item );把一个对象关联到目标列表的选项

    127、list_expand_item ( list, item [, mouse_button ] );显示隐藏的树型图选项

    128、list_extend_item ( list, item [, button  [, offset ] ] );往指定的列表里添加一个选项

    129、list_extend_multi_items ( list, item_list, [, mouse_button  [, offset ] ] );添加多个选项

    130、list_extend_range ( list, item1, item2 [, button  [, offset ] ] );添加一定范围的选项

    131、list_get_checked_items ( list, items, number );返回标记的选项的个数和值

    132、list_get_info ( list, property, out_value );返回列表属性的值

    133、list_get_item ( list, item_num, out_value );返回列表选项的内容

    134、list_get_item_coord ( list, item, out_x, out_y, out_width, out_height );返回列表选项的四个坐标

    135、list_get_item_info ( list, item, state, out_value );返回列表选项的状态

    136、list_get_item_num ( list, item, out_num );返回列表选项的位置

    137、list_get_selected ( list, out_item, out_num );返回列表里选定选项的数字和字符串值

    138、list_select_item ( list, item [,button  [, offset ] ]);选择一个列表选项

    139、list_select_multi_items ( list, item_list [, mouse_button  [, offset ] ] );选择一个列表的多个选项

    140、list_select_range ( list, item1, item2 [, button  [, offset ] ]);选定一定范围内全部选项

    141、list_wait_info ( list, property, value, time );等待列表属性的值

    142、menu_get_desc ( menu, oblig, optional, selector, out_desc );返回菜单的物理描述

    143、menu_get_info ( menu, property, out_value );返回菜单属性的值

    144、menu_get_item ( menu, item_number, out_contents );返回菜单选项的内容

    145、menu_get_item_num ( menu, item, out_position );返回菜单选项的位置

    146、menu_select_item ( menu;item [ x,y ] );选择一个菜单选项

    147、menu_wait_info ( menu, property, value, time );等待菜单属性的值

    148、obj_check_bitmap ( object, bitmap, time [, x, y, width, height] );比较对象的位图

    149、obj_check_gui ( object, checklist, expected_results_file, time );比较当前的gui对象数据

    150、obj_check_info ( object, property, property_value [, timeout ] );检查gui对象属性的值

    151、obj_click_on_text ( object, string [ ,search_area  [ , string_def  [ , mouse_button ] ] ] );在对象里点击文本

    152、obj_drag ( source_object, x, y [, mouse_button ] );从源对象拖动一个对象

    153、obj_drop ( target_object, x, y );拖动一个对象到目标对象

    154、obj_exists ( object [, time ] );检查对象是否显示在屏幕上

    155、obj_find_text ( object, string, result_array [, search_area  [, string_def ] ] );在对象里返回字符串的位置

    156、obj_get_desc ( object, oblig, optional, selector, out_desc );返回对象的物理描述

    157、obj_get_info ( object, property, out_value );返回对象属性的值

    158、obj_get_text ( object, out_text [, x1, y1, x2, y2 ] );读取对象的文本

    159、obj_highlight ( object [, flashes ] );高亮显示对象

    160、obj_mouse_click ( object, x, y [, mouse_button ] );点击一个对象

    161、obj_mouse_dbl_click ( object, x, y [, mouse_button ] );双击一个对象

    162、obj_mouse_drag ( object, start_x, start_y, end_x, end_y [,mouse_button ] );在对象上拖动鼠标

    163、obj_mouse_move ( object, x, y );在对象里移动鼠标指针

    164、obj_move_locator_text ( object, string [ , search_area  [ , string_def ] ] );在对象里移动鼠标到一个字符串

    165、obj_type ( object, keyboard_input );用键盘输入对象

    166、obj_wait_bitmap ( object, bitmap, time [, x, y, width, height] );等待对象位图出现在屏幕

    167、obj_wait_info ( object, property, value, time );等待对象属性的值

    168、scroll_check_info ( scroll, property, property_value );检查滚动条的属性值

    169、scroll_check_pos ( scroll, position );检查滚动条的当前位置

    170、scroll_drag ( scroll, orientation, position );滚动到指定位置

    171、scroll_drag_from_min ( scroll, orientation, position );从最小值开始滚动

    172、scroll_get_info ( scroll, property, out_value );返回滚动条的属性值

    173、scroll_get_max ( scroll, orientation, out_max );返回滚动条的最大位置

    174、scroll_get_min ( scroll, orientation, out_min );返回滚动条的最小位置

    175、scroll_get_selected ( slider, min_value, max_value );返回滚动条的最小和最大值

    176、scroll_get_pos ( scroll, orientation, out_pos );返回滚动条当前位置

    177、scroll_line ( scroll, orientation, [ +|- ] lines );滚动指定的几行

    178、scroll_max ( scroll, orientation );设置滚动条到最大位置

    179、scroll_min ( scroll, orientation );设置滚动条到最小位置

    180、scroll_page ( scroll, orientation, [+|-] pages );移动滚动条指定的页数

    181、scroll_wait_info ( scroll, property, value, time );等待滚动条属性的值

    182、spin_get_info ( spin, property, out_value );返回旋转属性的值

    183、spin_get_pos ( spin, out_value );返回旋转对象的位置

    184、spin_get_range ( spin, out_min_pos, out_max_pos );返回旋转对象的最小与最大位置

    185、spin_max ( spin [, index ] );设置旋转对象到最大值

    186、spin_min ( spin [, index ] );设置旋转对象到最小值

    187、spin_next ( spin [, index ] );设置旋转对象到下一个值

    188、spin_prev ( spin [, index ] ); 设置旋转对象到前一个值

    189、spin_set ( spin, item [, index ] );设置选择对象到一个选项值

    190、spin_wait_info ( spin, property, value, time );等待旋转属性等于指定的值

    191、static_check_info ( static, property, property_value );检查静态文本对象属性的值

    192、static_check_text ( static, text, case_sensitive );检查静态文本对象的内容

    193、static_get_info ( static, property, out_value );返回静态文本对象属性的值

    194、static_get_text ( static, out_string );返回静态文本对象的内容

    195、static_wait_info ( static, property, value, time );等待静态文本对象的属性值

    196、statusbar_get_field_num ( statusbar, field, field_index );返回状态栏区域的数字索引

    197、statusbar_get_info ( statusbar, property, out_value );返回状态栏的属性值

    198、statusbar_get_text ( statusbar, field_index, out_text );读取状态栏区域的文本

    199、statusbar_wait_info ( statusbar, property, value, time );等待状态栏属性的值

    200、tab_get_info ( tab, property, out_value );返回tab属性的值
     
    201、tab_get_item ( tab, item_num, out_item );返回tab选项的名称

    202、tab_get_selected ( tab, out_item, out_num );返回选定的tab选项的名称和个数

    203、tab_select_item ( tab, item );选择tab选项

    204、tab_wait_info ( tab, property, value, time );等待tab属性的值

    205、tbl_activate_cell ( table, row, column );双击表里某个单元

    206、tbl_activate_col ( table, column );双击表里某列

    207、tbl_activate_header ( table, column );双击表里某列标题

    208、tbl_activate_row ( table, row );双击表里某行

    209、tbl_deselect_col ( table, column );取消选择表的某列

    210、tbl_deselect_cols_range ( table, from_column, to_column );取消选择表里某几列

    211、tbl_deselect_row ( table, row );取消选择表里某行

    212、tbl_deselect_rows_range ( table, from_row, to_row );取消选择表里某几行

    213、tbl_extend_col ( table, column );往表里当前列加一列

    214、tbl_extend_cols_range ( table, from_column, to_column );往表里当前列加多列

    215、tbl_extend_row ( table, row );往表里当前行前加一行

    216、tbl_extend_rows_range ( table, from_row, to_row );往表里当前行加多行

    217、tbl_get_cell_data ( table, row, column, out_text );返回表里指定单元的内容

    218、tbl_get_cols_count ( table, out_cols_count );返回表的列数

    219、tbl_get_column_name ( table, col_index, out_col_name );返回表里指定列的标题名称

    220、tbl_get_column_names ( table, out_col_names, out_cols_count );返回表里列的名称和个数

    221、tbl_get_rows_count ( table, out_rows_count );返回表的行数

    222、tbl_get_selected_cell ( table, out_row, out_column );返回表里焦点所在单元

    223、tbl_get_selected_row ( table, row );返回当前焦点所在行

    224、tbl_select_cells_range ( table, start_row, start_col, end_row, end_col );在表里点击选定的几个单元

    225、tbl_select_col_header ( table, column );选定指定的列的标题

    226、tbl_select_cols_range ( table, from_column, to_column );在表里选定指定的几列

    227、tbl_select_rows_range ( table, from_row, to_row );在表里选定指定的几行

    228、tbl_set_cell_data ( table, row, column, data );设置表里某单元的内容

    229、tbl_set_cell_focus ( table, row, column );设置表里焦点到某个单元

    230、tbl_set_selected_cell ( table, row, column );在表里选定指定的单元

    231、tbl_set_selected_col ( table, column );在表里选定指定的列

    232、tbl_set_selected_row ( table, row );在表里选定指定的行

    233、obj_click_on_text ( object, string [ ,search_area  [ , string_def  [ , mouse_button ] ] ] );点击一个对象的文本

    234、obj_find_text ( object, string, result_array [, search_area  [, string_def ] ] );返回一个对象字符串的位置

    235、obj_get_text ( object, out_text [, x1, y1, x2, y2 ] );从对象里读取文本

    236、obj_move_locator_text ( object, string [ , search_area  [ , string_def ] ] );在对象里把鼠标焦点落在字符串

    237、win_find_text ( window, string, result_array [, search_area [, string_def ] ] );在一个窗口返回字符串位置

    238、win_click_on_text (window, string [ ,search_area  [ , string_def  [ , mouse_button ] ] ] );在窗口搜索文本

    239、win_get_text ( window, out_text [, x1, y1, x2, y2] );从窗口指定的区域读取文本

    240、win_move_locator_text ( window, string [ ,search_area  [ ,string_def ] ] );在窗口里把鼠标焦点落在字符串

    241、toolbar_button_press ( toolbar, button, mouse_button );点击工具栏按钮

    242、toolbar_get_button ( toolbar, button_num, out_text  );返回工具栏按钮名称

    243、toolbar_get_button_info ( toolbar, button, property, out_value );返回工具栏按钮属性值

    244、toolbar_get_button_num ( toolbar, button, out_num );返回工具栏按钮位置

    245、toolbar_get_buttons_count ( toolbar, out_num );返回工具栏按钮的个数

    246、toolbar_select_item ( toolbar, toolbar_item_chain [, mouse_button ] );选择类菜单工具栏的某项

    247、web_browser_invoke ( browser, site );调用ie打开某个站点

    248、web_cursor_to_image ( image, x, y );移动鼠标指针到某个图片

    249、web_cursor_to_label ( label, x, y );移动鼠标指针到某个标签

    250、web_cursor_to_link ( link, x, y );移动鼠标指针到某个链接

    251、web_cursor_to_obj ( object, x, y );移动鼠标指针到某个对象

    252、web_event ( object, event_name [, x , y ] );在指定对象运行一个事件

    253、web_file_browse ( object );点击浏览按钮

    254、web_file_set ( object, value );在文件类型的对象设置文本值

    255、web_find_text ( frame, text_to_find, result_array [, text_before, text_after, index, show ] );返回帧内文本位置

    256、web_frame_get_text ( frame, out_text [, text_before, text_after, index ] );返回帧内文本的内容

    257、web_frame_get_text_count ( frame, regex_text_to_find, count );返回帧内标准表达式的事件个数

    258、web_frame_text_exists ( frame, text_to_find [, text_before, text_after ] );检查帧内指定的文本字符串是否存在

    259、web_get_run_event_mode ( out_mode );返回当前的运行模式

    260、web_get_timeout ( out_timeout );返回winrunner响应web的最大等待时间

    261、web_image_click ( image, x, y );点击一个图片链接或图片

    262、web_label_click ( label );点击指定的标签

    263、web_link_click ( link );点击朝文本链接

    264、web_link_valid ( name, valid );检查url链接是否有效

    265、web_obj_get_child_item ( object, table_row, table_column, object_type, index, out_object );返回对象的子对象的物理描述

    266、web_obj_get_child_item_count ( object, table_row, table_column, object_type, object_count );返回对象的子对象的个数

    267、web_obj_get_info ( object, property_name, property_value );返回对象属性的值

    268、web_obj_get_text ( object, table_row, table_column, out_text [, text_before, text_after, index] );返回对象的文本字符串

    269、web_obj_get_text_count ( object, table_row, table_column, regex_text_to_find, count ); 返回对象内标准表达式的事件个数

    270、web_obj_text_exists ( object, table_row, table_column, text_to_find [, text_before, text_after] );在对象里如果该文本存在,返回该文本

    271、web_refresh ( frame );winrunner重新连接指定的帧

    272、web_restore_event_default ( );重新设置全部事件为默认值

    273、web_set_event ( class, event_name, event_type, event_status );设置事件状态

    274、web_set_run_event_mode ( mode );设置事件运行模式

    275、web_set_timeout ( timeout );设置winrunner响应web的最大时间

    276、web_set_tooltip_color ( fg_color, bg_color );设置webtest工具条的颜色

    277、web_sync ( timeout );等待帧的导航完成

    278、web_tbl_get_cell_data ( table, row, column, starting_pos, out_text, out_actual_text_length );返回web表内指定单元的内容,开始于指定的字符

    279、web_url_valid ( URL, valid );检查url是否有效

    280、tbl_get_cell_data ( table, row, column, out_text );返回table里指定单元的内容(加载webtest)

    281、tbl_get_cols_count ( table, out_cols_count );返回表的列数(加载webtest)

    282、tbl_get_column_name ( table, col_index, out_col_name );返回表里指定列的标题的名称(加载webtest)

    283、tbl_get_rows_count ( table, out_rows_count );返回表的行数(加载webtest)

    284、web_password_encrypt ( password );将web页面的密码加密

    285、set_window ( window [,time] );激活窗口并确定等待时间

    286、win_activate ( window );激活窗口

    287、win_check_bitmap ( window, bitmap, time [, x, y, width, height ] );比较窗口的位图

    288、win_check_gui ( window, checklist, expected_results_file, time );比较窗口的gui数据

    289、win_check_info ( window, property, property_value [, timeout ] );检查被请求的窗口属性

    290、win_click_help ( window );在窗口点击帮助按钮

    291、win_click_on_text (window, string [ ,search_area  [ , string_def  [ , mouse_button ] ] ] );在窗口搜索文本

    292、win_close ( window );关闭窗口

    293、win_drag (source_window, x, y [, mouse_button ] );从源窗口拖动对象

    294、win_drop ( target_window, x, y  );拖动对象到目标窗口

    295、win_exists ( window [, time ] );检查窗口是否显示在屏幕上

    296、win_find_text ( window, string, result_array [, search_area [, string_def ] ] );返回窗口里字符串的位置

    297、win_get_desc ( window, obligatory, optional, selector, out_desc );返回窗口的物理描述

    298、win_get_info ( window, property, out_value );返回窗口属性的值

    299、win_get_text ( window, out_text [, x1, y1, x2, y2] );从窗口指定区域读取文本

    300、win_highlight ( window [, flashes ] );高亮显示窗口
     
    301、win_max ( window );最大化窗口到全屏

    302、最小化窗口为一个图标

    303、win_mouse_click ( window, x, y [, mouse_button  [, modifier] ] );在窗口点击鼠标

    304、win_mouse_dbl_click ( window, x, y [, mouse_button  [, modifier ] ] );在窗口双击鼠标

    305、win_mouse_drag ( window, start_x, start_y, end_x, end_y [, mouse_button ] );在窗口做鼠标拖动操作

    306、win_mouse_move ( window, x, y );移动鼠标焦点到指定的位置

    307、win_move ( window, x, y );移动窗口到一个绝对位置

    308、win_move_locator_text ( window, string [ ,search_area  [ ,string_def ] ] );移动鼠标焦点到窗口的某个字符串

    309、win_open ( window );打开应用程序窗口

    310、win_resize ( window, width, height );调整窗口大小

    311、win_restore ( window );恢复窗口从前的大小

    312、win_type ( window, keyboard_input );用键盘输入窗口

    313、win_wait_bitmap ( window, bitmap, time [, x, y, width, height] );等待窗口位图

    314、win_wait_info ( window, property, value, time );等待窗口属性值

    315、atan2 ( y, x );返回y/x(正切)的弧度

    316、cos ( x );返回余弦值

    317、exp ( x );返回e的指数值

    318、int ( x );返回实数的整数部分

    319、log ( x );返回自然对数

    320、sin ( x );返回正弦值

    321、sqrt ( x );返回平方根值

    322、delete array [ subscrīpt ];删除数组里某个元素

    323、split ( string, array [ , field_separators ] );将输入分成区域保存在数组里

    324、call test_name ( [ parameter1, parameter2, ... parametern ] );调用其他测试脚本

    325、call_chain_get_attr ( property, level, out_value );返回调用链里测试或函数的信息

    326、call_chain_get_depth ( );返回调用链选项的个数

    327、call_close test_name ( [ parameter1, parameter2, ... parametern ] );调用测试脚本,完成时关闭测试

    328、call_ex ( Astra_test_path );从winrunner里调用Astra QuickTest测试

    329、return [ expression ];返回测试或函数的结果表达式

    330、texit ( [ expression ] );停止执行当前的测试

    331、treturn [ ( expression ) ];停止调用测试返回控制调用测试

    332、load ( module_name [,1/0 [,1/0 ] ] );载入一个编译过的模块

    333、reload ( module_name [,1|0 [,1|0] ]);删除编译过的模块并重新载入内存

    334、unload ( [ module | test [ , function_name ] ] );从内存里删除编译模块

    335、define_object_exception (recovery_scenario_name, function, window, object, property  [ , value ] );对一个gui对象异常事件定义简单的观察场景

    336、define_popup_exception (recovery_scenario_name, function, window );对pop-up事件定义异常

    337、define_tsl_exception (recovery_scenario_name, return_code [, TSL_function ] );定义tsl事件异常事件

    338、exception_off ( recovery_scenario_name );解除指定的观察场景

    339、exception_off_all ( );解除所有的观察场景

    340、exception_on (recovery_scenario_name );激活指定的观察场景

    341、file_close ( file_name );关闭用file-open打开的文件

    342、file_compare ( file1, file2 [ , save_file ] );比较两个文件的内容

    343、file_getline ( file_name, out_line );读取文件下一行,并将其分配给一个变量

    344、file_open ( file_name, mode );打开或创建指定的文件

    345、file_printf ( file_name, format, exp1 [ , exp2,... exp30 ] );按格式打印文件

    346、pause ( [ expression ] );暂停测试执行并输出提示信息

    347、report_msg ( message );往测试报告里写信息

    348、sprintf ( format, exp1, exp2,...expn );返回固定格式字符串到一个变量

    349、str_map_logical_to_visual ( logical_string, visual_string );把逻辑字符串转换成形象字符串

    350、eval ( statement1 [; statement2;.... statementn;] );评估并执行附属的tsl语句

    351、get_unique_filename ( folder_path , file_prefix  , file_extension  , out_filename  , with_underscore );基于指定的前缀,创建唯一的文件名

    352、nargs ( );返回参数通过的个数

    353、tl_step ( step_name, status, descrīption );把测试脚本分成几块,并在当前测试结果里插入状态信息

    354、invoke_application ( file, command_option, working_dir, show );调用windows应用程序

    355、dos_system ( expression );执行dos命令

    356、ascii ( string );返回字符串第一个字符的asc码

    357、compare_text ( str1, str2 [, chars1, chars2 ] );比较两个字符串

    358、index ( string1, string2 );显示两个字符串位置

    359、length ( string );计算字符串里字符的个数

    360、match ( string, regular_expression );寻找字符串里正规表达式的事件

    361、substr ( string, position [, length ] );从字符串里提取子字符串

    362、tolower ( string );转换全部大写字母到小写字母

    363、toupper ( string ); 转换全部小写字母到大写字母

    364、end_transaction ( transaction [ , status ] );标记一个性能分析的结束

    365、get_time ( );返回当前系统时间

    366、start_transaction ( transaction_name ); 标记一个性能分析的开始

    367、time_str ( [ expression ] );将返回的整数时间转换成字符串

    368、wait ( seconds [, milliseconds] );测试暂停


    invoke_application(file,command_option,working_dir,show);


    file:应用程序的文件名,绝对路径;


    command_option:应用程序的参数;


    working_dir:应用程序工作路径;


    show:程序运行时的显示模式;



    数据库检查点:标准检查点和运行时检查点


    标准检查点检查行数、列数、内容是否一致;包括defaultcheck仅检查数据库内容是否一致;custom check 可随意组合上面三种方式检查


    运行时检查点检查程序界面上某些控件显示的内容是否在数据库中匹配记录,三种方式:匹配一条、匹配多条、没有匹配记录
  • Bug Report 2-18-2008

    2008-06-01 13:35:33

    你有没有为了要更多的信息而被返回 bug report 的经历呢?有没有碰到过你发现的一个非常严重的错误被推迟到下一个版本才去修复的情况呢?
    你提交的每一个 bug report 都是和项目组就正在测试中的软件质量问题的一种书面沟通方式。通常,你用于沟通程序错误的能力-不是体现在错误本身的内在严重程度-而是体现在确定这个错误是否需要修复。
    如果这是一个可怕的想法,你可能会想, “ 等等!我讨厌写作,我并不擅长写作。怎么样才能够通过编写 bug report 来决定错误的命运呢? ” 它要吸引大家相信错误是为他们说话的-任何一个头脑正常的人都应该主动地查看一个特定的错误是足够可怕的以致要被修复。不幸的是,事实并不是这样。
    但是好消息是:有效的和软件开发人员、项目组沟通的能力不是由你在高校英语课程中的表现所决定的。
    这不是关于用有趣的词语编写流畅散文,也不是关于优秀语法和拼写的方法。它是有关仅用能够表达你观点的词语明白地表述错误的方法。太多地话将会使你的观点陷入茫然无措中。太少地话又会使他人用自己的假设去填补隔阂-通常是对软件有害的部分。如果你不是很确信是什么样的错误,那么不管你的 bug report 写得怎么好,也没有人知道那是什么样的错误。
    这篇文章主要讨论你现在能够开始着手提高人们倾听你发现的错误的机会的 4 个方法。
    •        了解你的听众
    毋庸置疑,任何写作课都会告诉你必须了解你是为谁编写 bug report 。
    每份 bug report 至少有两个听众:必须要修复错误的人和决定错误命运的人或团体。有时一个人会同时负责这两份工作,但是仍然是两个不同的听众,只是一起发生在同一个人身上罢了。
    你的第一个听众-那个必须修复错误的人需要清楚,明确的步骤以重现错误。信息越多越好。针对这个目的,我们称这个人为 “ 开发人员 ” 。开发人员需要关于我们操作了什么和我们看见了什么的准确信息。
    你的第二个听众-决定错误命运的人或团体需要知道如果不修复此错误的后果。这个听众需要精练的语句以抓住他们的注意力并且引发对错误的相关连问题的讨论。基于这个目的,我们称他为 “ 错误审核委员会 ” 。在使错误得以修复的过程中你的角色是帮助错误审核委员会了解不修复错误的风险远远超过修复错误可能发生的风险。
    你越了解你的开发人员和错误审核委员会如何工作,你就越可以根据他们的需要裁减你的 bug report 。尽力在私底下设法了解你的听众。如果你能够出席错误审核委员会会议,尝试这样做。你将学习到许多关于你的听众是如何思考的知识。
    •        选择一个好的标题
    一般把用于描述错误的短句称为错误的标题或描述。这是 bug report 中最重要的部分。错误审核委员会成员经常通过它来决定错误是否可以推迟修复。如果标题没有力度,委员会成员可能认为它是不值得花费太多的时间。(毕竟,在接下来的 2 个小时里还有 145 个以上的错误要审核。)


    以下是一些示例:
    好的 : 超时后在退出时崩溃了
    太长的 : 在数据库不可用后你又保存记录的更改 , 然后从文件菜单中选择退出时程序崩溃了
    不足够的信息 : 程序崩溃了
    太模糊 : 当数据库离线时出现问题
    标题变成了一种给项目组提供检查和调查错误的方法。和数据相比,人们更容易记词语。人们更愿意记得 “ 在 windows2000 下不能够安装 ” 的错误,而不是类似 “ # 23423” 错误,而且在以后人们还会利用这些关键词搜索错误。
    编写一个好的,简明的错误标题是不容易的。和编写 bug report 的其他部分相比,应该多花些时间构造理想的错误标题。要确信标题是足够短以便能够在显示错误的屏幕上和由缺陷跟踪系统生成的报表中显示完全(不会折行)。标题不必是完美的语法,而应简短并一针见血。
    •        书写清楚,明确的步骤
    你提交给开发人员的步骤应该提供如何产生错误的信息,这样错误就能够被发现并且修复。它也需要给错误审核委员会提供错误发生的环境。
    唯一正确 :
    1 .运行客户端
    2 .找出一个记录
    3 .更改记录但不存盘
    4 .使数据库服务器脱机
    5 .尝试保存记录
    6 .收到一个超时的错误
    7 .退出客户端
    结果:崩溃
    马虎的(有很大空间让人产生误解的 ):
    使数据库服务器脱机,保存,然后退出,崩溃了。
    太多冗余的信息(不能够指出什么是引发错误的最关键原因)
    1 .运行客户端
    2 .为输入新的条目查询数据库
    3 .打开一个浏览器
    4 .在 yahoo.com 上浏览新闻
    5 .关闭浏览器
    6 .选择一个条目
    7 .把种类从 “ 蔬菜 ” 更改到 “ 水果 ”
    8 .使数据库服务器脱机
    9 .尝试保存记录
    10 .收到一个超时的错误
    11 .退出客户端
    结果:崩溃
     
    (翻译)编写优秀Bug报告的艺术
                                        ----------http://blog.csdn.net/imlogic/
    前言

    在99年的Quality week上的一次演讲中,微软的一个测试经理,Roger Sherman指出了由于“不可重现”导致bug关闭的主要原因。这是一个非常可惜的情况,因为这样的bug report浪费了紧张的开发计划中的宝贵时间,增加了对产品质量完全是无关紧要的事情,同时导致了在开发人员和测试之间的挫败感和差的感觉。有时,bug report是由于短暂的或随机的事件,测试和开发之间不一致的工具和配置,或者在测试的环境下对正确的行为的模糊定义而产生的,但是许多的由于不可重现而被关闭的测试报告是因为描述不清晰,被误解,或者只是文字的错误。

    幸运的是,我学习到一些能够引起管理层注意,更清楚的和开发人员沟通并得到修复的编写优秀bug report的诀窍。这些技巧不仅仅提供了是在被修复的问题的比例方面得到了可靠的回报,而且在同开发人员和管理层的通过中也得到了回报。在我管理的项目中使用这种方法编写bug report,8份bug report中大约只有一个没有被修复。

    这篇文章的思想只有当你的报告针对的测试执行过程是专业的质量工作才可以发挥作用。聪明地执行完整的测试包是产生可靠的测试状况信息的基础的其中一个因素。在许多的测试文献中广泛地介绍了多种多样的关于如何构建这样的测试包的方法。选择和你质量风险管理需求相一致的技术并且使之适应你的具体情况,敏捷地监督已计划的测试的执行过程,这样你就可以拥有可靠的测试执行过程。

    另外一个关键的因素-bug report,却没有得到太多的关注。这是非常令人遗憾的,因为优秀的bug report对反映测试小组真实的和可理解的工作质量同测试本身一样都是非常重要的。试想一下:如果你不能用开发人员能够理解的术语和能够用于调试的方法给开发人员解释一个错误,他怎么能够修复问题呢?如果你不能够在bug report中提出象“保险杆标签”(bumper sticker)一样的错误总结来引起管理层的注意,你又如何让他们关心你们发现的问题呢?

    Bug report的核心是对错误的描述。表格1中是一个关于好和差的错误描述的例子。编写好的bug report是一种好的艺术形式。采用以下的10条技巧可以帮助你的小组提高编写bug report的质量:

    组织Structure:测试人员应该采用深思熟虑的,小心谨慎的方法执行测试,并且做详尽的记录。这样可以促使他们对测试下的系统有很好的认识。当错误发生的时候,一个有组织的测试人员能够知道最早出现问题的地方。

    重现Reproduce:测试人员在编写bug report之前必须在检查问题是否可重现。如果错误不可再重现,仍然应该写下来,但是必须说明问题的偶然性。一个好的处理原则就是在编写bug report之前反复尝试3次。

    隔离Isolate:在尝试编写bug report之前,必须试着隔离错误。可以采用改变一些变量的方法,如系统的配置,它可能可以改变错误的症状。这些信息可以为开发人员着手调试提供思路。

    归纳Generalize:在测试人员发现了一个已隔离的,可重现的问题后,应该对问题进行归纳。同一个问题是否出现在其他的模块或其他的地方?同一个故障是否有更加严重的问题?

    对比Compare:如果测试人员以前曾经验证过现在出错的测试用例,那么他就应该检查以前的测试结果以检查相同的条件是否通过以前的测试。如果是的话,那么这个问题就象是一个回归的错误。注意由于同一测试条件有可能出现在多个测试用例中,这个步骤就不仅仅只是检查一个测试用例在以前的多个结果。

    总结Summarize:在bug report的第一行写上错误的总结是非常关键的。测试人员要花些时间思考已发现的错误对客户有何影响。这不仅仅要求测试人员编写的报告要能够吸引读者,使和管理层的沟通清晰,还要能够帮助设置错误修复的优先级别。

    精简Condense:在bug report的初稿完成后,测试人员应该反复阅读它,集中剔除那些没有关系的步骤或词语。隐含的或模糊的说明和那些由于对没有任何关系的细节或者那些在重现错误过程中不需要的步骤而消磨报告欢迎程度的无穷唠叨都不是bug report的目标。

    消除歧义Disambiguate:测试人员在精简空话的同时或其之后随即应该再仔细检查报告是否有会产生误解的地方。测试人员应该尽量避免使用模糊的,会产生歧义的和主观的词语。目标是使用能够表述事实,清楚的,不会产生争执的词语。

    中立Neutralize:如文中所述,作为坏消息的传递人,和善地提交消息是一个挑战。如同所有的错误总结一样,独立的bug report在措辞方面应该保持公正。攻击开发人员,指责潜在的错误,企图诙谐或使用挖苦将引起开发人员的憎恶,并且使注意力从“提高产品质量”这个大的目标上转移开了。谨慎的测试人员只用Bug report来描述事实。

    检查Review:一旦测试人员感觉bug report是他能够编写的最好版本,他应该将报告再给一个或多个同行进行检查。他的同事们也应该给出一些建议,为了澄清问题不断地提问,如果适当的话,甚至可以挑战“错误成灾”的结论。在允许的时间里,测试小组应该尽可能提交最好的bug report。

    以上10条技巧可以帮助你和你的小组提交准确简洁的,彻底校订的,精心构思的,高质量的技术文档。测试小组应该集中编写bug report的任务,测试组长和经理应该让测试组成员清楚地认识到编写优秀的bug report是一项首要的工作任务。衡量优秀的bug report的质量指标应该包括如下:
    o        对管理层来说,是清晰明了的,特别是在概要这一级;
    o        对于开发部门是有用的,主要是给出能够让开发人员高效地调试问题的相关信息
    o        可以很快的将bug从“Opened”状态转变成“Closed”状态,减少为得到更多的信息从开发人员打回的差的bug report并导致测试人员返工的时间。

    改进bug报告的流程是需要花费一些时间的,但是也给予了效果显著的回报。首先,简单的流程改进了测试小组和高层、平行管理层之间的沟通,增强小组的信任度,名望和鼓励管理层给测试投资更多的资源。第二,平稳地递交报告给开发人员促进了测试和开发人员之间积极的关系。第三,更短的bug生命周期是更加有效的,在时间上之前花费在编写优秀bug report上的时间和后期由于返工差的bug report花费的时间相抵消。这些回报帮助开发流程通过有效的沟通和高效率的流程获得更好的产品质量。
  • Test case related - 2-18-2008

    2008-06-01 13:35:33

    一、测试用例是软件测试的核心
    软件测试的重要性是毋庸置疑的。但如何以最少的人力、资源投入,在最短的时间内完成测试,发现软件系统的缺陷,保证软件的优良品质,则是软件公司探索和追求的目标。每个软件产品或软件开发项目都需要有一套优秀的测试方案和测试方法。

    影响软件测试的因素很多,例如软件本身的复杂程度、开发人员(包括分析、设计、编程和测试的人员)的素质、测试方法和技术的运用等等。因为有些因素是客观存在的,无法避免。有些因素则是波动的、不稳定的,例如开发队伍是流动的,有经验的走了,新人不断补充进来;一个具体的人工作也受情绪等影响,等等。如何保障软件测试质量的稳定?有了测试用例,无论是谁来测试,参照测试用例实施,都能保障测试的质量。可以把人为因素的影响减少到最小。即便最初的测试用例考虑不周全,随着测试的进行和软件版本更新,也将日趋完善。

    因此测试用例的设计和编制是软件测试活动中最重要的。测试用例是测试工作的指导,是软件测试的必须遵守的准则。更是软件测试质量稳定的根本保障。

    二、什么叫测试用例
    测试用例(Test Case)目前没有经典的定义。比较通常的说法是:指对一项特定的软件产品进行测试任务的描述,体现测试方案、方法、技术和策略。内容包括测试目标、测试环境、输入数据、测试步骤、预期结果、测试脚本等,并形成文档。

    不同类别的软件,测试用例是不同的。不同于诸如系统、工具、控制、游戏软件,管理软件的用户需求更加不统一,变化更大、更快。笔者主要从事企业管理软件的测试。因此我们的做法是把测试数据和测试脚本从测试用例中划分出来。测试用例更趋于是针对软件产品的功能、业务规则和业务处理所设计的测试方案。对软件的每个特定功能或运行操作路径的测试构成了一个个测试用例。

    三、编制测试用例
    着重介绍一些编制测试用例的具体做法。

    1、测试用例文档
    编写测试用例文档应有文档模板,须符合内部的规范要求。测试用例文档将受制于测试用例管理软件的约束。
    软件产品或软件开发项目的测试用例一般以该产品的软件模块或子系统为单位,形成一个测试用例文档,但并不是绝对的。

    测试用例文档由简介和测试用例两部分组成。简介部分编制了测试目的、测试范围、定义术语、参考文档、概述等。测试用例部分逐一列示各测试用例。每个具体测试用例都将包括下列详细信息:用例编号、用例名称、测试等级、入口准则、验证步骤、期望结果(含判断标准)、出口准则、注释等。以上内容涵盖了测试用例的基本元素:测试索引,测试环境,测试输入,测试操作,预期结果,评价标准。

    如何设计编制软件测试用例(二)

    2、测试用例的设置
    我们早期的测试用例是按功能设置用例。后来引进了路径分析法,按路径设置用例。目前演变为按功能、路径混合模式设置用例。

    按功能测试是最简捷的,按用例规约遍历测试每一功能。

    对于复杂操作的程序模块,其各功能的实施是相互影响、紧密相关、环环相扣的,可以演变出数量繁多的变化。没有严密的逻辑分析,产生遗漏是在所难免。路径分析是一个很好的方法,其最大的优点是在于可以避免漏测试。

    但路径分析法也有局限性。在一个非常简单字典维护模块就存在十余条路径。一个复杂的模块会有几十到上百条路径是不足为奇的。笔者以为这是路径分析比较合适的使用规模。若一个子系统有十余个或更多的模块,这些模块相互有关联。再采用路径分析法,其路径数量成几何级增长,达5位数或更多,就无法使用了。那么子系统模块间的测试路径或测试用例还是要靠传统方法来解决。这是按功能、路径混合模式设置用例的由来。

    3、设计测试用例
    测试用例可以分为基本事件、备选事件和异常事件。设计基本事件的用例,应该参照用例规约(或设计规格说明书),根据关联的功能、操作按路径分析法设计测试用例。而对孤立的功能则直接按功能设计测试用例。基本事件的测试用例应包含所有需要实现的需求功能,覆盖率达100%。

    设计备选事件和异常事件的用例,则要复杂和困难得多。例如,字典的代码是唯一的,不允许重复。测试需要验证:字典新增程序中已存在有关字典代码的约束,若出现代码重复必须报错,并且报错文字正确。往往在设计编码阶段形成的文档对备选事件和异常事件分析描述不够详尽。而测试本身则要求验证全部非基本事件,并同时尽量发现其中的软件缺陷。

    可以采用软件测试常用的基本方法:等价类划分法、边界值分析法、错误推测法、因果图法、逻辑覆盖法等设计测试用例。视软件的不同性质采用不同的方法。如何灵活运用各种基本方法来设计完整的测试用例,并最终实现暴露隐藏的缺陷,全凭测试设计人员的丰富经验和精心设计。

    四、测试用例在软件测试中的作用
    1、指导测试的实施
    测试用例主要适用于集成测试、系统测试和回归测试。在实施测试时测试用例作为测试的标准,测试人员一定要按照测试用例严格按用例项目和测试步骤逐一实施测试。并对测试情况记录在测试用例管理软件中,以便自动生成测试结果文档。

    根据测试用例的测试等级,集成测试应测试那些用例,系统测试和回归测试又该测试那些用例,在设计测试用例时都已作明确规定,实施测试时测试人员不能随意作变动。
     
    如何设计编制软件测试用例(三)

    2、规划测试数据的准备
    在我们的实践中测试数据是与测试用例分离的。按照测试用例配套准备一组或若干组测试原始数据,以及标准测试结果。尤其象测试报表之类数据集的正确性,按照测试用例规划准备测试数据是十分必须的。
    除正常数据之外,还必须根据测试用例设计大量边缘数据和错误数据。

    3、编写测试脚本的"设计规格说明书"
    为提高测试效率,软件测试已大力发展自动测试。自动测试的中心任务是编写测试脚本。如果说软件工程中软件编程必须有设计规格说明书,那么测试脚本的设计规格说明书就是测试用例。

    4、评估测试结果的度量基准
    完成测试实施后需要对测试结果进行评估,并且编制测试报告。判断软件测试是否完成、衡量测试质量需要一些量化的结果。例:测试覆盖率是多少、测试合格率是多少、重要测试合格率是多少,等等。以前统计基准是软件模块或功能点,显得过于粗糙。采用测试用例作度量基准更加准确、有效。

    5、分析缺陷的标准
    通过收集缺陷,对比测试用例和缺陷数据库,分析确证是漏测还是缺陷复现。漏测反映了测试用例的不完善,应立即补充相应测试用例,最终达到逐步完善软件质量。而已有相应测试用例,则反映实施测试或变更处理存在问题。

    五、相关问题
    1、测试用例的评审
    测试用例是软件测试的准则,但它并不是一经编制完成就成为准则。测试用例在设计编制过程中要组织同级互查。完成编制后应组织专家评审,需获得通过才可以使用。评审委员会可由项目负责人、测试、编程、分析设计等有关人员组成,也可邀请客户代表参加。

    2、测试用例的修改更新
    测试用例在形成文档后也还需要不断完善。主要来自三方面的缘故:第一、在测试过程中发现设计测试用例时考虑不周,需要完善;第二、在软件交付使用后反馈的软件缺陷,而缺陷又是因测试用例存在漏洞造成;第三、软件自身的新增功能以及软件版本的更新,测试用例也必须配套修改更新。

    一般小的修改完善可在原测试用例文档上修改,但文档要有更改记录。软件的版本升级更新,测试用例一般也应随之编制升级更新版本。
  • QTP 基础代码收集

    2008-06-01 13:33:49

    1。 将bug添加到QC

    Dim TDConnection
    Set TDConnection = CreateObject("TDApiOle.TDConnection")
     
    TDConnection.InitConnection "http://yovav/tdbin" ' URL for the DB
    TDConnection.ConnectProject "TD76","bella","pino" ' Valid login information
     
    If TDConnection.Connected Then
      MsgBox("Connected to " + chr (13) + "Server " + TDConnection.ServerName _
      + chr (13) +"Project " + TDConnection.ProjectName )
    Else
      MsgBox("Not Connected")
    End If
     
    'Get the IBugFactory
    Set BugFactory = TDConnection.BugFactory
     
    'Add a new empty bug
    Set Bug = BugFactory.AddItem (Nothing)
     
    'fill the bug with relevant parameters
    Bug.Status = "New"
    Bug.Summary = "Connecting to TD"
    Bug.Priority = "4-Very High" ' depends on the DB
    Bug.AssignedTo = "admin" ' user that must exist in the DB's users list
    Bug.DetectedBy = "admin" ' user that must exist in the DB's users list
     
    'Post the bug to DB ( commit )
    Bug.Post

    2。 文件操作函数集:


    ' Creates a specified file and returns a TextStream object that can be used to read from or write to the file.
    ' Example of usage
    ' Set f = CreateFile("d:\temp\beenhere.txt", True)
    ' f.WriteLine Now
    ' f.Close
    Function CreateFile(sFilename, bOverwrite)
        Set fso = CreateObject("scrīpting.FileSystemObject")
        Set CreateFile = fso.CreateTextFile(sFilename, bOverwrite)
    End Function
     
    ' Opens a specified file and returns a TextStream object that can be used to read from, write to, or append to the file.
    ' iomode: 1 - ForReading, 2 - ForWriting, 8 - ForAppending
    ' Example of usage
    ' Set f = OpenFile("d:\temp\beenhere.txt", 2, True)
    ' f.WriteLine Now
    ' f.Close

    Function OpenFile(sFilename, iomode, create)
        Set fso = CreateObject("scrīpting.FileSystemObject")
        Set ōpenFile = fso.OpenTextFile(sFilename, iomode, create)
    End Function
     
    ' Appends a line to a file
    ' Example of usage
    ' AppendToFile "d:\temp\beenhere.txt", Now
    Function AppendToFile(sFilename, sLine)
        Const ForAppending = 8
        If sFilename = "" Then
            sFilename = Environment("SystemTempDir") & "\QTDebug.txt"
        End If
        Set f = OpenFile(sFilename, ForAppending, True)
        f.WriteLine sLine
        f.Close
    End Function
     
    ' Writes a line to a file.
    ' Destroys the current content of the file!
    ' Example of usage
    ' WriteToFile "d:\temp\beenhere.txt", Now
    Function WriteToFile(sFilename, sLine)
        Const ForWriting = 2
        If sFilename = "" Then
            sFilename = Environment("SystemTempDir") & "\QTDebug.txt"
        End If
        Set f = OpenFile(sFilename, ForWriting, True)
        f.WriteLine sLine
        f.Close
    End Function

    3。 使用qtp发mail

    ' Example 1
    Function SendMail(SendTo, Subject, Body, Attachment)
        Set ōl=CreateObject("Outlook.Application")
        Set Mail=ol.CreateItem(0)
        Mail.to=SendTo
        Mail.Subject=Subject
        Mail.Body=Body
        If (Attachment <> "") Then
            Mail.Attachments.Add(Attachment)
        End If
        Mail.Send
        ol.Quit
        Set Mail = Nothing
        Set ōl = Nothing
    End Function
     
    ' Example 2
    Function SendMail(SendFrom, SendTo, Subject, Body)
        Set ōbjMail=CreateObject("CDONTS.Newmail")
        ObjMail.From = SendFrom
        ObjMail.To = SendTo
        ObjMail.Subject = Subject
        ObjMail.Body = Body
        ObjMail.Send
        Set ōbjMail = Nothing
    End Function
     

    4。Excel操作函数集合:

    Dim ExcellApp 'As Excel.Application
    Dim excelSheet1 'As Excel.worksheet
    Dim excelSheet2 'As Excel.worksheet
     
    Set ExcelApp = CreateExcel()
     
    'Create a workbook with two worksheets
    ret = RenameWorksheet(ExcelApp, "Book1", "Sheet1", "Example1 Sheet Name")
    ret = RenameWorksheet(ExcelApp, "Book1", "Sheet2", "Example2 Sheet Name")
    ret = RemoveWorksheet(ExcelApp, "Book1", "Sheet3")
     
    'SaveAs the work book
    ret = SaveWorkbook(ExcelApp, "Book1", "D:\Example1.xls")
     
    'Fill worksheets
    Set excelSheet1 = GetSheet(ExcelApp, "Example1 Sheet Name")
    Set excelSheet2 = GetSheet(ExcelApp, "Example2 Sheet Name")
    For column = 1 to 10
        For row = 1 to 10
            SetCellValue excelSheet1, row, column, row + column
            SetCellValue excelSheet2, row, column, row + column
        Next
    Next
     
    'Compare the two worksheets
    ret = CompareSheets(excelSheet1, excelSheet2, 1, 10, 1, 10, False)
    If ret Then
        MsgBox "The two worksheets are identical"
    End If
     
    'Change the values in one sheet
    SetCellValue excelSheet1, 1, 1, "Yellow"
    SetCellValue excelSheet2, 2, 2, "Hello"
     
    'Compare the worksheets again
    ret = CompareSheets(excelSheet1, excelSheet2, 1, 10, 1, 10, True)
    If Not ret Then
        MsgBox "The two worksheets are not identical"
    End If
     
    'save the workbook by index identifier
    SaveWorkbook ExcelApp, 1, ""
     
    'Close the Excel application
    CloseExcel ExcelApp
     
    ' ****************************************** Function Library ***********************************************************

    Dim ExcelApp 'As Excel.Application
    Dim excelSheet 'As Excel.worksheet
    Dim excelBook 'As Excel.workbook
    Dim fso 'As scrīpting.FileSystemObject
     
    ' This function will return a new Excel Object with a default new Workbook
    Function CreateExcel() 'As Excel.Application
        Dim excelSheet 'As Excel.worksheet
        Set ExcelApp = CreateObject("Excel.Application") 'Create a new excel Object
        ExcelApp.Workbooks.Add
        ExcelApp.Visible = True
        Set CreateExcel = ExcelApp
    End Function
     
    'This function will close the given Excel Object
    'excelApp - an Excel application object to be closed
    Sub CloseExcel(ExcelApp)
        Set excelSheet = ExcelApp.ActiveSheet
        Set excelBook = ExcelApp.ActiveWorkbook
        Set fso = CreateObject("scrīpting.FileSystemObject")
        On Error Resume Next
        fso.CreateFolder "C:\Temp"
        fso.DeleteFile "C:\Temp\ExcelExamples.xls"
        excelBook.SaveAs "C:\Temp\ExcelExamples.xls"
        ExcelApp.Quit
        Set ExcelApp = Nothing
        Set fso = Nothing
        Err = 0
        On Error GoTo 0
    End Sub
     
    'The SaveWorkbook method will save a workbook according to the workbookIdentifier
    'The method will overwrite the previously saved file under the given path
    'excelApp - a reference to the Excel Application
    'workbookIdentifier - The name or number of the requested workbook
    'path - the location to which the workbook should be saved
    'Return "OK" on success and "Bad Workbook Identifier" on failure
    Function SaveWorkbook(ExcelApp, workbookIdentifier, path) 'As String
        Dim workbook 'As Excel.workbook
        On Error Resume Next
        Set workbook = ExcelApp.Workbooks(workbookIdentifier)
        On Error GoTo 0
        If Not workbook Is Nothing Then
            If path = "" Or path = workbook.FullName Or path = workbook.Name Then
                workbook.Save
            Else
                Set fso = CreateObject("scrīpting.FileSystemObject")
     
                'if the path has no file extension then add the 'xls' extension
                If InStr(path, ".") = 0 Then
                    path = path & ".xls"
                End If
     
                On Error Resume Next
                fso.DeleteFile path
                Set fso = Nothing
                Err = 0
                On Error GoTo 0
                workbook.SaveAs path
            End If
            SaveWorkbook = "OK"
        Else
            SaveWorkbook = "Bad Workbook Identifier"
        End If
    End Function
     
    'The SetCellValue method sets the given 'value' in the cell which is identified by
    'its row column and parent Excel sheet
    'excelSheet - the excel sheet that is the parent of the requested cell
    'row - the cell's row in the excelSheet
    'column - the cell's column in the excelSheet
    'value - the value to be set in the cell
    Sub SetCellValue(excelSheet, row, column, value)
        On Error Resume Next
        excelSheet.Cells(row, column) = value
        On Error GoTo 0
    End Sub
     
    'The GetCellValue returns the cell's value according to its row column and sheet
    'excelSheet - the Excel Sheet in which the cell exists
    'row - the cell's row
    'column - the cell's column
    'return 0 if the cell could not be found
    Function GetCellValue(excelSheet, row, column)
        value = 0
        Err = 0
        On Error Resume Next
        tempValue = excelSheet.Cells(row, column)
        If Err = 0 Then
            value = tempValue
            Err = 0
        End If
        On Error GoTo 0
        GetCellValue = value
    End Function
     
    'The GetSheet method returns an Excel Sheet according to the sheetIdentifier
    'ExcelApp - the Excel application which is the parent of the requested sheet
    'sheetIdentifier - the name or the number of the requested Excel sheet
    'return Nothing on failure
    Function GetSheet(ExcelApp, sheetIdentifier) 'As Excel.worksheet
        On Error Resume Next
        Set GetSheet = ExcelApp.Worksheets.Item(sheetIdentifier)
        On Error GoTo 0
    End Function
     
    'The InsertNewWorksheet method inserts an new worksheet into the active workbook or
    'the workbook identified by the workbookIdentifier, the new worksheet will get a default
    'name if the sheetName parameter is empty, otherwise the sheet will have the sheetName
    'as a name.
    'Return - the new sheet as an Object
    'ExcelApp - the excel application object into which the new worksheet should be added
    'workbookIdentifier - an optional identifier of the worksheet into which the new worksheet should be added
    'sheetName - the optional name of the new worksheet.
    Function InsertNewWorksheet(ExcelApp, workbookIdentifier, sheetName) 'As Excel.worksheet
        Dim workbook 'As Excel.workbook
        Dim worksheet 'As Excel.worksheet
     
        'In case that the workbookIdentifier is empty we will work on the active workbook
        If workbookIdentifier = "" Then
            Set workbook = ExcelApp.ActiveWorkbook
        Else
            On Error Resume Next
            Err = 0
            Set workbook = ExcelApp.Workbooks(workbookIdentifier)
            If Err <> 0 Then
                Set InsertNewWorksheet = Nothing
                Err = 0
                Exit Function
            End If
            On Error GoTo 0
        End If
     
        sheetCount = workbook.Sheets.Count
        workbook.Sheets.Add , sheetCount
        Set worksheet = workbook.Sheets(sheetCount + 1)
     
        'In case that the sheetName is not empty set the new sheet's name to sheetName
        If sheetName <> "" Then
            worksheet.Name = sheetName
        End If
     
        Set InsertNewWorksheet = worksheet
    End Function
     
    'The RenameWorksheet method renames a worksheet's name
    'ExcelApp - the excel application which is the worksheet's parent
    'workbookIdentifier - the worksheet's parent workbook identifier
    'worksheetIdentifier - the worksheet's identifier
    'sheetName - the new name for the worksheet
    Function RenameWorksheet(ExcelApp, workbookIdentifier, worksheetIdentifier, sheetName) 'As String
        Dim workbook 'As Excel.workbook
        Dim worksheet 'As Excel.worksheet
        On Error Resume Next
        Err = 0
        Set workbook = ExcelApp.Workbooks(workbookIdentifier)
        If Err <> 0 Then
            RenameWorksheet = "Bad Workbook Identifier"
            Err = 0
            Exit Function
        End If
        Set worksheet = workbook.Sheets(worksheetIdentifier)
        If Err <> 0 Then
            RenameWorksheet = "Bad Worksheet Identifier"
            Err = 0
            Exit Function
        End If
        worksheet.Name = sheetName
        RenameWorksheet = "OK"
    End Function
     
    'The RemoveWorksheet method removes a worksheet from a workbook
    'ExcelApp - the excel application which is the worksheet's parent
    'workbookIdentifier - the worksheet's parent workbook identifier
    'worksheetIdentifier - the worksheet's identifier
    Function RemoveWorksheet(ExcelApp, workbookIdentifier, worksheetIdentifier) 'As String
        Dim workbook 'As Excel.workbook
        Dim worksheet 'As Excel.worksheet
        On Error Resume Next
        Err = 0
        Set workbook = ExcelApp.Workbooks(workbookIdentifier)
        If Err <> 0 Then
            RemoveWorksheet = "Bad Workbook Identifier"
            Exit Function
        End If
        Set worksheet = workbook.Sheets(worksheetIdentifier)
        If Err <> 0 Then
            RemoveWorksheet = "Bad Worksheet Identifier"
            Exit Function
        End If
        worksheet.Delete
        RemoveWorksheet = "OK"
    End Function
     
    'The CreateNewWorkbook method creates a new workbook in the excel application
    'ExcelApp - the Excel application to which an new Excel workbook will be added
    Function CreateNewWorkbook(ExcelApp)
        Set NewWorkbook = ExcelApp.Workbooks.Add()
        Set CreateNewWorkbook = NewWorkbook
    End Function
     
    'The OpenWorkbook method opens a previously saved Excel workbook and adds it to the Application
    'excelApp - the Excel Application the workbook will be added to
    'path - the path of the workbook that will be opened
    'return Nothing on failure
    Function OpenWorkbook(ExcelApp, path)
        On Error Resume Next
        Set NewWorkbook = ExcelApp.Workbooks.Open(path)
        Set ōpenWorkbook = NewWorkbook
        On Error GoTo 0
    End Function
     
    'The ActivateWorkbook method sets one of the workbooks in the application as Active workbook
    'ExcelApp - the workbook's parent excel Application
    'workbookIdentifier - the name or the number of the workbook
    Sub ActivateWorkbook(ExcelApp, workbookIdentifier)
        On Error Resume Next
        ExcelApp.Workbooks(workbookIdentifier).Activate
        On Error GoTo 0
    End Sub
     
    'The CloseWorkbook method closes an open workbook
    'ExcelApp - the parent Excel application of the workbook
    'workbookIdentifier - the name or the number of the workbook
    Sub CloseWorkbook(ExcelApp, workbookIdentifier)
        On Error Resume Next
        ExcelApp.Workbooks(workbookIdentifier).Close
        On Error GoTo 0
    End Sub
     
    'The CompareSheets method compares between two sheets.
    'if there is a difference between the two sheets then the value in the second sheet
    'will be changed to red and contain the string:
    '"Compare conflict - Value was 'Value2', Expected value is 'value2'"
    'sheet1, sheet2 - the excel sheets to be compared
    'startColumn - the column to start comparing in the two sheets
    'numberOfColumns - the number of columns to be compared
    'startRow - the row to start comparing in the two sheets
    'numberOfRows - the number of rows to be compared
    Function CompareSheets(sheet1, sheet2, startColumn, numberOfColumns, startRow, numberOfRows, trimed) 'As Boolean
        Dim returnVal 'As Boolean
        returnVal = True
     
        'In case that one of the sheets doesn't exists, don't continue the process
        If sheet1 Is Nothing Or sheet2 Is Nothing Then
            CompareSheets = False
            Exit Function
        End If
     
        'loop through the table and fill values into the two worksheets
        For r = startRow to (startRow + (numberOfRows - 1))
            For c = startColumn to (startColumn + (numberOfColumns - 1))
                Value1 = sheet1.Cells(r, c)
                Value2 = sheet2.Cells(r, c)
     
                'if 'trimed' equels True then used would like to ignore blank spaces
                If trimed Then
                    Value1 = Trim(Value1)
                    Value2 = Trim(Value2)
                End If
     
                'in case that the values of a cell are not equel in the two worksheets
                'create an indicator that the values are not equel and set return value
                'to False
                If Value1 <> Value2 Then
                    Dim cell 'As Excel.Range
                    sheet2.Cells(r, c) = "Compare conflict - Value was '" & Value2 & "', Expected value is '" & Value1 & "'."
                    Set cell = sheet2.Cells(r, c)
                    cell.Font.Color = vbRed
                    returnVal = False
                End If
            Next
        Next
        CompareSheets = returnVal
    End Function

    5。WebTable功能函数集合:

    ' ************************************************** Function Library ********************************
     
    ' Registering both functions
    RegisterUserFunc "WebTable", "ObjectsByMicClass", "ObjectsByMicClass"
    RegisterUserFunc "WebTable", "ItemByKeyColumn", "ItemByKeyColumn"
     
    ' Function: ObjectsByMicClass
    ' Descrīption: Returns a collection of objects all the objects in a
    ' WebTable that have the specified MicClass
    ' Return Value: A Collection of Objects
    ' Arguments:
    ' Obj - Test Object (WebTable)
    ' micClass - The micClass of the objects to retrieve
    '-----------------------------------------------------------------------------------------------------------
    Function ObjectsByMicClass(Obj, micClass)
        Set Table = Obj
        ' Create a collection object to hold the items
        Set ōbjCollection = CreateObject("scrīpting.Dictionary")
        ' Go over all the cells in the table, and look for objects with the specified micClass
        For row=1 to Table.RowCount
            ColumnCount=Table.ColumnCount(row)
            For col=1 to ColumnCount
                For ItemIndex=0 to Table.ChildItemCount(row, col, micClass)-1
                    Set childItem=Nothing
                    Set childItem = Table.ChildItem(row, col, micClass, ItemIndex)
                    If Not childItem is Nothing Then
                         ' If the cell contains a micClass object, add it to the collection
                         ItemKey = objCollection.Count + 1
                         objCollection.Add ItemKey, childItem
                    End if
                Next
            Next
        Next
        Set ōbjectsbyMicClass = objCollection
    End Function
     
     
    ' Function: ItemByKeyColumn
    ' Descrīption: Returns an item from a column, based on the value of a
    ' key column
    ' Return Value: Object
    ' Arguments:
    ' Obj - Test Object (WebTable)
    ' KeyColumnIndex - Index of the KeyColumn
    ' KeyColumnValue - Value to search for in the key column
    ' KeyItemIndex - Index of the value in the key column (if there is
    '                        more than one). If 0, the first item will be used.
    ' TargetColumnIndex - Column from which to retrieve the target item
    ' micClass - The micClass of the target item
    ' TargetItemIndex - Index of the target item to retrieve (if there is
    '                           more than one). If 0, the first item will be used.
    ' ------------------------------------------------------------------------------------------------------------------------------------
    Function ItemByKeyColumn(Obj, KeyColumnIndex, KeyColumnValue, KeyItemIndex, TargetColumnIndex, micClass, TargetItemIndex)
        Table = Obj
        rowCount = Table.RowCount
     
        ' if TargetItemIndex was not specified, use 1 as deafult
        If TargetItemIndex < 1 Then
            TargetItemIndex = 1
        End If
        ' if KeyColumnIndex was not specified, use 1 as default
        If KeyItemIndex < 1 Then
            KeyItemIndex = 1
        End If
     
        ' look for KeyColumnValue in the key column to determine which
        ' row to retrieve the targe item from
        Row = 0
        foundIndex = 0
        While Row <= RowCount And foundIndex < KeyItemIndex
            Row = Row + 1
            CellData = Table.GetCellData(Row, KeyColumnIndex)
            If CellData = KeyColumnValue Then
               foundIndex = foundIndex + 1
            End If
        Wend
        If foundIndex < KeyItemIndex Then
            Exit Function
        End If
     
        ' Now that we know the row, retrieve the item (according to its micClass)
        ' from the target column.
        ChildItemsCount = Table.ChildItemCount(Row, TargetColumnIndex, micClass)
        If ChildItemsCount > =1 And ChildItemsCount >= TargetItemIndex Then
             Set GetItemByKeyColumn = Table.ChildItem(Row, TargetColumnIndex, micClass, TargetItemIndex-1)
        End If
    End Function
     
     
    ' ************************************ Examples that use these functions *******************************************************
     
     
    ' Using the ItemByKeyColumn Function
    Set ōbj = Browser("Table with objects").Page("Itenerary: Mercury Tours").WebTable("Acapulco to Zurich").ItemByKeyColumn(1,"FLIGHT",2,3,"WebElement",1)
    msgbox obj.GetROProperty("innerhtml")
     
    ' Using the ObjectsByMicClass function
    Set collection = Browser("Browser").Page("Page").WebTable("Table").ObjectsByMicClass("WebCheckBox")
    For i=1 to collection.count
        If collection(i).GetROProperty("checked") Then
            collection(i).Set "OFF"
        Else
            collection(i).Set "ON"
        End If
    Next

     

  • 验证页面连接方法

    2008-06-01 11:18:41

    1。 验证baidu上面所有的连接是否可用
    set a= Browser("百度一下,你就知道")
    set b= Browser("百度一下,你就知道").Page("百度一下,你就知道")
    call CheckLinks(a,b)

    Function CheckLinks (BrowserObject,BrowserPage)
    CheckLinks=TRUE
    Dim s_URL,i_CreationTime
    Dim s_LinkOuterText,s_LinkInnerText,s_Linkhref
    s_URL=BrowserPage.GetROProperty("url")
    i_CreationTime=1
    i_LinkCount=BrowserPage.object.links.length - 1

    Dim i_Link

    For i_Link=0 to i_LinkCount
    If Trim(BrowserPage.object.links(i_Link).target)="" Then
    BrowserPage.object.links(i_Link).target="_blank" ' Set the link to open i a new window so that we dont have any change in current window
    End If

    BrowserPage.object.links(i_Link).click
    On error resume next
    Browser("CreationTime:=" & i_CreationTime).sync
    Browser("CreationTime:=" & i_CreationTime).Page("micClass:=Page").sync
    On error goto 0
    Dim s_LinkDetails

    IHTML = Browser("CreationTime:=" & i_CreationTime).Page("micClass:=Page").object.Body.innerHTML
    'Check if page was not able to be displayed
    If (InStr(IHTML,"HTTP 404") <> 0) Or (InStr(IHTML,"cannot be displayed") <> 0) Then
    s_LinkDetails="Link Broken" + vbcrlf + "Link Details:" +vbcrlf
    s_LinkDetails=s_LinkDetails+"OuterText: "+ s_LinkOuterText + vbcrlf
    s_LinkDetails=s_LinkDetails+"InnerText: "+ s_LinkInnerText + vbcrlf
    s_LinkDetails=s_LinkDetails+ "href: " + s_Linkhref+ vbcrlf
    s_LinkDetails=s_LinkDetails+ "Links Open in New Browse: " & bNewBrowser & vbcrlf
    Reporter.ReportEvent micWarning,"Check Link(" & i_Link & ") -> " & s_LinkOuterText ,s_LinkDetails
    CheckLinks=FALSE
    Else
    s_LinkDetails="Link Working" + vbcrlf + "Link Details:" +vbcrlf
    s_LinkDetails=s_LinkDetails+"OuterText: "+ s_LinkOuterText + vbcrlf
    s_LinkDetails=s_LinkDetails+"InnerText: "+ s_LinkInnerText+ vbcrlf
    s_LinkDetails=s_LinkDetails+ "href: " + s_Linkhref+ vbcrlf
    s_LinkDetails=s_LinkDetails+ "Links Open in New Browse: " & bNewBrowser & vbcrlf
    Reporter.ReportEvent micPass,"Check Link(" & i_Link & ") -> " & s_LinkOuterText ,s_LinkDetails
    End If

    Browser("CreationTime:=1").close ' Close the link open.
    Next
    End Function

    列举应用程序:

    Function EnumerateApp(ParentObj, Desc, OperationMethod, PostOperationMethod, RestoreMethod)
       dim ObjCol, CurrentObj, idx
       idx = 0
       ' retrieve a collection of all the objects of the given descrition
       Set ōbjCol = ParentObj.ChildObjects(Desc)
     
       Do While (idx < ObjCol.Count)
          ' get the current object
          set CurrentObj = ObjCol.item(idx)
      
          ' perform the desired operation on the object
          eval("CurrentObj." & OperationMethod)
     
          ' perform the post operations (after the object operation)
          eval(PostOperationMethod & "(ParentObj, CurrentObj)")
     
          ' Return the application to the original state
          eval(RestoreMethod & "(ParentObj, CurrentObj)")
     
           idx = idx + 1
           ' reretrieve the collection of objects
           ' (as the application might have changed)
           Set ōbjCol = ParentObj.ChildObjects(Desc)
       Loop
    End Function
     
    ' ********************************** An Example of usage **********************
    ' Report all the pages refered to by the corrent page
    ' ***********************************************************************************
     
    Function ReportPage(ParentObj, CurrentObj)
        dim FuncFilter, PageTitle
     
        PageTitle = ParentObj.GetROProperty("title")
     
        FuncFilter = Reporter.Filter
        Reporter.Filter = 0
        Reporter.ReportEvent 0, "Page Information", "page title " & PageTitle
        Reporter.Filter = FuncFilter
    End Function
     
    Function BrowserBack(ParentObj, CurrentObj)
        BrowserObj.Back
    End Function
     
    ' save the Report Filter mode
    OldFilter = Reporter.Filter
    Reporter.Filter = 2 ' Enables Errors Only
     
    ' Create the descrīption of the Link object
    Set Desc = Descrīption.Create()
    Desc("html tag").Value = "A"
     
    Set BrowserObj = Browser("creationtime:=0")
    Set PageObj = BrowserObj.Page("index:=0")
     
    ' Start the enumeration
    call EnumerateApp(PageObj, Desc, "Click", "ReportPage", "BrowserBack")
     
    Reporter.Filter = OldFilter ' returns the original filter

  • 数据库操作

    2008-05-25 23:44:29

    1。 显示数据库所有记录:

    Dim oConn, oRst, oFieldDim sql
    set ōConn = CreateObject("ADODB.Connection")
    oConn.Open "QT_Flight32"
    set ōRst = CreateObject("ADODB.recordset")
    oRst.Open "Select * from Orders", oConn
    Do Until oRst.EOF   
     For each oField in oRst.Fields      
       Print oField.Name & " = " & oField.Value  
     Next   
    Print String( 20, "-" )   
    oRst.MoveNext
    loop
    oRst.close
    oConn.close

     

    2。 Database功能收集:


    'Example of How to use functions.

    ''************************************************************************************
    ' Example use DSN created for database of Flight sample application.
    ''************************************************************************************
    SQL="SELECT * FROM ORDERS"
    connection_string="QT_Flight32"
     
    isConnected = db_connect ( curConnection ,connection_string )
    If isConnected = 0 then
        ' execute the basic SQL statement
        set myrs=db_execute_query( curConnection , SQL )
       
        ' report the query and the connection string
        Reporter.ReportEvent micInfo ,"Executed query and created recordset ","Connection_string is ==> " & connection_string & " SQL query is ===> " & SQL
        ' show the number of rows in the table using a record set
        msgBox " Quantity of rows in queried DB ( db_get_rows_count )==> " & db_get_rows_count( myrs )
        ' show the number of rows in the table using a new SQL statement
        msgBox " Quantity of rows in queried DB (db_get_rows_count_SQL ) ==> " & db_get_rows_count_SQL( curConnection , "SELECT COUNT(*) FROM ORDERS" )
     
        ' change a value of a field in an existing row
        rc = db_set_field_value (curConnection, "ORDERS" , "Agents_Name" , "test", "Agents_Name", "AGENT_TESTER")
     
        ' examples of how to retrieve values from the table
        msgBox "val row 0 col 0: " & db_get_field_value( myrs , 0 , 0 )
        msgBox "val row 0 col 1: " & db_get_field_value( myrs , 0 , 1 )
        msgBox "val row 1 col Name: " & db_get_field_value( myrs , 1 , "Agents_Name" )
        msgBox "val SQL row 1 col Name: " & db_get_field_value_SQL( curConnection , "ORDERS" , 1 , "Agents_Name" )
     
        db_disconnect curConnection
    End If
     
    ''****************************************************************************************
     
     
    ' Database Functions library
    '******************************************************************************************
    'db_connect
    ' ---------------
    ' The function creates a new connection session to a database.
    ' curSession - the session name (string)
    ' connection_string - a connection string
    ' for example the connection_string can be "DSN=SQLServer_Source;UID=SA;PWD=abc123"
    '******************************************************************************************
    Function db_connect( byRef curSession ,connection_string)
        dim connection
        on error Resume next
        ' Opening connection
        set connection = CreateObject("ADODB.Connection")
        If Err.Number <> 0 then
            db_connect= "Error # " & CStr(Err.Number) & " " & Err.Descrīption
            err.clear
            Exit Function
        End If
     
        connection.Open connection_string
        If Err.Number <> 0 then
            db_connect= "Error # " & CStr(Err.Number) & " " & Err.Descrīption
            err.clear
            Exit Function
        End If
        set curSession=connection
        db_connect=0
    End Function
     
    '********************************************************************************************
    ' db_disconnect
    ' ---------------------
    ' The function disconnects from the database and deletes the session.
    ' curSession - the session name (string)
    '********************************************************************************************
    Function db_disconnect( byRef curSession )
        curSession.close
        set curSession = Nothing
    End Function
     
    '*********************************************************************************************
    ' db_execute_query
    ' ---------------------------
    ' The function executes an SQL statement.
    ' Note that a db_connect for (arg1) must be called before this function
    ' curSession - the session name (string)
    ' SQL - an SQL statement
    '**********************************************************************************************
    Function db_execute_query ( byRef curSession , SQL)
        set rs = curSession.Execute( SQL )
        set db_execute_query = rs
    End Function
     
    ''***********************************************************************************************
    ' db_get_rows_count
    ' ----------------------------
    ' The function returns the number of rows in the record set
    ' curRS - variable , contain record set , that contain all values that retrieved from DB by query execution
    ''***********************************************************************************************
    Function db_get_rows_count( byRef curRS )
        dim rows
        rows = 0
        curRS.MoveFirst
        Do Until curRS.EOF
            rows = rows+1
            curRS.MoveNext
        Loop
        db_get_rows_count = rows
    End Function
     
    ''************************************************************************************************
    ' db_get_rows_count_SQL
    ' ------------------------------------
    ' The function returns the number of rows that are the result of a given SQL statement
    ' curSession - the session name (string)
    ' CountSQL - SQL statement
    ''************************************************************************************************
    Function db_get_rows_count_SQL( byRef curSession ,CountSQL )
        dim cur_rs
        set cur_rs = curSession.Execute( CountSQL )
        db_get_rows_count_SQL = cur_rs.fields(0).value
    End Function
     
    ''*************************************************************************************************
    ' db_get_field_value_SQL
    ' -----------------------------------
    ' curSession - variable denote current active connection
    ' tableName - name of the table , where value should be retrieved
    ' rowIndex - row number
    ' colName - the column name.
    '*************************************************************************************************
    Function db_get_field_value_SQL( curSession , tableName , rowIndex , colName )
        dim rs
        SQL = " select " & colName & " from " & tableName
        set rs = curSession.Execute( SQL )

        rs.move rowIndex
        db_get_field_value_SQL = rs.fields(colName).value
    End Function

    '*************************************************************************************************
    ' db_get_field_value
    ' --------------------------
    ' The function returns the value of a single item of an executed query.
    ' Note that a db_execute_query for (arg1) must called before this function
     
    ' curRecordSet - variable , contain record set , that contain all values that retrieved from DB by query execution
    ' rowIndex - the row index number (zero based)
    ' colIndex - the column index number (zero based) or the column name.
    ' returned values
    ' -1 - requested field index more than exists in record set
    '*************************************************************************************************
    Function db_get_field_value( curRecordSet , rowIndex , colIndex )
        dim curRow
     
        curRecordSet.MoveFirst
        count_fields = curRecordSet.fields.count-1
        If ( TypeName(colIndex)<> "String" ) and ( count_fields < colIndex ) then
            db_get_field_value = -1 'requested field index more than exists in recordset
        Else
            curRecordSet.Move rowIndex
            db_get_field_value = curRecordSet.fields(colIndex).Value
        End If
    End Function
     
    '*************************************************************************************************
    ' db_set_field_value
    ' ---------------------------
    ' The function changes the value of a field according to a search criteria.
    ' We search for a certain row according to a column name and the desired vale, then we change a value in that row according
    ' to a desired columns
     
    ' curConnection - the session name (string)
    ' tableName - name of the table , where value should be retrieved
    ' colFind - the column we search the criteria in
    ' colFindValue - the value we search in the column
    ' colChange - the column were we want to change the value
    ' colChangeValue - the new value
     
    ' returned values
    ' -1 - requested field index that doesn't exists in the recordset
    '*************************************************************************************************
    Function db_set_field_value(curConnection, tableName , colFind , colFindValue, colChange, colChangeValue)
        dim curRow
        dim updateSQL
        dim checkSQL
     
        checkSQL = "select * from Details"
        set myrs1 = db_execute_query( curConnection , SQL )
        myrs1.MoveFirst
        count_fields = myrs1.fields.count
        If ( TypeName(colFind)<> "String" ) or ( TypeName(colChange)<> "String" ) then
            db_set_field_value = -1 'requested field index that doesn't exists in the record set
        Else
            updateSQL = "UPDATE " & tableName & " SET " & colChange & "='" & colChangeValue & "' WHERE " & colFind & "='" & colFindValue & "'"
            set myrs1 = db_execute_query( curConnection , updateSQL )
            db_set_field_value = 1 'operation suceeded
        End If
    End Function
     
    '*************************************************************************************************
    ' db_add_row
    ' -----------------
    ' The function adds a new row to the desired table
     
    ' curConnection - variable , contains a recordset , that contains all the values to be retrieved from DB by query execution
    ' tableName - name of the table , where value should be retrieved from
    ' values - array that contains values to be entered in a new row to the table.

    ' Note: the function must receive values for all the columns in the table!
    ' returned values
    ' -1 - the number of values to be entered to the table doesn't fit the number of columns
    ' 1 - execution of the query succeed and the data was entered to the table
    '*************************************************************************************************
    Function db_add_row(curConnection, tableName , byRef values)
        dim i
        dim updateSQL
        dim myrs1
     
        updateSQL = "INSERT INTO " & tableName & " VALUES ("
        arrLen = UBound (values) - LBound (values) + 1
     
        set myrs1=db_execute_query( curConnection , SQL )
        myrs1.MoveFirst
        count_fields = myrs1.fields.count
        ' check if numbers of values fit the numbers of columns
        If arrLen <> count_fields then
            db_add_row = -1
        Else
            For i = 0 to arrLen-1
                updateSQL = updateSQL & values (i)
                If i <> arrLen-1 then
                    updateSQL = updateSQL & ","
                End If
            Next
            updateSQL = updateSQL & ")"
            set myrs1 = db_execute_query( curConnection , updateSQL )
            db_add_row = 1
         End If
    End Function
     
    '*************************************************************************************************
    ' represent_values_of_RecordSet
    ' ---------------------------------------------
    ' the function reports all the values on fields in a record set
    ' curRS - variable , contains the recordset , that contains all the values that were retrieved from the DB by the query execution
    '*************************************************************************************************
    Function represent_values_of_RecordSet( myrs)
        dim curRowString
        myrs.MoveFirst
        reporter.ReportEvent 4,"Fields quantity" , myrs.fields.count
        count_fields = myrs.fields.count-1
        curRow=0
        Do Until myrs.EOF
            curRowString= ""
            curRow = curRow+1
            For ii=0 to count_fields
                curRowString = curRowString& "Field " &"==> " & myrs.fields(ii).Name &" : Value ==>" & myrs.fields(ii).Value & vbCrLf
            Next
            myrs.MoveNext
            reporter.ReportEvent 4,"Current row"& curRow , curRowString
        Loop
    End Function

     

  • DeviceReplay 用法

    2008-05-25 22:29:58

      当我想对UI上的控件做一些特定的操作的时候,例如鼠标左右键点击,键盘输入字符串等,特别是在Object.Set和Object.Type没法使用的时候,DeviceReplay就显得非常有用。

    DeviceReplay使用的前提是:

    1. 应用程序窗口被激活。

    对窗口应用程序: 可以使用Window( "W" ).Activate micLeftBtn

    对网页应用程序: 可以使用

    hwnd = Browser( "B" ).GetROProperty( "hwnd" )

    Window( "hwnd:=" & hwnd ).Activate micLeftBtn

    2. 目标控件为焦点。

    WebEdit( "WE" ).object.focus 或者 WebEdit( "WE" ).FireEvent "onfocusin"

    使用以下方法可以判断当前哪些键是否按下:(Microsoft.VisualBasic.Devices.Keyboard

    Set Keyboard = DotNetFactory.CreateInstance( "Microsoft.VisualBasic.Devices.Keyboard", "Microsoft.VisualBasic" )

    Print CBool( Keyboard.AltKeyDown )

    Print CBool( Keyboard.CapsLock )

    Print CBool( Keyboard.CtrlKeyDown )

    Print CBool( Keyboard.NumLock )

    Print CBool( Keyboard.ScrollLock )

    Print CBool( Keyboard.ShiftKeyDown )

    注意:使用DotNetFactory的时候要注意数据类型的转换

    使用以下方法可以判断当前鼠标的位置:(System.Windows.Forms.Control)

    Set ctlr = DotNetFactory.CreateInstance("System.Windows.Forms.Control")

    For i = 1 To 10

       Wait 2

       Print "1. X=" & ctlr.MousePosition.X & "; Y=" & ctlr.MousePosition.Y

    Next

     

    DeviceReplay有以下常用方法:

    1。 object.SendString( str )

    Set deviceReplay = CreateObject( "Mercury.DeviceReplay" )

    SystemUtil.Run "notepad.exe", "", "", "open"

    ' ** this line always identifies the notepad window.

    Window( "nativeclass:=Notepad", "index:=0″ ).Activate micLeftBtn

    deviceReplay.SendString( "DeviceReplay" )

    Set deviceReplay = Nothing

    2。 object.KeyDown( key )|object.KeyUp( key )

    Const VK_SHIFT = 42

    Const VK_RETURN = 28

    Set deviceReplay = CreateObject( "Mercury.DeviceReplay" )

    SystemUtil.Run "notepad.exe", "", "", "open"

    Window( "nativeclass:=Notepad", "index:=0″ ).Activate micLeftBtn

    ' ** Typing uppercase

    deviceReplay.KeyDown VK_SHIFT

    deviceReplay.SendString( "devicereplay" )

    deviceReplay.PressKey VK_RETURN

    deviceReplay.KeyUp VK_SHIFT

    ' ** Typing in lower case

    deviceReplay.SendString( "devicereplay" )

    Set deviceReplay = Nothing

    3。 object.PressKey( key )

    Const VK_O = 24 : Const VK_F = 33

    Const VK_CONTROL = 29 : Const VK_ESCAPE = 1 : Const VK_MENU = 56

    Set deviceReplay = CreateObject( "Mercury.DeviceReplay" )

    SystemUtil.Run "notepad.exe", "", "", "open"

    Window( "nativeclass:=Notepad", "index:=0″ ).Activate micLeftBtn

    Wait 1

    ' ** Opening the menu Alt + F + O

    deviceReplay.PressKey VK_MENU

    deviceReplay.PressKey VK_F

    deviceReplay.PressKey VK_O

    Wait 2

    ' ** Closing the menu

    deviceReplay.PressKey VK_ESCAPE

    deviceReplay.SendString "Open menu was closed."

    Set deviceReplay = Nothing

    4. object.PressNKeys( key, N )


    用于模拟连续多次按某个键。

    5. object.DragAndDrop( dragX, dragY, dropX, dropY, Button )

    LEFT_MOUSE_BUTTON = 0

    MIDDLE_MOUSE_BUTTON = 1

    RIGHT_MOUSE_BUTTON = 2

    等同于object.MouseDown( x, y, Button ), object.MouseDown( x, y ), object.MouseUp( x, y, Button )的组合

    6. object.MouseClick( x, y, Button )

    7. object.MouseDblClick( x, y, Button )

    8。 object.SetSynchronizationTimeout( object, nSyncTimeout, is_sec)


  • QTP 调用vbs读写xml

    2008-05-17 22:27:08

    摘自: http://bbs.51testing.com/viewthread.php?tid=76590&highlight=%23text

    Dim strXML

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


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

    Function xmlRecursion(byval xmlNode,byval strNodeName)
            If xmlNode.nodeName = strNodeName And xmlNode.hasChildNodes Then
                    If  xmlNode.childNodes.item(0).nodeName = "#text" Then
                            strXML = strXML & xmlNode.nodeName & ":" & xmlNode.childNodes.item(0).nodeValue & Chr(13)                                               
                    End If               
            End If                       
            If xmlNode.hasChildNodes Then
                    For Each childNodeItem In xmlNode.ChildNodes
                            If childNodeItem.hasChildNodes Then
                                    xmlRecursion childNodeItem,strNodeName                               
                            End If                       
                    Next
            End If       
    End Function

    使用xml文件:

    <?xml version="1.0"?>
      <books>
        <book>
            <author>Carson</author>
            <price format="dollar">31.95</price>
            <pubdate>05/01/2001</pubdate>
        </book>
        <pubinfo>
            <publisher>MSPress</publisher>
            <state>WA</state>
            <author>Randall</author> 
        </pubinfo>
        <abc>
            <user>
                <author>Alex</author>
            </user>
        </abc>
      </books>

    结果:

    author:Carson

    author:Randall

    author:Alex

    附:ms-help://MS.MSDNQTR.v90.en/wd_xml/html/b5e52844-4820-47c0-a61d-de2da33e9f54.htm

    The XML Document Object Model (DOM) class is an in-memory representation of an XML document. The DOM allows you to programmatically read, manipulate, and modify an XML document.

    xml:

     
    <?xml version="1.0"?>
      <books>
        <book>
            <author>Carson</author>
            <price format="dollar">31.95</price>
            <pubdate>05/01/2001</pubdate>
        </book>
        <pubinfo>
            <publisher>MSPress</publisher>
            <state>WA</state>
        </pubinfo>
      </books> 

    The following illustration shows how memory is structured when this XML data is read into the DOM structure.

    XML document structure

    Within the XML document structure, each circle in this illustration represents a node, which is called an XmlNode object. The XmlNode object is the basic object in the DOM tree. The XmlDocument class, which extends XmlNode, supports methods for performing operations on the document as a whole (for example, loading it into memory or saving the XML to a file. In addition, XmlDocument provides a means to view and manipulate the nodes in the entire XML document.

  • VBscript 基础积累

    2008-05-17 17:41:57

    摘自:http://doc.51windows.net/vbscrīpt/?url=/vbscrīpt/dir.htm

    1, 声明变量:

    使用 Option Explicit 语句作为脚本的第一条语句,后面使用变量都必须显示声明,可使用Dim, Public, Private.

    Note:

    Dim A(10) 虽然括号中显示的数字是 10,但由于在 VBscrīpt 中所有数组都是基于 0 的,所以这个数组实际上包含 11 个元素。在基于 0 的数组中,数组元素的数目总是括号中显示的数目加 1。这种数组被称为固定大小的数组。
     ReDim MyArray(25)
     . . . 
     ReDim Preserve MyArray(30) 关键字Preserve可以调节数组维数
    2, 过程调用(对Sub过程):
    Call MyProc(firstarg, secondarg)
    MyProc firstarg, secondarg
    当不使用 Call 语句进行调用时,括号被省略。
    3. VB命名约定:
    常量:这种标识常数的方法依旧可行,但您还可以选择其他方案,用 Const 语句创建真正的常数。这个约定使用大小写混合的格式,并以“con”作为常数名的前缀。例如: conYourOwnConstant
    变量: 
    子类型前缀示例
    BooleanblnblnFound
    BytebytbytRasterData
    Date (Time)dtmdtmStart
    DoubledbldblTolerance
    ErrorerrerrOrderNum
    IntegerintintQuantity
    LonglnglngDistance
    ObjectobjobjCurrent
    SinglesngsngAverage
    StringstrstrFirstName

    对象:

    对象类型 前缀 示例
    3D 面板 pnl pnlGroup
    动画按钮 ani aniMailBox
    复选框 chk chkReadOnly
    组合框、下拉列表框 cbo cboEnglish
    命令按钮 cmd cmdExit
    公共对话框 dlg dlgFileOpen
    框架 fra fraLanguage
    水平滚动条 hsb hsbVolume
    图像 img imgIcon
    标签 lbl lblHelpMessage
    直线 lin linVertical
    列表框 lst lstPolicyCodes
    旋钮 spn spnPages
    文本框 txt txtLastName
    垂直滚动条 vsb vsbRate
    滑块 sld sldScale

    4, VBscrīpt 特性:

    类别 关键字
    数组处理 Array
    Dim, Private, Public, ReDim
    IsArray
    Erase
    LBound, UBound
    赋值 Set
    程序注释 使用 ' 或 Rem 的程序注释
    常数/文字 Empty
    Nothing
    Null
    True, False
    控制流程 Do...Loop
    For...Next
    For Each...Next
    If...Then...Else
    Select Case
    While...Wend
    With
    转换 Abs
    Asc, AscB, AscW
    Chr, ChrB, ChrW
    CBool, CByte
    CCur, CDate
    CDbl, CInt
    CLng, CSng, CStr
    DateSerial, DateValue
    Hex, Oct
    Fix, Int
    Sgn
    TimeSerial, TimeValue
    日期/时间 Date, Time
    DateAdd, DateDiff, DatePart
    DateSerial, DateValue
    Day, Month, MonthName
    Weekday, WeekdayName, Year
    Hour, Minute, Second
    Now
    TimeSerial, TimeValue
    声明 Class
    Const
    Dim, Private, Public, ReDim
    函数, Sub
    属性 Get, 属性 Let, 属性 Set
    错误处理 On Error
    Err
    表达式 Eval
    Execute
    RegExp
    Replace
    Test
    格式化字符串 FormatCurrency
    FormatDateTime
    FormatNumber
    FormatPercent
    输入/输出 InputBox
    LoadPicture
    MsgBox
    文字 Empty
    False
    Nothing
    Null
    True
    数学 Atn, Cos, Sin, Tan
    Exp, Log, Sqr
    Randomize, Rnd
    杂类 Eval 函数
    Execute 语句
    RGB 函数
    对象 Create对象
    Err 对象
    Get对象
    RegExp
    运算符 加法 (+),减法 (-)

    幂(^)
    求余算术运算 (Mod)
    乘法 (*)除法(/)
    整除(\)
    求补(-)
    字符串连接(&)
    Is
    And, Or, Xor
    Eqv, Imp

    选项 Option Explicit
    过程 Call
    函数, Sub
    属性 Get, 属性 Let, 属性 Set
    四舍五入 Abs
    Int, Fix, Round
    Sgn
    scrīpt 引擎 ID scrīptEngine
    scrīptEngineBuildVersion
    scrīptEngineMajorVersion
    scrīptEngineMinorVersion
    字符串 Asc, AscB, AscW
    Chr, ChrB, ChrW
    Filter, InStr, InStrB
    InStrRev
    Join
    Len, LenB
    LCase, UCase
    Left, LeftB
    Mid, MidB
    Right, RightB
    Replace
    Space
    Split
    StrComp
    String
    StrReverse
    LTrim, RTrim, Trim
    变量 IsArray
    IsDate
    IsEmpty
    IsNull
    IsNumeric
    Is对象
    TypeName
    VarType

    5, 正值表达式:

    正则表达式(RegExp)对象

    提供简单的正则表达式支持功能。

    说明

    下面的代码说明了RegExp对象的用法:

    Function RegExpTest(patrn, strng)
      Dim regEx, Match, Matches      ' 建立变量。
      Set regEx = New RegExp         ' 建立正则表达式。
      regEx.Pattern = patrn         ' 设置模式。
      regEx.IgnoreCase = True         ' 设置是否区分字符大小写。
      regEx.Global = True         ' 设置全局可用性。
      Set Matches = regEx.Execute(strng)   ' 执行搜索。
      For Each Match in Matches      ' 遍历匹配集合。
        RetStr = RetStr & "Match found at position "
        RetStr = RetStr & Match.FirstIndex & ". Match Value is '"
        RetStr = RetStr & Match.Value & "'." & vbCRLF
      Next
      RegExpTest = RetStr
    End Function
    MsgBox(RegExpTest("is.", "IS1 is2 IS3 is4")
  • QTP 个人总结 (初级)

    2008-04-22 23:16:54

    1. QTP 识别对象原理

    QTP对每个控件类都定义了一些强制属性和辅助属性。当qtp对对象进行识别的时候,首先qtp会取出控件的所有强制属性,如果这些强制属性能够唯一标识这个控件则选强制属性来标识控件,如不能唯一标识控件,qtp则逐一取出控件类的辅助属性直到能唯一标识控件为止。

    如果使用强制属性和辅助属性还不能唯一标识控件。 则有以下两种可能:

    QTP对控件类的识别使用了智能识别(Smart Identification),qtp会忽略之前对强制属性与辅助属性的识别,这时qtp会使用smart identification 中的 basic filter properties和optional filter properties来对对象进行识别. basic filter properties就是一些控件的基础属性,例如button的Name,这个属性变了button也就变成另外一个button了。

    如果对控件类的识别没有使用Smart Identification,系统会使用Ordinal Identifier来对控件进行识别。

    2. QTP的测试流程。大多自动化测试工具都是使用录制回放这种方式:

    录制:QTP录制方式有三种,标准录制,模拟录制与低级录制。

    标准录制一般就是最常用的,录制对标准控件的一些操作,如对button的click,winEdit的Set value等等。

    模拟录制,可以录制鼠标的轨迹,主要用与绘图此类软件的录制。

    低级录制,与标准录制不同,不是Object.Operation value 而是记录屏幕坐标点上的操作。 稳定性较差。

    录制的时候,QTP会将用户的操作以VBscrīpt的形式保存在Expert View里头,录制的时候还会判断控件是否存在对象库里面,如果没有则创建对象。对象库里面的对象称为 Test Object 与程序UI上的控件对象Run Time Object 相对应。

    和TO、RO相关的几个函数有:

    GetTOProperty():取得仓库对象的某个属性的值
    GetTOProperties():取得仓库对象的所有属性的值 //返回一个对象类型,属性集为对象标识属性集
    SetTOProperty():设置仓库对象的某个属性的值
    GetROProperty():取得实际对象的某个属性的值

    录制完成需要对代码进行修改,增加代码的稳定性与可移植性。

    1. Add Comments. 代码中加必要的解释能增加代码的可读性,利于回归测试中代码的维护。

    2. 增加控制流语句。如程序的登陆,正常流程是输入验证信息,点击登陆按钮进入主界面。若用户已经登陆则系统就应该弹出一个确认框问用户是否需要删除原来的session。 这是录制的教本里面我们就应该加一个判断, 判断是否这个弹出框存在。

    3. 参数化。 QTP 参数化有一下几种方式:1)action parameter. Keyword View -> 右键ActionName ->Action Properties, Parameter tab. 可以配置action的传入参数与传出参数,参数的使用为: strInput = Parameter("input"), input为action的传入参数。 Parameter("output") = strOutput, output为action的输出参数。 2)Environment, 在脚本中使用strTemp = Environment("environmentVariable"). 3)datatable, 使用DataTable.SetCurrentRow(RowVale)  strTemp = DataTable.RowValue(Parameter, SheetID).

    4. CheckPoint.

    5. 同步点. WaitProperty(Property, value, Timeout). Object.exist(Timeout). Wait Time.

    6. QTP错误处理机制:

    QTP 有三种错误处理机制:

    1, 全局错误响应: Test setting中run设置

    全局错误响应是qtp的系统缺省错误处理,当没有使用其他错误处理方式时,系统会自动调用这里指定的方式进行错误处理。

    在整个脚本有效。 若是出错在Function Library,则错误号只存在library,不会传到Action中。

    2, VBscrīpt on Error错误处理: On Error Resume Next

    VBscrīpt的错误处理方式,三种相关方式为:

    a)On Error Resume Next: 一旦这个语句已经被处理,脚本将继续后面的程序,不理会已经出现的错误。

    b)On Error GoTo 0: 使用On Error GoTo 0语句恢复缺省的错误处理行为, 在运行这个语句后, 发生的运行期错误将导致缺省错误处理,在qtp中,缺省的出错处理就是全局错误响应。

    c)Err对象: Err对象有三个属性  Number, Source, Descrīption. Err对象在运行时错误发生的时候赋予新的值,原来的值将被丢弃。 Err对象是全局的, 不受函数调用的影响。 Err对象可以使用clear方法清空。 任何时候使用On Error Resume Next或者On Error GoTo 0都会清空Err对象。

    只对语句所在的函数或Action中该语句之后的代码生效,对于子函数,调用Action均无效。若On Error 语句存在Action中而出错在Function Library则系统会调用全局错误响应处理。若是Action中函数调用,则会返回到使用On Error 语句的环境中。

    3, 错误恢复场景: Recovery Scenario.

    触发条件有:

    a) Pop-up Window

    b) Object state

    c) Test run error.

    d) Application Crash.

    错误恢复有以下几种方式:

    a) Keyboard or mouse operation

    b) Close Application process

    c) Function Call

    d) Restart Microsoft Windows

    7. 关于虚拟对象的使用:

    虚拟对象管理器中显示的虚拟对象集合存储在您的计算机中,而不是随包含虚拟对象步骤的测试或组件存储。这意味着如果您在测试或组件步骤中使用虚拟对象,则仅当在包含正确的虚拟对象定义的计算机中运行时,该对象在运行会话过程中才能被识别。要将您的虚拟对象集合定义复制到另一个计算机,请将您的 <QuickTest 安装文件夹>\dat\VoTemplate 文件夹的内容(或该文件夹中的单个 .vot 集合文件)复制到目标计算机上的相同文件夹中

     <QuickTest 安装文件夹>\dat\VoTemplate 文件夹只有在已经定义虚拟对象的情况下才会出项

    8. 使用RegisterUserFunc注册用户定义的测试对象方法

    RegisterUserFunc TOClass, MethodName, FunctionName

    如果输入已经和指定的对象类关联的方法的名称,则用户定义的函数将覆盖现有方法。如果输入新名称,将添加到对象支持的方法列表中。

    Function MySet (obj, x)

    dim y

    y = obj.GetROProperty("value")

    Reporter.ReportEvent micDone, "previous value", y

    MySet=obj.Set(x)

    End Function

    RegisterUserFunc "WebEdit", "Set", "MySet"

    Browser("MercuryTours").Page("FindFlights").WebEdit("Country").Set "Canada"

    使用UnRegisterUserFunc TOClass, MethodName 可以取消用户注册方法

    9, QTP描述性编程:

    平行于对象库的一种编程方法. Example:

    set EditDesc = Descrīption.Create()

    EditDesc("Name").Value = "userName"

    EditDesc("Index").Value = "0"

    Browser("Welcome: Mercury").Page("Welcome: Mercury").WebEdit(EditDesc).Set "MyName"

    使用描述性编程加正值表达式对于那些测试对象经常动态变化的情况很有用, Example:

    Dim strTemp
    strTemp = "Google.*"
    Browser("百度一下,你就知道").Page("Google").WebEdit("q").Set "abc"
    Browser("百度一下,你就知道").Page("Google").WebButton("Name:="&strTemp).Click

    10, 巧用WebTable的ChildItem方法: Example

    Set ōbjTable = Browser("hao123网址之家--文学小说").Page("hao123网址之家--文学小说").WebTable("起点中文网")
    intRow = 2
    intCol = 2
    ' 通过ChildItem获取单元格中的链接对象
    Set ōbjLink = objTable.ChildItem(intRow, intCol, "Link" , 0)
    ' 单击链接
    objLink.click

  • QTP tips

    2008-04-17 21:26:59

    1) How to add a constant number in a datatable?
    This is more to do with MS excel then QTP!! but useful to know because at times it becomes frustrating to the novices.
    Just append ' to the number
    Ex: if you wish to enter 1234567 in datatable then write it as '1234567

    2) How can i check if a parameter exists in DataTable or not?
    The best way would be to use the below code:
    on error resume next
    val=DataTable("ParamName",dtGlobalSheet)
    if err.number<> 0 then
    'Parameter does not exist
    else
    'Parameter exists
    end if

    3) How can i check if a checkpoint passes or not?
    chk_PassFail = Browser(...).Page(...).WebEdit(...).Check (Checkpoint("Check1"))
    if chk_PassFail then
    MsgBox "Check Point passed"
    else MsgBox "Check Point failed"
    end if

    4) My test fails due to checkpoint failing, Can i validate a checkpoint without my test failing due to checpoint failure?
    Reporter.Filter = rfDisableAll 'Disables all the reporting stuff
    chk_PassFail = Browser(...).Page(...).WebEdit(...).Check (Checkpoint("Check1"))
    Reporter.Filter = rfEnableAll 'Enable all the reporting stuff
    if chk_PassFail then
    MsgBox "Check Point passed"
    else
    MsgBox "Check Point failed"
    end if

    5) What is the difference between an Action and a function?
    Action is a thing specific to QTP while functions are a generic thing which is a feature of VB scrīpting. Action can have a object repository associated with it while a function can't. A function is just lines of code with some/none parameters and a single return value while an action can have more than one output parameters.

    6) Where to use function or action?
    Well answer depends on the scenario. If you want to use the OR feature then you have to go for Action only. If the functionality is not about any automation scrīpt i.e. a function like getting a string between to specific characters, now this is something not specific to QTP and can be done on pure VB scrīpt, so this should be done in a function and not an action. Code specific to QTP can also be put into an function using DP. Decision of using function/action depends on what any one would be comfortable using in a given situation.

    7) When to use a Recovery Scenario and when to us on error resume next?
    Recovery scenarios are used when you cannot predict at what step the error can occur or when you know that error won't occur in your QTP scrīpt but could occur in the world outside QTP, again the example would be "out of paper", as this error is caused by printer device driver. "On error resume next" should be used when you know if an error is expected and dont want to raise it, you may want to have different actions depending upon the error that occurred. Use err.number & err.descrīption to get more details about the error.

    8) How to use environment variable?
    A simple defintion could be... it is a variable which can be used across the reusable actions and is not limited to one reusable action.
    There are two types of environment variables:
    1. User-defined
    2. Built-in
    We can retrieve the value of any environment variable. But we can set the value of only user-defined environment variables.

    To set the value of a user-defined environment variable:
    Environment (VariableName) = NewValue

    To retrieve the value of a loaded environment variable:
    CurrValue = Environment (VariableName)

    Example
    The following example creates a new internal user-defined variable named MyVariable with a value of 10, and then retrieves the variable value and stores it in the MyValue variable.

    Environment.Value("MyVariable")=10
    MyValue=Environment.Value("MyVariable")

    9) What are the files and subfolders of a QuickTest Professional test?
    The files and folders hold binary and text data that are required for the test to run successfully.
    The following table provides a descrīption, the type, and comments regarding the files that make up a QuickTest Professional test.

    File Name

    Descrīption

    Type

    Comments Regarding File

    Test.tsp

    Test settings

    Binary

    Do not edit

    Default.xls

    Data table parameters

    Excel similar

    Can be edited using Excel

    Parameters.mtr

    Parameterization information

    Binary

    Do not edit

    Action

    Action folder (See other table)

    <!--[if !supportEmptyParas]--> <!--[endif]-->


    <!--[if !supportEmptyParas]--> <!--[endif]-->


    Default.cfg

    Load test configuration file

    Text

    Do not edit

    Default.prm

    Load test configuration file

    Text

    Do not edit

    Default.usp

    Load test configuration file

    Text

    Do not edit

    .usr

    Load test configuration file

    Text

    Do not edit

    Thick_usr.dat

    Load test configuration file

    Text

    Do not edit

    Thin_usr.dat

    Load test configuration file

    Text

    Do not edit

    Files within Action folder:

    File Name

    Descrīption

    Type

    Comments Regarding File

    scrīpt.mts

    Action scrīpt

    Text

    Edit text preceding the @@ sign only

    Resource.mtr

    Object Repository

    Binary

    Do not edit

    Snapshots

    Active screen files

    Folder

    Do not edit

    There are few more files extensions like

    .MTB Batch File
    .LCK Locked


    10) How to rename a checkpoint (QTP 9.0)?
    Example:
    Window("Notepad").WinEditor("Edit").Check CheckPoint("Edit")
    In the above example, the user would like to change the name of the CheckPoint object from "Edit" to something more meaningful.
    Note:
    This functionality is new to QuickTest Professional 9.0.This is not available for QTP 8.2 and below.
    1. Right-click on the Checkpoint step in the Keyword View or on the Checkpoint object in Expert View.
    2. Select "Checkpoint Properties" from the pop-up menu.
    3. In the Name field, enter the new checkpoint name.
    4. Click . The name of the checkpoint object will be updated within the scrīpt.
    Example:
    Window("Notepad").WinEditor("Edit").Check CheckPoint("NewCheckPointName")
    Note:
    You must use the QuickTest Professional user interface to change the name of the checkpoint. If you manually change the name of the checkpoint in the scrīpt, QuickTest Professional will generate an error during replay. The error message will be similar to the following:

    "The "" CheckPoint object was not found in the Object Repository. Check the Object Repository to confirm that the object exists or to find the correct name for the object."

    The CheckPoint object is not a visible object within the object repository, so if you manually modify the name, you may need to recreate the checkpoint to resolve the error.

    <!--[if !supportEmptyParas]--> <!--[endif]-->

    11) Does QuickTest Professional support Internet Explorer 7.0?
    QuickTest Professional 9.1
    QuickTest Professional 9.1 supports Microsoft Internet Explorer 7.0 Beta 3. Internet Explorer version 7.0 is now certified to work and to be tested with QuickTest Professional version 9.1.
    QuickTest Professional 9.0
    QuickTest Professional 9.0 supports Internet Explorer 7.0 Beta 2.
    QuickTest Professional 8.2 and below
    QuickTest Professional 8.2 and below do not include support for Internet Explorer 7.0.

    Does QuickTest Professional support Firefox?
    QuickTest Professional 9.1 and 9.2
    QuickTest Professional 9.1 provides replay support for Mozilla Firefox 1.5 and Mozilla Firefox 2.0 Alpha 3 (Alpha-level support for Bon Echo 2.0a3).
    Notes:

    QuickTest Professional 9.1 will not record on FireFox. You can record a test on Microsoft Internet Explorer and run it on any other supported browser, such as FireFox.

    The .Object property for web objects is not supported in FireFox.

    QuickTest Professional 9.0
    QuickTest Professional 9.0 provides replay support for Mozilla FireFox 1.5.
    Notes:

    QuickTest Professional 9.0 will not record on FireFox. You can record a test on Microsoft Internet Explorer and run it on any other supported browser, such as FireFox.

    The .Object property for web objects is not supported in FireFox.

    QuickTest Professional 8.2 and below

    QuickTest Professional 8.2 and below do not have support for Firefox.


    <!--[if !supportLineBreakNewLine]-->12) Problem
    After Quick Test Professional is started, Windows Media will not start. It returns the error message "wmplayer.exe has generated errors and will be closed by Windows. You will need to restart the program. An error log is being created."

    If you start Window's Media Player first, it will continue to work normally after starting QuickTest Professional.

    Solution:

    Include the Windows Media Player's executable in the NoBBTApps section of the mic.ini file

    1. Close QuickTest Professional.
    2. Go to \bin\mic.ini.
    3. Include wmplayer.exe in the NoBBTApps section of mic.ini file.

    Example:
    [NoBBTApps]
    wmplayer.exe=rek

    4. Save the mic.ini file and restart QuickTest Professional.

    13) What is the lservrc file in QTP?

    The lservrc file contains the license codes that have been installed

    The lservrc file contains the license codes that have been installed. Whenever a new license is created, the license code is automatically added to this file. The lservrc file is a text file, with no extension.

    File Location:

    1) For a Concurrent (Floating) license installation:

    "#server installation directory#\#language#"

    Example:
    C:\Program Files\XYZ Technologies\ABC Server\English\lservrc

    2) For a Seat (Stand-alone) license installation:

    #AQT/QTP installation directory#\bin"

    Example:
    C:\Program Files\Mercury Interactive\QuickTest Professional\Bin\lservrc


    14) What to do if you are not able to run QTP from quality center?
    This is for especially for newbies with QTP.
    Check that you have selected Allow other mercury products to run tests and components from Tools--> Options--> Run Tab.

    15) Does QuickTest Professional support Macintosh operating systems?
    No, QTP is not expected to run on this OS.

    16) The follow situation need to use Parentheses.

    When programming in VBscrīpt, it is important that you follow the rules for using or not using parentheses () in your statements.

    You must use parentheses around method arguments if you are calling a method that returns a value and you are using the return value. For example, use parentheses around method arguments if you are returning a value to a variable, if you are using the method in an If statement, or if you are using the Call keyword to call an action. You also need to add parentheses around the name of a checkpoint if you want to retrieve its return value.

    Tip: If you receive an Expected end of statement error message when running a step in your test, it may indicate that you need to add parentheses around the arguments of the step's method.

    Following are several examples showing when to use or not use parentheses.

    The following example requires parentheses around method arguments, since it returns a value to a variable.

    Set WebEditObj = Browser("Mercury Tours").Page("Method of Payment").WebTable("FirstName").ChildItem (8, 2, "WebEdit", 0)

    WebEditObj.Set "Example"

    The following example requires parentheses around method arguments, since Call is being used.

    Call RunAction("BookFlight", oneIteration)

    The following example requires parentheses around method arguments, since the method is used in an If statement.

    If Browser("index").Page("index").Link("All kind of").WaitProperty("attribute/readyState", "complete", 4) Then Browser("index").Page("index").Link("All kind of").Click

    The following example requires parentheses around method arguments, since it returns the value of the checkpoint.

    a = Browser("MyBrowser").Page("MyPage").Check (CheckPoint("MyProperty"))

    The following example does not require parentheses around the Click method arguments, since it does not return a value.

    Browser("Mercury Tours").Page("Method of Payment").WebTable("FirstName").Click 3,4

    17) Encrypts a string.

    In the following example, a password is taken from a database and encrypted using the Encrypt method, and then placed in the password edit box using the SetSecure method.

    pwd = "GetPasswordfromSomewhere"

    e_pwd = Crypt.Encrypt(pwd)

    Browser("dfgd").Dialog("pass").WinEdit("pwd").SetSecure e_pwd

    18) Environment object example:

    The following example uses the ExternalFileName property to check whether an environment variable file is loaded, and if not, loads a specific file and then displays one of the values from the file.

    'Check if an External Environment file is loaded and if not, load it.

    fileName = Environment.ExternalFileName

    If (fileName = "") Then

           Environment.LoadFromFile("C:\Environment.xml")

    End If

    'display value of one of the Environment variables from the External file

    msgbox Environment("MyVarName")

     

  • 转: QTP小结

    2008-04-15 22:28:09

    1.在测试中我们使用QTP调试脚本的时候一般就是DEBUG或者MSGBOX察看一些信息,其实有时候也可以使用print来实现批量的察看信息但是不影响程序运行.
    运行脚本:

    复制内容到剪贴板
    代码:
    a="100"
    print a
    ~~~~~~~~~~~~~~~~~~~~~~~~~
    2.取datatable特定行的数据可以这样使用
    运行脚本:
    复制内容到剪贴板
    代码:
    DataTable.GetSheet("Action1").GetParameter("test").ValueByRow(4)
    ~~~~~~~~~~~~~~~~~~
    3.Wait Seconds [, Milliseconds]可以精确到毫秒.
    ~~~~~~~~~~~~~~~~~~
    4.在自定义的function里面数组作为返回值.
    运行脚本:
    复制内容到剪贴板
    代码:
    circuit = "399937"
    Function trimString(circuit)
    Dim holdArray(5)
    holdArray(0) = Left(circuit, 2)
    holdArray(1) = Right(circuit, 2)
    msgbox holdArray(0) 'showed 39
    trimString = holdArray' I get an out of range error here
    End Function
    dim myArray
    'here I want to assign the return array to another array
    myArray = trimString(circuit)
    ' and then call one element from it
    msgbox myArray(1)
    ~~~~~~~~~~~~~~~
    5.计算一个操作的时间.
    运行脚本:
    复制内容到剪贴板
    代码:
    Browser("Browser").Page("Page").Image("getRates").Click
    var_StartTime = Timer
    Browser("Browser").Page("Page").Sync
    Browser("Browser").Page("Page").Check CheckPoint("Check1")
    var_EndTime = Timer
    intRespTime = round ((var_EndTime - var_StartTime), 2 )
    msgbox (intRespTime)
    ~~~~~~~~~~~~~~~
    6.取得指定sheet(datatable)的行数和列数(也可以理解为参数个数)
    复制内容到剪贴板
    代码:
    paramcount = DataTable.GetSheet("Action1").GetParameterCount
    msgbox "There are " &paramcount&"columns in the data sheet."
    rowcount = DataTable.GetSheet("Action1").GetRowCount
    msgbox "There are " &rowcount&"rows in the data sheet."
    ~~~~~~~~~~
    7.一种设置全局变量的方法GlobalDictionary
    'Part 1.
    '***********************************************************************************************************
    复制内容到剪贴板
    代码:
    Dim WshShell
    Set WshShell =CreateObject("Wscrīpt.Shell")
    WshShell.RegWrite "HKCU\Software\Mercury Interactive\QuickTest Professional\MicTest\ReservedObjects\GlobalDictionary\ProgID", "scrīpting.Dictionary","REG_SZ"
    Set WshShell = Nothing
    '*********************************************************************************************************************
    'Part 2.
    '*****************************************************************************************
    复制内容到剪贴板
    代码:
    GlobalDictionary.Add "ParamName", "ParamValue"
    Msgbox GlobalDictionary.Item("ParamName")
    GlobalDictionary.Item("ParamName")="***********"
    Msgbox GlobalDictionary.Item("ParamName")
    Msgbox GlobalDictionary.Exists("ParamName")
    GlobalDictionary.Remove("ParamName")
    Msgbox GlobalDictionary.Exists("ParamName")
    '*********************************************************************************************
    ~~~~~~~~~~~
    8.关掉多余的IE窗口
    复制内容到剪贴板
    代码:
    SystemUtil.CloseProcessByWndTitle "51testing", True
    ~~~~~~~~~~~~~~~~~~
    9.Execute 的用法,这个用法在一些特殊时候很有用的.
    复制内容到剪贴板
    代码:
    x="4"
    Execute "Dim A_" & x
    Execute "A_" & x &"=99"
    Msgbox Eval("A_" & x)  
    ~~~~~~~~~~~~~~~~~~~
    10.GetLastError的介绍,看字面就是取运行最后一个错误
    复制内容到剪贴板
    代码:
    x = GetLastError
    msgbox(DescribeResult(x))
    这样可以在程序里面判断程序运行时候是否出错了.
    ~~~~~~~~~~~~~~~~~
    11.把weblist抓图下来
    复制内容到剪贴板
    代码:
    Setting.WebPackage("ReplayType") = 2 'Default is 1
    Browser(".").Page(".").WebList(".").Click
    Desktop.CaptureBitmap "C:\Test.bmp",True
    Setting.WebPackage("ReplayType") = 1
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
    12.Reporter.ReportEvent的新用法
    transNumber = 12345
    复制内容到剪贴板
    代码:
    Reporter.ReportEvent micPass, "TransactionNumber", "<DIV style='font-size: 7pt; color: white'>&</DIV>"&"<B> <FONT COLOR=#000000>"&transNumber&"</FONT></B>"
    Reporter.ReportEvent micPass, "TransactionNumber", "<DIV style='font-size: 7pt; color: white'>&</DIV>"&"<B> <FONT COLOR=red>"&transNumber&"</FONT></B>"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
    13.For循环中step的用法
    复制内容到剪贴板
    代码:
    For K = 1 To 10 step 2
              msgbox k
    Next
    ~~~~~~~~~~~~~~~~~~~~~~~
    14.Option Explicit,大家都知道VB scrīpt里面是可以不申明变量直接使用,但是有时候我们为了脚本的规范,尽量申明使用的变量,这样你就用一下Option Explicit吧.
    复制内容到剪贴板
    代码:
    Option Explicit   ' Force explicit variable declaration.
    Dim MyVar   ' Declare variable.
    MyInt = 10   ' Undeclared variable generates error.
    MyVar = 10   ' Declared variable does not generate error.
    ~~~~~~~~~~~~~~~~~~~~~~~
    14.从TXT文件里面读取特定行的数据.
    复制内容到剪贴板
    代码:
    Dim fso, myfile,msg
    Set fso=CreateObject("scrīpting.FileSystemObject")   
    Set myfile = fso.openTextFile("C:\login.txt",1,false)
    '这里设置一个循环看需要读取第几行
    for i=1 to 10
    myfile.SkipLine
    next
    msg=myfile.ReadLine
    myfile.close
  • WCF CallBack

    2008-04-07 20:31:20

    Callback 机制又被称之为 "duplex call",说白了就是在原有基础上,为客户端也添加一个服务端点,让服务器能调用这个客户端 "服务",从而实现所谓的回调机制。也正因为如此,通讯 binding 就必须支持双向通讯能力(bidirectional-capable),通常我们会选择 WSDualHttpBinding、NetTcpBinding 以及 NetNamedPipeBinding。

    接下来,我们回忆一下 Callback 的开发步骤。

    1. 创建服务契约。
    [ServiceContract(SessionMode=SessionMode.Required)]
    public interface IService
    {
      [OperationContract]
      void Test();
    }

    2. 定义回调接口。

    由于回调接口的实现类型在客户端执行,因此无需添加 ServiceContract。
    public interface ICallBack
    {
      [OperationContract]
      void Execute(DateTime d);
    }

    3. 实现服务契约。

    我们可以使用 "OperationContext.Current.GetCallbackChannel<T>()" 来回调客户端 "Callback"。
    public class MyService : IService, IDisposable
    {
      public void Test()
      {
        Console.WriteLine("Service Invoke CallBack...");
        OperationContext.Current.GetCallbackChannel<ICallBack>().Execute(DateTime.Now);
      }

      public void Dispose()
      {
        Console.WriteLine("Dispose:{0}", DateTime.Now);
      }
    }

    4. 创建 ServiceHost。

    注意发布 Metadata。
    ServiceHost host = new ServiceHost(typeof(MyService), new Uri("http://localhost:8080/myservice"));
    host.AddServiceEndpoint(typeof(IService), new WSDualHttpBinding(), "");

    ServiceMetadatabehavīor metadata = new ServiceMetadatabehavīor();
    metadata.HttpGetEnabled = true;
    host.Descrīption.behavīors.Add(metadata);

    host.Open();

    5. 使用 Svcutil.exe 或 VS2005 创建客户端代理。
    //------------------------------------------------------------------------------
    // <auto-generated>
    //   此代码由工具生成。
    //   运行库版本:2.0.50727.42
    //
    //   对此文件的更改可能会导致不正确的行为,并且如果
    //   重新生成代码,这些更改将会丢失。
    // </auto-generated>
    //------------------------------------------------------------------------------

    namespace ConsoleApplication1.localhost
    {
      [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
      [ServiceContractAttribute(ConfigurationName = "ConsoleApplication1.localhost.IService", CallbackContract = typeof(IServiceCallback), SessionMode = SessionMode.Required)]
      public interface IService
      {
        [OperationContractAttribute(Action = "http://.../IService/Test", ReplyAction = "http://.../IService/TestResponse")]
        void Test();
      }

      [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
      public interface IServiceCallback
      {
        [OperationContractAttribute(Action = "http://.../IService/Execute", ReplyAction = "http://.../IService/ExecuteResponse")]
        void Execute(System.DateTime d);
      }

      [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
      public interface IServiceChannel : IService, IClientChannel
      {
      }

      [DebuggerStepThroughAttribute()]
      [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
      public partial class ServiceClient : DuplexClientBase<IService>, IService
      {
        public ServiceClient(System.ServiceModel.InstanceContext callbackInstance)
          : base(callbackInstance)
        {
        }

        public void Test()
        {
          base.Channel.Test();
        }
      }
    }

    6. 创建客户端回调接口的实现类型。
    class CallBack : IServiceCallback
    {
      public void Execute(DateTime d)
      {
        Console.WriteLine("Client:{0}", d);
      }
    }

    7. 为客户端自动生成的配置文件添加 clientBaseAddress。

    服务器通过这个地址调用客户端回调服务。在同一台机器上调试,注意使用一个不同的端口。
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <bindings>
          <wsDualHttpBinding>
            <binding name="WSDualHttpBinding_IService" clientBaseAddress="http://localhost:8081/" >
            </binding>
          </wsDualHttpBinding>
        </bindings>
        <client>
          <endpoint address="http://localhost:8080/myservice" binding="wsDualHttpBinding"
            bindingConfiguration="WSDualHttpBinding_IService" contract="ConsoleApplication1.localhost.IService"
            name="WSDualHttpBinding_IService">
            <identity>
              <userPrincipalName value="HZH\Administrator" />
            </identity>
          </endpoint>
        </client>
      </system.serviceModel>
    </configuration>

    8. 创建客户端调用代码。
    InstanceContext instance = new InstanceContext(new CallBack());
    using (ServiceClient client = new ServiceClient(instance))
    {
      client.Test();
    }

    运行,看看结果。你看到了什么?异常!!!
    用户代码未处理 System.InvalidOperationException
      Message="This operation would deadlock because the reply cannot be received until the current Message completes processing. If you want to allow out-of-order message processing, specify ConcurrencyMode of Reentrant or Multiple on ServicebehavīorAttribute."
      Source="mscorlib"
      StackTrace:
        Server stack trace:
          在 System.ServiceModel.Channels.ServiceChannel.PrepareCall(ProxyOperationRuntime operation, Boolean oneway, ProxyRpc& rpc)

    死锁(deadlock)?没错,你找到了让本文继续下去的理由。

    在缺省情况下,服务实例是 single-threaded (ConcurrencyMode=ConcurrencyMode.Single) 的。当服务实例调用客户端回调服务时,方法被阻塞,直到客户端回调服务消息返回(reply message)。而问题是,Single模式不允许重入调用(reentrant calls),即便系统获得返回消息,也会因为无法重入调用方法解除阻塞而造成死锁。了解了这些背景,要解决这个死锁也很简单。

    方法1: 将回调接口方法设置为 "IsOneWay=true",这样就无需处理客户端返回消息。

    为回调接口方法添加 IsOneWay。
    public interface ICallBack
    {
      [OperationContract(IsOneWay=true)]
      void Execute(DateTime d);
    }

    修改客户端代理文件,添加 IsOneWay,删除 ReplyAction。
    [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    public interface IServiceCallback
    {
      [OperationContractAttribute(IsOneWay = true, Action = "http://.../IService/Execute")]
      void Execute(System.DateTime d);
    }

    方法2: 修改服务契约的并发模式,改为 "ConcurrencyMode.Reentrant" 或 "ConcurrencyMode.Multiple"。

    和方法1不同,本方法无需对客户端做出修改。
    [Servicebehavīor(ConcurrencyMode=ConcurrencyMode.Reentrant)]
    public class MyService : IService, IDisposable
    {
      public void Test()
      {
        Console.WriteLine("Service Invoke CallBack...");
        OperationContext.Current.GetCallbackChannel<ICallBack>().Execute(DateTime.Now);
      }

      public void Dispose()
      {
        Console.WriteLine("Dispose:{0}", DateTime.Now);
      }
    }

    无论使用哪种方法,修改后再次运行,我们得到了应有的结果。

    回调机制可以用来实现类似事件通知等功能,但对于多数情况下,并不推荐使用。服务器要连接客户端实现回调,可能面临很多问题,诸如内部网络地址、防火墙等等,而且回调机制也让服务实例的生存期管理变得更复杂。
  • C# 获取本地IP地址以及MAC地址

    2008-04-06 13:39:14

    1、通过主机名获取局域网IP地址;
                try
                {
                    IPHostEntry ipHostEntry = Dns.GetHostEntry(txtHost.Text);//传递计算机名
                    if (ipHostEntry.Aliases.Length > 0)
                    {
                        foreach (string alias in ipHostEntry.Aliases)
                            txtIP.Text = alias;
                    }
                    //获取IP地址
                    foreach (IPAddress addr in ipHostEntry.AddressList)
                        txtIPAddress.Text = addr.ToString();//获取IP地址
                 }
                catch
                {
                    MessageBox.Show("错误的主机名。");
                }
    2、通过局域网IP地址获取主机名;
    try
                {
                   IPHostEntry ipHostEntry = Dns.GetHostByAddress(txtIP.Text); ;//传递IP地址
                   txtHostName.Text = ipHostEntry.HostName.ToString()//取得主机名
                }
                catch
                {
                   MessageBox.Show("错误的IP地址。");
                }
    3、通过局域网IP地址获取Mac地址
    public static string ReadMac(string ip)//传递IP地址,即可返回MAC地址
            {
                string mac = "";
                System.Diagnostics.Process p = new System.Diagnostics.Process();
                p.StartInfo.FileName = "nbtstat";
                p.StartInfo.Arguments = "-a " + ip;
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.CreateNoWindow = true;
                p.StartInfo.RedirectStandardOutput = true;            
                p.Start();
                string ōutput = p.StandardOutput.ReadToEnd();
                int len = output.IndexOf("MAC Address = ");
                if(len>0)
                {
                     mac = output.Substring(len + 14, 17);
                }            
                p.WaitForExit();            
                return mac;
            }


    4.直接获取本机IP地址
       
    string   strHostIP="";  
        IPHostEntry   ōIPHost=Dns.Resolve(Environment.MachineName);  
        if(oIPHost.AddressList.Length>0)  
        strHostIP=oIPHost.AddressList[0].ToString();  
        Console.WriteLine(strHostIP);
  • 392/2<12

    数据统计

    • 访问量: 42300
    • 日志数: 40
    • 文件数: 1
    • 建立时间: 2007-08-06
    • 更新时间: 2014-06-10

    RSS订阅

    Open Toolbar