发布新日志

  • [ZT]描述性统计与性能结果分析

    2010-09-15 13:53:22

    描述性统计与性能结果分析

    摘自:http://www.51testing.com/?uid-175815-action-spacelist-type-blog

    LoadRunner中的90%响应时间是什么意思?这个值在进行性能分析时有什么作用?本文争取用最简洁的文字来解答这个问题,并引申出“描述性统计”方法在性能测试结果分析中的应用。

     

    为什么要有90%用户响应时间?因为在评估一次测试的结果时,仅仅有平均事务响应时间是不够的。为什么这么说?你可以试着想想,是否平均事务响应时间满足了性能需求就表示系统的性能已经满足了绝大多数用户的要求?

    假如有两组测试结果,响应时间分别是 {1351016} {56789},它们的平均值都是7,你认为哪次测试的结果更理想?

    假如有一次测试,总共有100个请求被响应,其中最小响应时间为0.02秒,最大响应时间为110秒,平均事务响应时间为4.7秒,你会不会想到最小和最大响应时间如此大的偏差是否会导致平均值本身并不可信?

    为了解答上面的疑问,我们先来看一张表:

    在上面这个表中包含了几个不同的列,其含义如下:

    CmdID   测试时被请求的页面

    NUM      响应成功的请求数量

    MEAN    所有成功的请求的响应时间的平均值

    STD DEV      标准差(这个值的作用将在下一篇文章中重点介绍)

    MIN              响应时间的最小值

    50 th(60/70/80/90/95 th)          如果把响应时间从小到大顺序排序,那么50%的请求的响应时间在这个范围之内。后面的60/70/80/90/95 th 也是同样的含义

    MAX      响应时间的最大值

    我想看完了上面的这个表和各列的解释,不用多说大家也可以明白我的意思了。我把结论性的东西整理一下:

    1.      90%用户响应时间在 LoadRunner中是可以设置的,你可以改为80%或95%;

    2.      对于这个表,LoadRunner中是没有直接提供的,你可以把LR中的原始数据导出到Excel中,并使用Excel中的PERCENTILE 函数很简单的算出不同百分比用户请求的响应时间分布情况;

    3.      从上面的表中来看,对于Home Page来说,平均事务响应时间(MEAN)只同70%用户响应时间相一致。也就是说假如我们确定Home Page的响应时间应该在5秒内,那么从平均事务响应时间来看是满足的,但是实际上有10-20%的用户请求的响应时间是大于这个值的;对于Page 1也是一样,假如我们确定对于Page 1 的请求应该在3秒内得到响应,虽然平均事务响应时间是满足要求的,但是实际上有20-30%的用户请求的响应时间是超过了我们的要求的;

    4.      你可以在95 th之后继续添加96/ 97/ 98/ 99/ 99.9/ 99.99 th,并利用Excel的图表功能画一条曲线,来更加清晰表现出系统响应时间的分布情况。这时候你也许会发现,那个最大值的出现几率只不过是千分之一甚至万分之一,而且99%的用户请求的响应时间都是在性能需求所定义的范围之内的;

    5.      如果你想使用这种方法来评估系统的性能,一个推荐的做法是尽可能让你的测试场景运行的时间长一些,因为当你获得的测试数据越多,这个响应时间的分布曲线就越接近真实情况;

    6.      在确定性能需求时,你可以用平均事务响应时间来衡量系统的性能,也可以用90%或95%用户响应时间来作为度量标准,它们并不冲突。实际上,在定义某些系统的性能需求时,一定范围内的请求失败也是可以被接受的;

    7.      上面提到的这些内容其实是与工具无关的,只要你可以得到原始的响应时间记录,无论是使用LoadRunner还是JMeter或者OpenSTA,你都可以用这些方法和思路来评估你的系统的性能。

     

    事实上,在性能测试领域中还有更多的东西是目前的商业测试工具或者开源测试工具都没有专门讲述的——换句话说,性能测试仅仅有工具是不够的。我们还需要更多其他领域的知识,例如数学和统计学,来帮助我们更好的分析性能数据,找到隐藏在那些数据之下的真相。

  • 【转】常用软件缺陷预防技术和缺陷分析技术有哪些?

    2010-07-19 13:23:21

    常用软件缺陷预防技术缺陷分析技术有哪些?(08-06-13)(获奖名单已公布)

    【引题】请介绍常用软件缺陷预防技术和缺陷分析技术有哪些?希望在常用方法上提出一些新的观点或自己独到的观点?

    【题外话】对于这个问题,我一点思路都没有,只知道软件测试的目的就是尽早的尽可能地找出软件缺陷,从而保证软件的质量。尽早地参与,尽可能多的去发现问题。这只是原则,但是对于方法,我知之甚少,一方面,没有经过系统的学习和培训,也没有专人指导,工作经验一年多点,但也仅限于一些基本的功能测试。整理了大家的精彩回答作为学习源。

    【正题】Zhuzx这个会思考又有经验的人,是这个问题的提出者,源于他面谈一家公司的测试经理的时候,被总监和老总问的问题,当然了,他的回答也很详细!看了之后,我不知道这些方法能有多少会被经常用到的呢:)

    常用的主要缺陷分析技术如下:
    1)、散布图:2)、柱状图:3)、饼图:4)、折线图:

    常用的软件缺陷分析方法:
    1)、缺陷分布报告:
    通过对功能上的分布情况进行分析,可以了解哪些模块处理比较难,哪些模块程序质量比较差,有利于程序质量的改进和提高。缺陷起源分布报告,显示了缺陷的根本原因上的分布情况,这种分析会帮助程序代码质量的改进。
    2)、缺陷趋势报告:
    一个产品的开发过程,一般都会遵循一种比较接近的模式向前发展。在生命周期的初期,缺陷率增长较快。在到达顶峰以后,就随时间以较慢的速度下降。同时,缺陷趋势分析,还可以延伸用来评估开发所做的努力,同时也是判断测试完成标准的重要基础。
    3)、缺陷年龄报告:
    缺陷年龄报告是一种特殊类型的缺陷分布报告,显示缺陷目前的活动(NewRejectOpenFixReopenSuspendedClosed)状态的时间,展示一个缺陷处于某种状态的时间长短,从而了解处理这些缺陷的时间进度情况。通过发现的缺陷数量和关闭的缺陷数趋势图,找到缺陷的收敛点,来预测产品下一个阶段的测试计划。
    4)、测试结果进度报告:
    展示测试在被测应用的几个版本中的执行结果以及测试周期,显示对应用程序进行若干次迭代和测试生命周期后的测试过程执行结果。

    针对目前项目的实际情况,主要的缺陷预防方法如下:
    1)、重点评审需求中不明确的功能模块和存在分歧的模块:
    2)、根据需求开发Demo,让测试人员和用户确认:
    3)、业务功能交叉的模块,最好做好代码走查:
    4)、开发过程和需求更新要及时监控,并形成文档:
    5)、对用户业务场景常用的模块,要重点评审;
    6)、制定一个比较规范的测试规范;

    针对目前软件企业的现状我总结的缺陷预防方法如下:

    1、采用Demo技术设计低缺陷需求:
       
    随着软件开发新技术的飞速发展和业务需求的不断增加,一般来说,软件业务比较复杂,单靠客户代表通过文字讲清全部的需求比较困难,并且也不太现实。加之开发方和客户在一些文字上理解的差异性,也就导致了开发方开发的需求和用户的实际需求相差越来越远,到最后缺陷也许就无法修复。
       针对目前需求的实际情况,我们通常把业务的常用模块、关键模块和核心模块做成Demo让用户确认,让用户真实体验使用软件的真是感受,如果发现使用不方便或者效果不佳,马上修改方案,减少许多不必要的损失。

    2、采用统一的编码技术开发源代码:

      由于软件开发工作性质的特殊性,加之编码工作都属于脑力劳动,特别具有个性。软件的编码,对于从事软件程序开发的程序员来说,编程语言掌握的熟练程度和对编程思想的理解不同,决定不同编程人员的编程习惯上的差别。如果没有一个统一的代码风格,那么一个程序员的变动,也许就会导致另外一个程序员看不懂,给维护也带来较大的困难,因此,统一的代码规范(如:Windows命名规则、GNU命名规则和习惯以及函数处理规则等等)就显得非常重要。
      在有了良好的代码风格那是远远不够的,还必须有统一的编码规范(如C++规范、Java规范等)来提高代码的质量,让所有的开发人员都学习该规范,达成统一共识,严格按照规范编写程序。

    3、采用技术评审手段减少缺陷产生:

       技术评审作为软件开发生命周期中的一中非常重要的手段,理论上来说可以减少缺陷。我们可以通过对开发过程中的每一个阶段,进行评审来保证产品的质量。
      对客户和开发方的需求确定以后,需要客户代表和开发方对需求规格说明书进行评审,修改不合理需求或理解有分歧的需求后,再最终定稿需求。接下来就是对开发方重点评审需求分析人员编写的概要设计文档和开发人员编写的详细设计文档。对于测试人员编写的单元测试、集成测试和系统测试文档,包括测试计划、测试用例和测试报告,都必须有开发人员、测试人员、项目经理和需求分析人员等人的共同评审。只有不断修改评审后的文档,才会起到缺陷减少的目的。

    4、采用成熟的开发技术和开发工具:

    软件开发过程中缺陷的引入,大多数是在使用新的开发工具和新技术的情况下产生的。由于大部分的开发人员对一些新技术的认识和了解不够,加上开发时间的压力,缺乏新开发工具的使用经验开发人员不得不加班加点,学习和探索新技术,追赶开发进度,导致大量的缺陷被引入软件中。
       采用成熟的开发技术和开发工具,加上相关设计人员和开发人员丰富的经验,能够较大限度的避免缺陷的发生。

    5、采用单元测试技术降低软件缺陷:

      单元测试是软件测试中一个比较关键的阶段,根据项目的实际经验,大约有50%80%的缺陷,都可以通过单元测试发现,并立即消除。通过单元测试这样一个非常重要的环节,规范单元测试流程,切实做好单元测试,提高单元测试技巧,更高更好的完成软件测试工作。

    这个人又很好学,回答完这个问题又回去“翻书”找了更为详尽的答案,作为补充,我也一并收藏

    常用的统计分析工具:
    1)散布图:
    散布图通常作为研究因果关系的一部分,是考察数据的第一步。有时假定一个变量是独立的,另一个变量是非独立的。当系统处于稳定状态时,散布图通常是回归分析的前导,当它显示二个变量之间存在某种关系时,可紧接着采用更正式的统计方法。
    2)运行图:
    是散布图的时间序列表,可用于快速检验数据和非正式地显示在一个时间段中的趋势。它非常像控制图,但没有界限和中心线。
    运行图能用于监视一个过程的趋势或过程变化的情况,如:产量、产品规模、团队大小、发现的缺陷数、库存、累计或每日的消耗等。能真实地显示任何时间段或范围的情况。
    3)因果图:
    也称鱼刺图或石川图,创建于1943年。用于表述、图解和区分一个特殊过程、问题或结果的因果关系,了解什么是可能引发问题的原因。因果图通常是由集体讨论时绘制的。虽然因果图具有主观的因素,但它是基于实际的信息的,如度量值和问题出现的日期。
    因果图分为三类:
    偏差分析因果图――它是通过反复提问为什么会出现偏差?来建立的。它的强项是帮助理清引起产品或其它过程偏差的因素。不足是依赖个人的观点,有可能引入次要因素。
    生产过程分类因果图――它是通过生产过程的步骤了建立的。通过1)将每一步原因设置在鱼刺的主要肋骨上,2)在背瘠上画一个方框,每个框中是一个生产步骤。它的强项是容易汇总和明了,不足是类似的原因可能出现在多个地方,使问题的结果难于描述。
    原因枚举因果图――首先列出所有可能的在产品或过程质量方面的原因,然后将它们组织起来表示它们之间的关系,这些可能的因素可由头脑风暴法产生。它的强项是可以枚举大量的可能的原因,减少忽视主要问题的可能性。只要做得好,能产生更为完整的结果。它的不足是树的树梢难于整合到结果中去。
    4)柱状图(直方图、频数分布图)
    能显示经验观察结果的分布情况,显示给定观察时间段内出现的事件的频率。可用于刻划任何过程或产品属性的观察值,如,模块大小、Bug的修复时间、两个故障间的时间、每次测试或检查发现的缺陷数、每天的订单等。对揭示过程、项目、或时间中的差异很有帮助。它能显示频率计数,容易比较分布情况和看到主要趋势与偏差。具体算法:
    1)收集数据(数据越多越能说明问题);
    2)计算极差RXmaxXmin
    3)确定分组数:50100个数据,分为610组;100250个数据,分为712组;250以上,分为1020组;
    4)确定测定值最小单位,如:2
    5)计算组间距:HR/组数;
    6)计算第1组的下限值:Xmin-测定值最小单位/2; 第2组的下限值=第1组的下限值+组间距;
    7)计算组中心值=(组上限值+组下限值)/2
    8)计算频数表:
    9)画柱状图;
    10)分析过程状态:
    正常型,服从正态分布;
    偏向型,可能由习惯作业造成;
    双峰型,可能来自两个总体的数据混在一起;
    孤岛型,可能由于短时间的异常因素作用所致;
    低峰型,可能由于过程中某种倾向性因素缓慢作用所致;
    高峰型,可能数据经过筛选;
    5)条形图:
    大部分情况类似柱状图,但它不需要连续的测量或频数计数,是基于离散的范围的数据。用于研究数据集的形态,显示确定实体、产品集或过程中相关的总的规模、成本、和消耗的时间。
    6Pareto图:
    称佩瑞多图,佩瑞多(18481923意大利经济学家和社会学家)。它是柱形图或条形图的一种特殊形式。对发现分类的问题、原因、依据总量的活动、出现的频率、或经济结果很有帮助。对于组织从众多的事件中分离出主要的少数事件,将采取何种高优先级的改进活动提供帮助,有助于明确哪一类缺陷应该特别关注?所检测到的问题中,哪一个部分贡献最大?
    Pareto图一般采取降序的方式显示频率计数或总量。它总是与相应的时间段相关,时间界限必须清楚;它对用于比较改进措施采取的前后状态是敏感的。但如果过程不稳定,可能导致错误的结论。
    7)检查表:
    分析识别方法
    写出所有问题的清单
    按重要性整理这个清单
    识别出重要少数(Vital few
    识别出不重要多数(Trivial many)

    天网作为版主,也给出了自己简明的见解:

    常见缺陷分析技术
    1ODC缺陷分析:由IBMwaston中心推出。将一个缺陷在生命周期的各环节的属性组织起来,从单维度、多维度来对缺陷进行分析,从不同角度得到各类缺陷的缺陷密度和缺陷比率,从而积累得到各类缺陷的基线值,用于评估测试活动、指导测试改进和整个研发流程的改进;同时根据各阶段缺陷分布得到缺陷去除过程特征模型,用于对测试活动进行评估和预测。上面回答中涉及到的缺陷分布、缺陷趋势等都属于这个方法中的一个角度而已。
    2Gompertz分析:根据测试的累积投入时间和累积缺陷增长情况,拟合得到符合自己过程能力的缺陷增长Gompertz曲线,用来评估软件测试的充分性、预测软件极限缺陷数和退出测试所需时间、作为测试退出的判断依据、指导测试计划和策略的调整;
    3Rayleigh分析:通过生命周期各阶段缺陷发现情况得到缺陷Rayleigh曲线,用于评估软件质量、预测软件现场质量;
    4、四象限分析:根据软件内部各模块、子系统、特性测试所累积时间和缺陷去除情况,和累积时间和缺陷去除情况的基线进行比较,得到各个模块、子系统、特性测试分别所位于的区间,从而判断哪些部分测试可以退出、哪些测试还需加强,用于指导测试计划和策略的调整;
    5、根本原因分析:利用鱼骨图、柏拉图等分析缺陷产生的根本原因,根据这些根本原因采取措施,改进开发和测试过程;
    6、缺陷注入分析:对被测软件注入一些缺陷,通过已有用例进行测试,根据这些刻意注入缺陷的发现情况,判断测试的有效性、充分性,预测软件残留缺陷数。在06年软件评测师考试中有一题就是考这个思路,参见这个帖子我的回复:http://bbs.51testing.com/thread-114979-1-1.html
    7DRE/DRM分析:通过已有项目历史数据,得到软件生命周期各阶段缺陷注入和排除的模型,用于设定各阶段质量目标,评估测试活动.

    至于缺陷预防,基本上是两个方面:
    1、测试活动尽量提前,通过及时消除开发前期阶段引入的缺陷,防止这些缺陷遗留并放大到后续环节;
    2、通过对已有缺陷进行分析(例如上面的ODC分析等),找出产生这些缺陷的技术上不足和流程上不足,通过对这些不足进行改进,防止类似缺陷再次发生。

    超级版主fengyun32从分析Bug根源的角度给出自己的阐释。

    bug预防策略
       我们的策略是发现bug,找出bug的根源,然后寻找一个方法来预防类似的bug在将来出现。因为QC过程已经用于在目前的产品中发现bug,因此该策略的大部分工作实际上已经执行,大多数开发过程缺少的正是分析在QC过程中发现的bug。正如你将看到,尽管策略的这一部分并不需要昂贵的花费,但是却带来了极大的额外价值。
    分析过程
    (1) Bug发现和初步分析
       如前所述,bug分析的第一步是发现bug。然而,发现bugQC工程师(注:测试工程师)不应该满足于记录bug的表面症状。QC工程师的一个重要职责就是试图发现bug的根本原因。QC小组在检验产品质量时,不应该将产品看作一个黑盒,而应该像开发人员那样了解产品的内在,包括深入源代码,理解产品的设计和实现。这些能力都是QC小组开始bug分析的基本要求。熟悉了产品的代码,QC工程师就可能推测出bug的根本原因。我要强调是下面这个短语的本质:bug的根本原因?bug的根本原因并不是产生这bug的源代码所在,尽管这些信息可能和分析过程关系密切。但是,发现bug的根本原因意味着找到造成这些错误的原因。通过一些实例来说明这个问题可能更清楚一些。
       让我们看一个普遍存在的关于线程同步的问题。假设一个多线程的应用程序需要同步地访问某个数据结构。被指派测试这个产品的QC工程师发现在某种情景下,应用程序尽管没有Crash,但是会停止响应。正常的QC过程是,这个bug被记录在bug跟踪系统中,并描述了测试情景和停止响应的实际结果。然而,如果这个QA工程师熟悉源代码,就可以进行bug产生原因的初步分析。例如,这个QC工程师可能断定这个bug产生的原因是之前的线程没有释放mutex,从而造成了冲突。这些分析可以记录在bug的详细说明中,作为bug分析的一个基础。
    (2) Bug修订和进一步分析
       一如既往,发现一个bug之后,开发人员应该负责处理它。但是,如果bug的发现过程包含了bug根本原因的初步分析,那么关于如何解决这个bug,开发人员可能拥有了更多的信息。虽然这不是QC工程师bug初步分析的目的,但是它可能为开发人员提供了更多的观点。除了修正缺陷以及记录实现的具体步骤,开发人员还应该对bug进行进一步的分析。这次分析应该着眼于导致bug产生的开发情景。
       在线程同步的例子中,开发人员不应该仅仅记录增加了一个调用来释放mutex(注:Mutal Exclusion =互斥锁,保证了共享数据不会同时被多个线程访问,只向一个线程授予对共享资源的独占访问权)。反之,开发人员应该找出没有释放mutex的原因。假设分析的原因是:因为需要同步的方法超过一个的返回点,因此开发人员在某些控制路径上忘记清理代码。
       这一类简单的分析实际带来了非常大的价值。不同于记录具体问题的具体解决办法,我们现在有了可以解决许多情况的经验,有些情况甚至并不涉及到线程同步和释放mutex。但是,分析过程并没有结束,我们需要进一步的分析来将收集的所有数据转换为实践,从而帮助在将来避免类似bug的发生。
    (3) bug预防分析
       分析的最后一步就是寻找一个预防类似错误的方法。这一方法不仅涉及到开发、QC工程师,还涉及到不直接负责代码编写的资深开发人员。
       这一阶段的成果是一些有用的实践经验,开发人员可以通过这些实践预防bug而不是修正bug。这些实践不应该是某个具体问题的解决方案。在我们线程同步的例子中,可能得到这样一个实践:是否有审计范围机制来获取和释放资源?这种实践(不一定适合所有编程语言)可以指导开发人员用一个类(class)封装资源,这样构造(constructor)函数容易分配和而与析构(destructor)函数释放资源。如果遵守这样的约定,当程序结束这方法时,不管控制路径是怎样的,资源(上述例子中获得的mutex)总能被释放。
        Bug预防分析是整个bug分析过程的核心。这一阶段总结出的实践可以在更广泛的范围内预防潜在的缺陷。由于分析结果的广泛应用性,分析某个具体问题的投入将很容易被收回。
       非常重要的是我们前面所举的例子是一个随机性的bug。开发人员由于疏忽而忘记了释放资源。在代码实现时,这样的bug是随机产生的,但是类似bug产生的几率却非常高。所以,尽管这一类bug是随机的,但仍然可以被预见并防止发生。
    (4)发布经验
       分析得出的实践经验应该被记录并发布,这样其他的开发人员就可以通过学习这些经验避免类似的错误。一个发布经验最好的办法就是知识库。这将使得新的知识在组织内流动并被相关的开发人员所学习。
       如果不将分析结果传达给组织内相关的其他人员,那么分析的目的就没有达到。避免下一个bug出现的唯一办法就是让开发人员知道如何避免它,并鼓励他们这么做。
    Bug分析实例
       让我们研究另外一个例子,以便更好地理解bug分析的益处。在这个事例中,QC工程师进行了如下的操作:当输入一个长字符串到应用程序时造成其崩溃(crash)。这一结论本身就需要一定程度的分析,但这个QC工程师并不满足于这样的分析,进一步研究了相关的代码,发现crash的原因是输入字符串时的处理有问题。其中一个步骤是将输入的字符缓存在一个固定大小的数组中,而这个数组有时候显得太小了。和线程同步的例子一样,QC工程师的初步分析带来了很大的价值,开发可以更容易的发现和修正这个bug。此外,记录缺陷的真正原因而不是表象,将帮助其他人避免类似的bug
       接着,开发人员开始修正这个bug。当修正的时候,她不仅记录了解决措施,并说明了导致缺陷产生的原因。在这个例子中,造成bug的原因是在操作未经处理的C/C++缓冲区时,没有经常检验缓冲区的大小是否不够。然而,这个结论甚至可以被进一步总结为更广泛应用的经验以便帮助开发人员在以后避免类似的缺陷发生。所以,在分析的最后阶段,开发人员在组内更资深的开发人员的帮助下,得到了下面的实践经验:避免使用未经处理的C/C++缓冲区,尽量使用安全的collectionsstrings,如标准模版数据库中提供的可用collectionsstrings。这样就完全可以避免前面发现的这个bug
    益处
        Bug分析带来了很多的好处。第一个好处就是帮助产生错误的开发人员总结经验,并使他在将来避免类似的错误。有时,只修正一个具体的bug而不去分析它产生的原因并不会帮助在日后得到提高。在这种情况下,只有深入分析和资深开发人员的指导才能使开发人员成长和提高能力。
       更广泛的好处是使得其他开发人员从同事的错误中吸取教训。分析总结的实践经验可以预防bug的产生,这样的知识在组织内的成员间共享。某个开发人员产生的bug可以帮助组织内的其他人避免类似的bug出现。
       从更一般的角度来看,发布最佳实践(如bug分析总结的实践)促进了组织内成员的学习和自我提高。这样看来,Bug分析的价值还不仅仅是缺陷的预防。
       另一个好处是通过从更广的角度上记录bug,组织内的其他QC工程师将知道如何发现类似的错误。除了分享组织内的测试知识和经验,bug分析过程可以促进开发更好的测试技术和工具,从而帮助发现类似的bug。所以,就算缺陷没有被完全预防,也能更容易被发现。
       作为上面所有好处的结果,QC在一轮测试中将有更多的时间来测试更复杂的情景并发现更狡猾的”bug。如果类似的bug都已经被预防而不容易产生,而且QC都有更好的技术来发现类似的bug,就有了更充裕的时间来进行更高级的测试。当然,组织所生产的产品的质量也将得到提高。
       最后,我想强调的是bug分析不仅收集了执行中的问题,而且从这些问题中总结了实践经验。举例来说,导致一个bug产生的原因可能是需求不够清楚。这样,通过bug分析得到的经验提供了一种方法来预防需求不清楚。这个经验可能不会对组织中的开发人员产生效果。所以尽管QC工程师开始验证开发人员的实现结果,但是还需要改善开发流程,如需求收集、设计流程等。
       真正的质量是生产没有bug的产品。任何其他目标都使组织内的成员从思想上接受软件缺陷是正常工作流的一部分。所以,第一步就是防止相同的bug再次发生。我们可以很轻易地执行这个目标。我们可以通过某个开发人员产生的一个bug提高整个组织的实践经验

  • 对apache中并发控制参数prefork理解和调优

    2009-03-25 13:32:40

    转载自:扶凯[http://www.php-oa.com]

    本文链接: http://www.php-oa.com/2008/02/22/prefork.html

     

    一个apache有linux下的并发不是很高的,大约到3K的样子(其实处理的http的请求可能只有300/s),普通的服务器都会不同程度的出现问题.apache有关并发控制主要是 prefork和worker二个其中一个来控制.我们可以使用httpd -l来确定当前使用的MPM是prefork.c,还是Worker.c.下面是apache中有关prefork的配置.下面是我优化过的参数.

    <IfModule prefork.c>

    #有这个参数就不必像apache1一样修改源码才能修改256客户数的限制,听讲要放到最前面才会生效,2000是这个参数的最大值
    ServerLimit 2000
    #指定服务器启动时建立的子进程数量,prefork默认为5。
    StartServers 25

    #指定空闲子进程的最小数量,默认为5。如果当前空闲子进程数少于MinSpareServers ,那么Apache将以最大每秒一个的速度产生新的子进程。此参数不要设的太大。
    MinSpareServers 25

    #设置空闲子进程的最大数量,默认为10。如果当前有超过MaxSpareServers数量的空闲子进程,那么父进程将杀死多余的子进程。此参数 不要设的太大。如果你将该指令的值设置为比MinSpareServers小,Apache将会自动将其修改成"MinSpareServers+1"。
    MaxSpareServers 50

    #限定同一时间客户端最大接入请求的数量(单个进程并发线程数),默认为256。任何超过MaxClients限制的请求都将进入等候队列,一旦一个链接被释放,队列中的请求将得到服务。要增大这个值,你必须同时增大ServerLimit 。
    MaxClients 2000

    #每个子进程在其生存期内允许伺服的最大请求数量,默认为10000.到达MaxRequestsPerChild的限制后,子进程将会结束。如果MaxRequestsPerChild为"0",子进程将永远不会结束。
    MaxRequestsPerChild 10000

    </IfModule>

    将MaxRequestsPerChild设置成非零值有两个好处:
    1.可以防止(偶然的)内存泄漏无限进行,从而耗尽内存。
    2.给进程一个有限寿命,从而有助于当服务器负载减轻的时候减少活动进程的数量。

    工作方式:
    一个单独的控制进程(父进程)负责产生子进程,这些子进程用于监听请求并作出应答。Apache总是试图保持一些备用的 (spare)或者是空闲的子进程用于迎接即将到来的请求。这样客户端就不需要在得到服务前等候子进程的产生。在Unix系统中,父进程通常以root身 份运行以便邦定80端口,而 Apache产生的子进程通常以一个低特权的用户运行。User和Group指令用于设置子进程的低特权用户。运行子进程的用户必须要对它所服务的内容有 读取的权限,但是对服务内容之外的其他资源必须拥有尽可能少的权限。

    对上面的有些值,一定要记的不是越大越好.这个需要经过几次尝试和出错之后才能选好要使用的值(不同的硬件处理水平不一样)。最重要的值是maxclient允许足够多的 工作进程,同时又不会导致服务器进行过度的交换(死机)。如果传入的请求超出处理能力而让服务器当掉的话,那么至少满足此值的那些请求会得到服务,其他请求被阻塞这样会更加好。

     

    我们调优常常要查看httpd进程数(即prefork模式下Apache能够处理的并发请求数)

    #ps -ef | grep httpd | wc -l

    出现的结果,就是当前Apache能够处理的多少个并发请求,这个值Apache根据负载情况自动调.

    查看Apache的并发请求数及其TCP连接状态:

    #netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

    上面这句来自己我一个新浪的朋友张宴.

    返回结果示例:
    LAST_ACK 5
    SYN_RECV 30
    ESTABLISHED 1597
    FIN_WAIT1 51
    FIN_WAIT2 504
    TIME_WAIT 1057
    其中的SYN_RECV表示正在等待处理的请求数;ESTABLISHED表示正常数据传输状态;TIME_WAIT表示处理完毕,等待超时结束的请求数。

    状态:描述
    CLOSED:无连接是活动的或正在进行
    LISTEN:服务器在等待进入呼叫
    SYN_RECV:一个连接请求已经到达,等待确认
    SYN_SENT:应用已经开始,打开一个连接
    ESTABLISHED:正常数据传输状态
    FIN_WAIT1:应用说它已经完成
    FIN_WAIT2:另一边已同意释放
    ITMED_WAIT:等待所有分组死掉
    CLOSING:两边同时尝试关闭
    TIME_WAIT:另一边已初始化一个释放
    LAST_ACK:等待所有分组死掉

    可以使用Linux下的webbench来作压力测试.

    更新日期:08年9月28日.

  • 学习日志_20090120_退出循环

    2009-01-21 17:21:37

    8.ExitAction - 退出当前操作,无论其循环属性如何。
      ExitActionIteration - 退出操作的当前循环。
      ExitRun - 退出测试,无论其循环属性如何。
      ExitGlobalIteration - 退出当前全局循环。
  • QTP学习日记_20090121

    2009-01-21 16:57:10

    以下是《摘抄》,非原创

    QTP中WebElement对象的赋值

    由于一般web上面的编辑控件,QTP都识别成WebElement对象,所以在编辑框中输入的内容,QTP没有录制下来,以下代码实现了WebElement的赋值:

    Dim MyWebElement

    Set MyWebElement = Browser("Tencent BBS V3.1_2").Page("Community Server - 回复内容").Frame("Frame").WebElement("WebElement").Object


    MyWebElement.innerHTML = "替换成要输入的内容即可"

    -------------------------------------

    QTP中对识别为WebElement的对象进行输入操作的一种解决办法

        在设计自动化框架的过程,发现了一些被QTP识别为WebElement的对象,需要对其进行输入操作;而WebElement只有click方法,是没有输入的方法的。
        考虑了实际中确实需要具有这种输入的支持(比如利用js生成的输入框,比较常见的是HTML编辑器输入框),就着手去解决。找到了一种解决办法:利用WshShell对象的SendKey方法来实现。在网上找了个html代码编辑器的实例,实现具体代码如下:

    Option Explicit

    Dim oWin32

    Set oWin32 = CreateObject("wscrīpt.shell")

    oWin32.Run("http://www.ewebeditor.net/demo/")

    '由于html编辑器输入框没有找到稳定的属性用于识别,QTP录制时也没有录下对其操作,所以采用先将焦点移到其上一个对象,再按tab移动焦点到html编辑器上
    Browser("title:=.*eWebEditor").page("title:=.*eWebEditor").WebList("name:=select","index:=0").FireEvent "onfocus"
    '对IE窗口模拟键盘输入操作
     With oWin32
      .sendkeys "{TAB}"
      wait 2
      .sendkeys "ksadjflonfocusksjdlemowstitlitoWebLeEvenfocusonfocusonfocusonfocusonfocusonfocusonfocusdsjflkjdsklfjlkdsjf"
     End With

        以上是我想到的一种实现方式,也是目前正在使用的方式。但只是一个不得已的解决方法——因为这种方式是很脆弱的,焦点变动,甚至一个Windows消息提示都可能使脚本失败。

        欢迎交流更好的解决思路!

     

  • [转]一些t-sql技巧

    2008-08-06 13:23:22

    摘自 http://www.51testing.com/html/200807/n88553.html

      一、 只复制一个表结构,不复制数据 

    select top 0 * into [t1] from [t2]
     

      二、 获取数据库中某个对象的创建脚本

      1、 先用下面的脚本创建一个函数

      if exists(select 1 from sysobjects where id=object_id('fgetscrīpt') and objectproperty(id,'IsInlineFunction')=0)
      drop function fgetscrīpt
      go

      create function fgetscrīpt(
      @servername varchar(50)    --服务器名
       @userid varchar(50)='sa'    --用户名,如果为nt验证方式,则为空
      @password varchar(50)=''    --密码
      @databasename varchar(50)    --数据库名称
      @objectname varchar(250)    --对象名

      ) returns varchar(8000)
      as
      begin
      declare @re varchar(8000)        --返回脚本
      declare @srvid int,@dbsid int      --定义服务器、数据库集id
      declare @dbid int,@tbid int        --数据库、表id
      declare @err int,@src varchar(255), @desc varchar(255) --错误处理变量

      --创建sqldmo对象
      exec @err=sp_oacreate 'sqldmo.sqlserver',@srvid output
      if @err <>0 goto lberr

      --连接服务器
      if isnull(@userid,'')='' --如果是 Nt验证方式
      begin
      exec @err=sp_oasetproperty @srvid,'loginsecure',1
      if @err <>0 goto lberr

      exec @err=sp_oamethod @srvid,'connect',null,@servername
      end
      else
        exec @err=sp_oamethod @srvid,'connect',null,@servername,@userid,@password

      if @err <>0 goto lberr

      --获取数据库集
      exec @err=sp_oagetproperty @srvid,'databases',@dbsid output
      if @err <>0 goto lberr

      --获取要取得脚本的数据库id
      exec @err=sp_oamethod @dbsid,'item',@dbid output,@databasename
      if @err <>0 goto lberr

      --获取要取得脚本的对象id
      exec @err=sp_oamethod @dbid,'getobjectbyname',@tbid output,@objectname
      if @err <>0 goto lberr

      --取得脚本
      exec @err=sp_oamethod @tbid,'scrīpt',@re output
      if @err <>0 goto lberr

      --print @re
      return(@re)

      lberr:
      exec sp_oageterrorinfo NULL, @src out, @desc out
      declare @errb varbinary(4)
      set @errb=cast(@err as varbinary(4))
      exec master..xp_varbintohexstr @errb,@re out
      set @re='错误号: '+@re 
        +char(13)+'错误源: '+@src 
        +char(13)+'错误描述: '+@desc
      return(@re)
      end
      go

      2、 用法如下

      print dbo.fgetscrīpt('服务器名','用户名','密码','数据库名','表名或其它对象名')

      3、 如果要获取库里所有对象的脚本,如如下方式

      declare @name varchar(250)
      declare #aa cursor for
      select name from sysobjects where xtype not in('S','PK','D','X','L')
      open #aa
      fetch next from #aa into @name
      while @@fetch_status=0
      begin
      print dbo.fgetscrīpt('onlytiancai','sa','sa','database',@name)
      fetch next from #aa into @name
      end
      close #aa
      deallocate #aa

      4、 声明,此函数是csdn邹建邹老大提供的

      三、 分隔字符串

      如果有一个用逗号分割开的字符串,比如说"a,b,c,d,1,2,3,4",如何用t-sql获取这个字符串有几个元素,获取第几个元素的值是多少呢?因为t-sql里没有split函数,也没有数组的概念,所以只能自己写几个函数了。

      1、 获取元素个数的函数

      create function getstrarrlength (@str varchar(8000))
      returns int
      as
      begin 
        declare @int_return int 
        declare @start int 
        declare @next int 
        declare @location int 
        select @str =','+ @str +',' 
        select @str=replace(@str,',,',',') 
        select @start =1 
        select @next =1 
        select @location = charindex(',',@str,@start) 
        while (@location <>0) 
        begin 
          select @start = @location +1 
          select @location = charindex(',',@str,@start) 
          select @next =@next +1 
        end
      select @int_return = @next-2
      return @int_return
      end

      2、 获取指定索引的值的函数

      create function getstrofindex (@str varchar(8000),@index int =0)
      returns varchar(8000)
      as
      begin 
        declare @str_return varchar(8000) 
        declare @start int 
        declare @next int 
        declare @location int 
        select @start =1 
        select @next =1 --如果习惯从0开始则select @next =0 
        select @location = charindex(',',@str,@start) 
        while (@location <>0 and @index > @next ) 
        begin 
          select @start = @location +1 
          select @location = charindex(',',@str,@start) 
          select @next =@next +1 
        end 
        if @location =0 select @location =len(@str)+1 --如果是因为没有逗号退出,则认为逗号在字符串后 
        select @str_return = substring(@str,@start,@location -@start) --@start肯定是逗号之后的位置或者就是初始值1 
        if (@index <> @next ) select @str_return = '' --如果二者不相等,则是因为逗号太少,或者@index小于@next的初始值1。 
        return @str_return
      end

      3、 测试

      SELECT [dbo].[getstrarrlength]('1,2,3,4,a,b,c,d')
      SELECT [dbo].[getstrofindex]('1,2,3,4,a,b,c,d',5)

      四、 一条语句执行跨越若干个数据库
      我要在一条语句里操作不同的服务器上的不同的数据库里的不同的表,怎么办呢?
      第一种方法:

      select * from OPENDATASOURCE('SQLOLEDB','Data Source=远程ip;User ID=sa;Password=密码').库名.dbo.表名

      第二种方法:
      先使用联结服务器:

      EXEC sp_addlinkedserver '别名','','MSDASQL',NULL,NULL,'DRIVER={SQL Server};SERVER=远程名;UID=用户;PWD=密码;'
      exec sp_addlinkedsrvlogin  @rmtsrvname='别名',@useself='false',@locallogin='sa',@rmtuser='sa',@rmtpassword='密码'
      GO

      然后你就可以如下:

      select * from 别名.库名.dbo.表名
      insert 库名.dbo.表名 select * from 别名.库名.dbo.表名
      select * into 库名.dbo.新表名 from 别名.库名.dbo.表名
      go

      五、 怎样获取一个表中所有的字段信息
      蛙蛙推荐:怎样获取一个表中所有字段的信息
      先创建一个视图

      Create view fielddesc   
      as
      select o.name as table_name,c.name as field_name,t.name as type,c.length as

      length,c.isnullable as isnullable,convert(varchar(30),p.value) as desp
      from syscolumns c 
      join systypes t on c.xtype = t.xusertype
      join sysobjects o on o.id=c.id
      left join    sysproperties p on p.smallid=c.colid and p.id=o.id   
      where o.xtype='U'


      查询时:

      Select * from fielddesc where table_name = '你的表名'


      还有个更强的语句,是邹建写的,也写出来吧

      SELECT
      (case when a.colorder=1 then d.name else '' end) N'表名',
      a.colorder N'字段序号',
      a.name N'字段名',
      (case when COLUMNPROPERTY( a.id,a.name,'IsIdentity')=1 then '√'else '' end) N'标识',
      (case when (SELECT count(*)
      FROM sysobjects
      WHERE (name in
              (SELECT name
              FROM sysindexes
              WHERE (id = a.id) AND (indid in
                        (SELECT indid
                      FROM sysindexkeys
                      WHERE (id = a.id) AND (colid in
                                (SELECT colid
                                FROM syscolumns
                                WHERE (id = a.id) AND (name = a.name))))))) AND
            (xtype = 'PK'))>0 then '√' else '' end) N'主键',
      b.name N'类型',
      a.length N'占用字节数',
      COLUMNPROPERTY(a.id,a.name,'PRECISION') as N'长度',
      isnull(COLUMNPROPERTY(a.id,a.name,'Scale'),0) as N'小数位数',
      (case when a.isnullable=1 then '√'else '' end) N'允许空',
      isnull(e.text,'') N'默认值',
      isnull(g.[value],'') AS N'字段说明'
      --into ##tx

      FROM  syscolumns  a left join systypes b
      on  a.xtype=b.xusertype
      inner join sysobjects d
      on a.id=d.id  and  d.xtype='U' and  d.name <>'dtproperties'
      left join syscomments e
      on a.cdefault=e.id
      left join sysproperties g
      on a.id=g.id AND a.colid = g.smallid 
      order by object_name(a.id),a.colorder

     

      六、 时间格式转换问题


      因为新开发的软件需要用一些旧软件生成的一些数据,在时间格式上不统一,只能手工转换,研究了一下午写了三条语句,以前没怎么用过convert函数和case语句,还有"+"操作符在不同上下文环境也会起到不同的作用,把我搞晕了要,不过现在看来是差不多弄好了。

      1、把所有"70.07.06"这样的值变成"1970-07-06"

      UPDATE lvshi
      SET shengri = '19' + REPLACE(shengri, '.', '-')
      WHERE (zhiyezheng = '139770070153')

      2、在"1970-07-06"里提取"70","07","06"

      SELECT SUBSTRING(shengri, 3, 2) AS year, SUBSTRING(shengri, 6, 2) AS month,
          SUBSTRING(shengri, 9, 2) AS day
      FROM lvshi
      WHERE (zhiyezheng = '139770070153')

      3、把一个时间类型字段转换成"1970-07-06"

      UPDATE lvshi
      SET shenling = CONVERT(varchar(4), YEAR(shenling))
          + '-' + CASE WHEN LEN(MONTH(shenling)) = 1 THEN '0' + CONVERT(varchar(2),
          month(shenling)) ELSE CONVERT(varchar(2), month(shenling))
          END + '-' + CASE WHEN LEN(day(shenling)) = 1 THEN '0' + CONVERT(char(2),
          day(shenling)) ELSE CONVERT(varchar(2), day(shenling)) END
      WHERE (zhiyezheng = '139770070153')

     

      七、 分区视图


      分区视图是提高查询性能的一个很好的办法

      --看下面的示例

      --示例表
      create table tempdb.dbo.t_10(
      id int primary key check(id between 1 and 10),name varchar(10))

      create table pubs.dbo.t_20(
      id int primary key check(id between 11 and 20),name varchar(10))

      create table northwind.dbo.t_30(
      id int primary key check(id between 21 and 30),name varchar(10))
      go

      --分区视图
      create view v_t
      as
      select * from tempdb.dbo.t_10
      union all
      select * from pubs.dbo.t_20
      union all
      select * from northwind.dbo.t_30
      go

      --插入数据
      insert v_t select 1 ,'aa'
      union  all select 2 ,'bb'
      union  all select 11,'cc'
      union  all select 12,'dd'
      union  all select 21,'ee'
      union  all select 22,'ff'

      --更新数据
      update v_t set name=name+'_更新' where right(id,1)=1

      --删除测试
      delete from v_t where right(id,1)=2

      --显示结果
      select * from v_t
      go

      --删除测试
      drop table northwind.dbo.t_30,pubs.dbo.t_20,tempdb.dbo.t_10
      drop view v_t

      /**//*--测试结果

      id          name     
      ----------- ----------
      1          aa_更新
      11          cc_更新
      21          ee_更新

      (所影响的行数为 3 行)
      ==*/

      八、 树型的实现

      --参考

      --树形数据查询示例
      --作者: 邹建

      --示例数据
      create table [tb]([id] int identity(1,1),[pid] int,name varchar(20))
      insert [tb] select 0,'中国'
      union  all  select 0,'美国'
      union  all  select 0,'加拿大'
      union  all  select 1,'北京'
      union  all  select 1,'上海'
      union  all  select 1,'江苏'
      union  all  select 6,'苏州'
      union  all  select 7,'常熟'
      union  all  select 6,'南京'
      union  all  select 6,'无锡'
      union  all  select 2,'纽约'
      union  all  select 2,'旧金山'
      go

      --查询指定id的所有子
      create function f_cid(
      @id int
      )returns @re table([id] int,[level] int)
      as
      begin
      declare @l int
      set @l=0
      insert @re select @id,@l
      while @@rowcount>0
      begin 
        set @l=@l+1 
        insert @re select a.[id],@l 
        from [tb] a,@re b 
        where a.[pid]=b.[id] and b.[level]=@l-1
      end
      /**//**//**//*--如果只显示最明细的子(下面没有子),则加上这个删除
      delete a from @re a
      where exists( 
        select 1 from [tb] where [pid]=a.[id])
      --*/
      return
      end
      go

      --调用(查询所有的子)
      select a.*,层次=b.[level] from [tb] a,f_cid(2)b where a.[id]=b.[id]
      go

      --删除测试
      drop table [tb]
      drop function f_cid
      go

      九、 排序问题

      CREATE TABLE [t] (
      [id] [int] IDENTITY (1, 1) NOT NULL ,
      [GUID] [uniqueidentifier] NULL
      ) ON [PRIMARY]
      GO

      下面这句执行5次

    insert t values (newid())

      查看执行结果

    select * from t

      1、 第一种

      select * from t
      order by case id when 4 then 1
                      when 5 then 2
                      when 1 then 3
                      when 2 then 4
                      when 3 then 5 end

      2、 第二种

    select * from t order by (id+2)%6

      3、 第三种

    select * from t order by charindex(cast(id as varchar),'45123')

      4、 第四种

      select * from t
      WHERE id between 0 and 5
      order by charindex(cast(id as varchar),'45123')

      5、 第五种

    select * from t order by case when id >3 then id-5 else id end

      6、 第六种

    select * from t order by id / 4 desc,id asc


      十、 一条语句删除一批记录

      首先id列是int标识类类型,然后删除ID值为5,6,8,9,10,11的列,这里的cast函数不能用convert函数代替,而且转换的类型必须是varchar,而不能是char,否则就会执行出你不希望的结果,这里的"5,6,8,9,10,11"可以是你在页面上获取的一个chkboxlist构建成的值,然后用下面的一句就全部删除了,比循环用多条语句高效吧应该。

    delete from [fujian] where charindex(','+cast([id] as varchar)+',',','+'5,6,8,9,10,11,'+',')>0

      还有一种就是

    delete from table1 where id in(1,2,3,4 )

       十一、获取子表内的一列数据的组合字符串

       下面这个函数获取05年已注册了的某个所的律师,唯一一个参数就是事务所的名称,然后返回zhuce字段里包含05字样的任何律师。

       CREATE

       FUNCTION fn_Get05LvshiNameBySuo

       (@p_suo Nvarchar(50))RETURNS Nvarchar(2000)ASBEGINDECLARE @LvshiNames varchar(2000), @name varchar(50)select @LvshiNames=''DECLARE lvshi_cursor CURSOR FOR

  • 博客收藏

    2008-04-04 21:53:49

  • 网络分析技术学习步骤[转]

    2008-04-04 21:33:37

    网络分析技术学习步骤

    网络分析有以下典型作用:
     查看网络中的流量分布;
    l
     查看网络中的协议分布;l
     查看网络中各主机的通讯信息;l
     快速定位并排查网络故障;l
     找出网络中潜在的安全隐患;l
     查找网络中的蠕虫病毒攻击,黑客攻击,木马攻击;l
     协议学习;l
     。。。。。。l

    对于网络分析的学习,我们推荐按照以下的学习步骤


    首先,必须了解并掌握网络分析的前置知识,只有在掌握相应知识的前提下,才能对网络进行有效的分析


    前置知识1http://www.csna.cn/viewthread.php?tid=626&extra=page%3D2

    前置知识2http://www.csna.cn/viewthread.php?tid=630&extra=page%3D2

    网络分析技术基础知识培训PPThttp://www.csna.cn/viewthread.php?tid=639&extra=page%3D2



    接着,可以了解一些常见的协议


    常见协议简介,http://www.csna.cn/viewthread.php?tid=405&extra=page%3D1

    以太网协议,http://www.csna.cn/viewthread.php?tid=276&extra=page%3D5

    FTP
    协议,http://www.csna.cn/viewthread.php?tid=574&extra=page%3D1

    RIP
    协议,http://www.csna.cn/viewthread.php?tid=594&extra=page%3D1

    OSPF
    协议,http://www.csna.cn/viewthread.php?tid=114&extra=page%3D1

    ICMP
    协议,http://www.csna.cn/viewthread.php?tid=437&extra=page%3D1

    SMB/CIFS
    协议,http://www.csna.cn/viewthread.php?tid=84&extra=page%3D2



    为更有效地学习网络分析技术,下面这些书籍是有必要看的。


    TCP/IP
    详解(卷一),http://www.csna.cn/viewthread.php?tid=605&extra=page%3D1

    TCP/IP
    详解(卷一),http://www.csna.cn/viewthread.php?tid=606&extra=page%3D2

    TCP/IP
    详解(卷三),http://www.csna.cn/viewthread.php?tid=619&extra=page%3D2

    Sniffer
    故障排查,http://www.csna.cn/viewthread.ph ... B%B2%CB%C7%E0%B3%E6

    网络分析经典学习书籍,详见http://www.csna.cn/viewthread.php?tid=286&extra=page%3D2



    工欲善其事,必先利其器。要进行网络分析,我们首先必须理解网络分析软件的工作原理,并将网络分析软件接入到网络中采集数据包,另外,需要学习网络分析软件,学习之后我们即可借助网络分析软件帮助我们分析查找网络的故障。


    网络分析软件安装部署,http://www.csna.cn/viewthread.php?tid=355&extra=page%3D1

    Iris
    软件使用详解,http://www.csna.cn/viewthread.php?tid=264&extra=page%3D1

    Sniffer Pro 4.7
    入门指南,http://www.csna.cn/viewthread.php?tid=57&extra=page%3D1

    Sniffpro 4.7
    专家系统配置指南,http://www.csna.cn/viewthread.php?tid=58&extra=page%3D3

    TCPDUMP
    中文手册,http://www.csna.cn/viewthread.php?tid=469&extra=page%3D1



    不同的网络分析软件,在功能和使用上有着比较大的差别,对这些有深入的理解,将有助于我们选择使用最合适的网络分析软件并快速解决问题。


    网络分析软件过滤器之位过滤功能对比,http://www.csna.cn/viewthread.php?tid=138&extra=page%3D1

    网络分析软件ARP攻击分析功能对比,http://www.csna.cn/viewthread.php?tid=521&extra=page%3D1

    对比网络分析软件过滤IP网段数据通讯,http://www.csna.cn/viewthread.php?tid=164&extra=page%3D6



    学习使用网络分析软件后,我们可以借助网络分析软件对网络故障进行分析。


    某电业局网络故障诊断,http://www.csna.cn/viewthread.php?tid=97&extra=page%3D1

    电信网页访问监控原理分析,http://www.csna.cn/viewthread.php?tid=68&extra=page%3D1

    使用协议分析软件查找网络故障慢的原因,http://www.csna.cn/viewthread.php?tid=198&extra=page%3D1

    使用协议分析软件查看MSN聊天内容,http://www.csna.cn/viewthread.php?tid=152&extra=page%3D1

    使用TTL分析网络故障,http://www.csna.cn/viewthread.php?tid=618&extra=page%3D2

    使用科来网络分析系统捕捉网络中的用户名密码,http://www.csna.cn/viewthread.php?tid=149&extra=page%3D2

    详细的HTTP访问流程分析,http://www.csna.cn/viewthread.php?tid=156&extra=page%3D3

    Email
    邮件分析,http://www.csna.cn/viewthread.php?tid=569&extra=page%3D2

    FTP
    文件传输应用分析,http://www.csna.cn/viewthread.php?tid=1293&extra=page%3D2

    ARP
    攻击与防护完全手册,http://www.csna.cn/viewthread.php?tid=1311&extra=page%3D1

    网络分析,与网络管理紧密结合,常见网络管理员的使用,我们也是可以了解的。


    Solarwinds IP Network Browser
    学习笔记,http://www.csna.cn/viewthread.php?tid=270&extra=page%3D4


    学会网络分析软件的使用,不单单可以查找分析网络故障,还能帮助我们学习相应的协议。

    NetBIOS
    协议分析,http://www.csna.cn/viewthread.php?tid=595&extra=page%3D2

    使用网络分析软件学习HTTP协议,http://www.csna.cn/viewthread.php?tid=371&extra=page%3D1

    CDP
    协议分析,http://www.csna.cn/viewthread.php?tid=479&extra=page%3D4

    使用分析工具学习TCP/IP协议,http://www.csna.cn/viewthread.php?tid=319&extra=page%3D5

    Snitfer Pro Omnipeek Solarwinds 科来网络分析系统

     

  • LR的协议选择【转载】

    2007-10-29 12:59:42

    LR的协议选择

    摘自:fengniao的个人空间

    2007-07-10 17:21:28

    经常看到某些人问LR中如何选择协议,我来谈谈这个问题

    1.LR支持多种协议,请大家一定要注意,这个地方协议指的是你的Client端通过什么协议访问的Server,Client一般是面向最终使用者的,Server是第一层Server端,因为现在的体系架构中经常Server层也分多个层次,什么应用层,什么数据层等等,LR只管Client如何访问第一层Server。

    2.特别要注意某些应用,例如一个Web系统,这个系统是通过ActiveX控件来访问后台的,IE只是一个容器,而ActiveX控件访问后台是通过COM/DCOM协议的,这种情况就不能使用Web协议,否则你什么也录制不到,所以,LR工程师一定要了解应用程序的架构和使用的技术

    3.谈谈多协议

    LR是支持在一个脚本里面使用多协议的,不过这个多协议是有一定的限制的,我有一个LR7.6上哪些协议支持多协议,LR8.0是不是取消了这些限制我不清楚。象HTTPS,一般来讲一定要选择多协议,但在选择具体协议的时候一定只选Web协议,这时候才能作那个端口映射。

    4.谈谈Web协议中Option

    Web协议里面有一些Option,具体我记不清楚了,但有一个地方很重要:就是选择URL方式还是HTM方式录制,这里有一些原则

    a. 尽量使用HTM方式录制

    b.如果使用了Javascrīpt,并且javascrīpt里面与后台有交互,那一定要使用URL方式,例如javascrīpt用于判断用户名和密码是否正确(与后台一定会有交互),那么就要使用URL方式录制;但如果Javascipt只是判断用户名或密码的格式,那一般不会与后台发生交互,就不需要使用URL方式。至于什么情况下一定要用URL方式,我曾经写过一个文档,但现在我不记得了不好意思。

    5.谈谈并发点和结果检查

    很多人喜欢使用并发点和结果检查,我谈谈我自己的看法。第一我基本上从来不使用结果检查,压力测试的结果我一般是去后台检查存储层的数据是否正确的。LR只能检查协议层上的错误,但如果在大量并发用户的情况下使用返回结果检查例如reg_text_check,会极大的占用客户端的资源,我一般不这么作;至于并发点,我只有在客户强烈要求的情况下才会使用,否则基本不用。

  • 关于LR监控Weblogic8的心得

    2007-10-29 12:54:40

    摘自:fengniao的个人空间

    关于LR监控Weblogic8的心得

    2007-05-11 11:23:21

    我前一段时间使用LR8.0测试一个Web应用系统,中间件用的就是Weblogic8.1.5,监控过程中遇到了很多问题,总结出来与大家共享

    1.Controller机器负责监控Weblogic,所以要确认Controller本机使用的JDK与所有服务器上使用的JDK版本一定要一致,这点非常重要,特别是在Cluster环境上。我曾经在这个地方费了很大的力气,而且感觉非常奇怪,为何Controller可以监控一个Web服务器,为什么就不能监控EJB服务器呢?后来统一为j2sdk1.4.2之后,问题才解决了。

    2.按照说明书上的要求修改Web*.ini和一个jar包文件,这点没什么可说的,一定要严格按照这个来修改,否则会出现文档顶层无效的提示。

    3.不要监控太多的指标,监控指标过多,会影响服务器的性能,而且数据没有意义,特别是监控EJB指标的时候,特别要注意这点。

    4.最好先在开始->运行里面用\\方式访问一下被监控的服务器,使用administrator登陆(如果服务器操作系统是Windows的话)。

  • 决定成败的人生细节

    2007-10-29 12:43:06

    决定成败的人生细节

    2007-10-10 15:22:50

    1 坚持在背后说别人的好话
    2 每天向你周围的人问声“早上好”
    3 连续加班后,更要精神饱满
    4 过去的事不要全让人知道
    5 说话时尽量常用“我们”
    6 该问的与不该问的
    7 有人在你面前说别人坏话时,你不要插嘴
    8 人多的场合少说话
    9 与人握手时,可多握一会儿
    10 不是你的功劳,千万不要占有它
    11 尽量不要借朋友的钱
    12 不要轻易承诺
    13 老板错了的时候,你要懂得应对
    14 随便打断别人说话是一种陋习
    15 不要比你的老板穿得更好
    16 主动汇报自己的工作情况
    17 要懂得感恩
    18 不要把谈论别人的缺点当做乐趣
    19 遇事多考虑3分钟
    20 不想因应酬伤害自己,就要注意分寸
    21 上班时与下班时
    22 要想办法让老板知道你做了什么
    23 别忘随时为自己鼓掌
    24 搜集信息还要消化信息
    25 多自我批评,少自我表扬
    26 不要为自己的错误做任何辩解
    27 自以为最了解自己,其实不然
    28 不要负面回应批评
    29 对自己不知道的事情,坦率地说不知道
    30 对事无情,对人要有情
    31 和上司谈话时,关掉你的手机
    32 和客户通电话时,不要先挂掉电话
    33 找借口拒绝时,要尽可能模糊一点
    34 遇到老板,主动迎上去谈几句
    35 给老板的报告里预备一份概要
    36 不要占用公司的一张纸或一支笔
    37 在工作中使用“日常备忘录”
    38 不要在朋友面前炫耀自己
    39 保持办公桌的整洁、有序
    40 只要还能坚持上班就不要请假
    41 做事前,先想像一个好的结果
    42 竞争中要学会欣赏对手
    43 接到额外工作时,不要抱怨
    44 昨晚多几分钟的准备,今天少几个小时的麻烦
    45 出现在公共场合时要保持整洁
    46 向上司请教前,事先想好问题的解决方法
    47 做错事要马上道歉
    48 要学会说善意的谎言
    49 约会时要提前几分钟到达
  • 图片验证码性能测试解决方案『转载』

    2007-10-10 13:58:08

    摘自 木子清风的博客 :http://www.51testing.com/?84226/action_viewspace_itemid_4335.html

    经常看到朋友讨论如何测试图片验证码功能,大家常用的有三种方法:51Testing软件测试网4{6d#T1q}q6j
    1.设置一个万能验证码.
    U9x2q@&O&IN18755 2.取消验证码功能.51Testing软件测试网0n*O\ [ M'd]6?8l
    3.编写个专用插件,动态获取真实的验证码.51Testing软件测试网#Q%g^.DSFp?,D7kw

    )Od+Gi3X/g6\Mg RL(D18755 1,2两种方法实现比较容易,缺点是不能真实的模拟实际应用环境.
    `a6w3X|i18755 3的方法技术难度较高.
    w9K;I:d-An18755 51Testing软件测试网U i+`^#ZJ1ey
    其实我们还有第4种即简单又能够真实的模拟实际应用的方法.
    -bm*F:F dSL18755
    Ywf8o w+Rk|"CK18755 以Jsp网站为例,先来看看验证码功能的实现方法.图片验证码由以下几个步骤实现.
    :U$g v{'P*h18755 1.生成随机数.51Testing软件测试网3y1}2\xS^ ?!]
    2.将随机数存入 Session (会话).51Testing软件测试网K0MScbIP
    3.将随机数制作成图片.51Testing软件测试网$PR&c!BL.A(~uL
    部分较重要的代码如下.51Testing软件测试网7DG7g"@F)p S/Q
    <img src="CheckCode.jsp" border="0" alt="验证....... 这个是调用 CheckCode.jsp 文件,生成图片验证码.51Testing软件测试网\4H'{1\G{W@r
    51Testing软件测试网p(ak"X!r
    CheckCode.jsp文件代码如下51Testing软件测试网6?"c6mG b4H"f
    String sRand="";51Testing软件测试网gn aB'K;Ca ~5Z2D
    for (int i=0;i<4;i++){51Testing软件测试网9o#VVp"J @5@9_
        String rand=String.valueOf(random.nextInt(10));   //生成随机数
    ([td*F5^m18755     sRand+=rand;
    3E\K+zY-_n18755      ..........51Testing软件测试网jW0}#b{Z
    }
    Yy$]J5hAF/Y18755 session.setAttribute("rand",sRand);    将随机数据存入session中.51Testing软件测试网q1B@%oc7k[cW
    51Testing软件测试网c,L Qr Bk%X
    到这里我们已经知道,只要制作一个jsp页面调出session中的rand 值,就可以得到验证码的正文数据.51Testing软件测试网(X-P y&WweiXMa1} _
    实现代码如下.
    9N j(YxQja18755 t.jsp51Testing软件测试网 [}!K o)B iQ
    <%51Testing软件测试网W*l9Ij7n ZD:t]
    out.print(session.getAttribute("rand"));51Testing软件测试网-J5y)ur-Ha_
    %>
    5hrvCr.tJ%ex18755 51Testing软件测试网|Zm;} F?"w:h
    如果在LoadRunner中实现的方法如下:51Testing软件测试网H5VS~.H KU}
    请求 CheckCode.jsp 生成图片验证码.51Testing软件测试网 Idl)S]\u
    请求 t.jsp 获取验证码的正文数据.51Testing软件测试网+P;yb:Rr[h7F
    提交 数据.51Testing软件测试网 gD7vY4Bp H[ |z
    51Testing软件测试网ljGg^-C
    稍后我会上传一个完整的实例,包括B/S验证码应用和LR脚本.请大家稍等.51Testing软件测试网&p#OI)Vk

    Z-WE i%X#CC18755 附件中已经上传了案例和LoadRunner脚本.
    9Ns:_,Qj'F18755 PicVerify 是LoadRunner脚本.
    u(qGY`z0|/C18755 verf 是源代码. 首页文件是reg.jsp51Testing软件测试网2B?m-FQv:Xf*r
    jsp项目的安装与部署方法请参考51Testing软件测试网;N;?Fg,dj8W%b
    搭建测试环境

      下载并安装 Java    地址:http://java.sun.com/javase/downloads/index_jdk5.jsp
       下载并安装 Tomcat   地址: http://apache.justdn.org/tomcat/ ... e-tomcat-5.5.20.zip


      下载并安装Java JDK  (注:假设安装路径为   Java D:\java Tomcat D:\apache-tomcat-5.5.20
      设置Java环境变量
           Path、Java_Home、Class_Path
           操作方法简述:

          环境变量Java_Home 设置:
          桌面 -->右键单击"我的电脑" --> 单击"属性" --> 单击 "高级" --> 环境变量 新建系统环境变量 Java_Home 输入 "D:\Java"

          环境变量Class_Paht 设置:
          新建系统环境变量 Class_Path 输入 ".;%java_home%\lib"
          
          环境变量Paht 修改:
          修改 Path 变量增加"%java_home%\bin"

          验证:
          修改完成后,在Dos窗口中输入java -version 查看Java版本信息。

      下载并安装Tomcat

          配置:
      1.安装数据库驱动:将附件中的Jar文件拷贝到Tomcat的server\lib文件夹中。

      验证
          运行tomcat\bin\startup.bat文件启动Tomcat。在IE地址栏中输入 http://本机IP地址:8080 或 http://127.0.0.1:8080 查看Tomcat信息。
    LoadRunner使用方法请参考  LR使用说明******

    资源:图片验证码 性能测试解决方案** LR脚本

  • 如何用LR监视服务器LINUX的方法『转载』

    2007-09-15 17:37:13

     

    一、在服务器上安装rstatd守护进程
    安装步骤:
    1. 从网上下载rstatd
    2. 将该文件放到/home/user目录下
    3. chmod 777 rpc.rstatd----改变该文件读写的权限,拥有所有权限。
    4. chmod 777 configure ---同上
    5. ./configure ---配置
    6. make ---编译
    7. make install ---安装
    8. rpc.rstatd ---启动rstatd进程

    二、在lr中配置
    从LR里面add measurement, 填写linux机器的IP,出现所有unix/linux的计数器,包括cpu的,mem的,disk,network的。介绍几个常用的:
    average load :在过去的1分钟,的平均负载
    cpu utilization: cpu的使用率
    disk traffic: disk传输率
    paging rate: 每秒从磁盘读到物理内存,或者从物理内存写到页面文件的内存页数
    Swap-in rate: 每秒交换到内存的进程数
    Swap-out rate: 每秒从内存交换出来的进程


    补充一些常见的问题及处理方法:
    1、在执行配置或安装命令过程中出现“拒绝的权限”的提示;
    答:是由于文件的权限引起的,应该给当前用户所有文件的“777”权限,即完全控制权限。

    2、安装好后从LoadRunner中看不到信息,但是没有报错;
    答:可能是返回的信息值比较小,所以在图中几乎看不到,例如:如果没有运行程序的话,CPU的使用率接近于0,所以在监视图中看不到变化。也有可能是采样的频率过大,可以在图表中设置没1秒获取一次信息,这样界面就刷新的比较及时了。

    3、监视一段时间后LoadRunner中提示有错误发生不能继续监视到信息;
    答:可能是由于CPU长时间处于高负荷状态,而导致系统自动关闭了该服务。可以在LoadRunner中重新加一次计数器,并且设置取样的时间稍长一点,就会避免这种情况。

    4、以前用LoadRunner监视都是成功的,但是再次监视不到信息;
    答:有可能是由于系统重新启动,而没有打开rstatd守护进程。可以手工重新打开一次,使用命令“rpc.rstatd”,另外可以使用“rpcinfo -p”命令来查看当前系统是否已经启动了rstatd守护进程。

  • 如何应对面试“面试的十大必考题”『转载』

    2007-09-12 13:30:54

     

    面试时,有几个问题是公司面试人员常常会提出的,针对这些问题好好准备,在面试时也就不会哑口无言,无言以对了,下面就面试十大必考题做出分析:

      (1)为什么想进本公司?

      这通常是面试官最先问到的问题。此时面试官就开始评断录用与否了,建议大家先判断自己去应征的工作性质,是专业能力导向呢,或是需要沟通能力,其实现在市场多以服务为方向,所以口才被视为基本能力之一,所以在此时就要好好表现自己的口才,而口才较差者就务必表现出自己的专业能力即诚意,弥补口才不足的部分。

      回答这个问题时,一定要积极正面,如想要使自己能有更好的发展空间,希望能在相关领域中有所发展,希望能在公司多多学习等等﹔此时可以稍稍夸一下面试公司,但切记一定要诚恳,不然可是会画蛇添足,得不偿失哦!对于社会新鲜人的建议则是,由于之前没有工作经验,所以建议你可以坦承的说出自己的动机,不过用语还是要思考一下。

      (2)喜欢这份工作的哪一点?

      相信其实大家心中一定都有答案了吧!每个人的价值观不同,自然评断的标准也会不同,但是,在回答面试官这个问题时可不能太直接就把自己心理的话说出来,尤其是薪资方面的问题,不过一些无伤大雅的回答是不错的考虑,如交通方便,工作性质及内容颇能符合自己的兴趣等等都是不错的答案,不过如果这时自己能仔细思考出这份工作的与众不同之处,相信在面试上会大大加分。

      (3)自己的优缺点为何?

      有许多面试官都喜欢问这个问题,目的是在于检视人才是否适当,求职者的诚恳度等等,在这之前应该好好分析自己,将自己的优点与缺点列张单子,在其中挑选亦是缺点亦是优点的部分,在回答问题时,以优点作为主要诉求,强调可以为公司带来利益的优点,如积极,肯学习是最普遍的回答,而缺点部分则建议选择一些无伤大雅的小缺点,或是上述那些模嶙两可的优缺点作为回答,这样才不会使面试官太过针对缺点做发挥,造成面试上的困难。

      (4)对公司的了解有多少?

      这时准备的功夫就派上用场,将你之前所吸收的信息发挥出来吧!至少也要知道公司的产品是哪些,提供哪些服务等等,不然面试官一问当场傻在那儿就糗大了,所以一定要事前准备!

      (5)对工作的期望与目标何在?

      这是面试者用来评断求职者是否对自己有一定程度的期望、对这份工作是否了解的问题。对于工作有确实学习目标的人通常学习较快,对于新工作自然较容易进入状况,这时建议你,最好针对工作的性质找出一个确实的答案,如业务员的工作可以这样回答:“我的目标是能成为一个超级业务员,将公司的产品广泛的推销出去,达到最好的业绩成效;为了达到这个目标,我一定会努力学习,而我相信以我认真负责的态度,一定可以达到这个目标。”其他类的工作也可以比照这个方式来回答,只要在目标方面稍微修改一下就可以了。

      (6)为什么要离职?

      回答这个问题时一定要小心,就算在前一个工作受到在大的委屈,对公司有多少的怨言,都千万不要表现出来,尤其要避免对公司本身主管的批评,避免面试官的负面情绪及印象;建议此时最好的回答方式是将问题归咎在自己身上,例如觉得工作没有学习发展的空间,自己想在面试工作的相关产业中多加学习,或是前一份工作与自己的生涯规划不合等等,回答的答案最好是积极正面的。

      (7)选择这份工作的原因为何?

      这是面试官用来测试应聘者对工作理解度的问题,藉以了解求职者只是基于对工作的憧憬或是确实的兴趣来应征这份工作,此时之前所强调的事先研究功夫又再度派上用场,建议你的回答应以个人的兴趣配合工作内容特质,表现出高度的诚意,这样才可以为自己铺下迈向成功之路。

      (8)你认为相关产业的发展为何?

      这也是事前准备的功夫,多阅读一些相关的报章杂志,做一些思考,表现出自己对此相关产业的的认识,如果是同业转职者,可强调以自己的经验为基础所做的个人见解,但若是初次接触此一行业,建议采取较为保守的方式,以目前资讯所提供的资料为主作答,表现出高度兴趣及诚意为最高指导原则。

      (9)你希望的待遇为多少?

      这是一个非常敏感的问题,其实在目前,一般大型企业在招聘时就会事先说明基本底薪等等薪资待遇为何,而一般中小型企业有许多仍以个人能力,面试评价做作为议薪的标准,所以建议求职者可以利用现在网络科技查询薪资定位的相关资料,配合个人的价值观,经验,能力等等条件,做出最基本的薪资底限,这时建议无工作经验者应采取保守的态度为准,以客观资料作为最主要考量重点,“依公司规定”的回答是不被建议的,这样不但表示出自己对于工作的自信程度不高,在薪资无法符合个人要求时更会造成许多困扰。

      (10)在工作中学习到了些什么?

      这是针对转职者提出的问题,建议此时可以配合面试工作的特点作为主要依据来回答,如业务工作需要与人沟通,便可举出之前工作与人沟通的例子,经历了哪些困难,学习到哪些经验,把握这些要点做陈述,就可以轻易过关了

  • 测试的招聘与面试!『转载』

    2007-09-12 13:22:18

    摘自 http://www.51testing.com/?121932/action_viewspace_itemid_20477.html

    最近工作一直很忙,也很累,正如那句话说的“疲惫的身体,疲惫的心”。但是那么累,我却过的是那么的开心。前两天在测试时代上看到一些测试的招聘信息,突然让我回忆起测试同行问过我关于测试的招聘与面试怎么知道是真是假,面对多家招聘公司的选择,怎么去判断自己的选择是正确的呢?今天突发奇想,觉的可以记录一些东西,因此便有了这个随笔

     

    今天记录下面两个问题的分析

    1、  怎么从招聘信息分析公司对测试这个职位的了解?

    2、  怎么知道所面试的公司是否适合自己?

     

    从招聘测试的招聘信息和面谈可以了解招聘公司对测试工作的理解和态度 .

    分析点 :

    1)      如果招聘信息要求应聘者了解一些开发流程、测试流程、测试技术(如黑盒测试、白盒测试等等),可见这个公司了解测试这个工作岗位。

    2)      在上面第一条的基础上,如果招聘信息要求应聘者熟悉测试工具的使用,可见这个公司在使用自动化技术或者有这个打算。

    3)      如果招聘信息要求应聘者要有很好的沟通能力、表达能力、协调能力、适应能力、学习能力,可见这个公司的企业文化比较人文化(大家可以互相交流意见)。

    4)      如果招聘信息详细描述包含了两部分:岗位名称和岗位职责,并且招聘信息描述正确、排版美观,说明简洁明了,可见这个公司人事管理规范。


    面谈的时候,招聘公司是否重视测试、懂的测试这个职位,从这下面这几个方面就可以有些了解:

    NO1 :测试的领导是否做过测试工作。

    很多公司管理者的技术能力是在程序员的时代得到的,这些人走上管理岗位后,如果没有持续的学习,就会根本不了解测试是怎么回事,有什么价值,在他们心目中,只有开发人员做的事情才是重要的,可见的。他们之所以招人做测试是因为软件的质量实在太差,客户的不满让他们无法忍受。面对测试狗屁不通的测试经理或者高级经理做测试工作,后果是:首先,努力得不到肯定,工作成果得不到尊重。接着,会发现成长的机会很少,因为领导既然不懂测试,也就不知道需要提高什么样的技能,既不要求你,也不支持你。你只好自己学习,而且难以获得支持和肯定。

     

    NO2 :测试的管理是否规范

    招聘单位是否重视软件质量,从对待开发、测试的管理、执行是否规范就可以看出。测试在整个项目的介入、测试工作的评审,测试报告、对待严重 bug 的处理;对测试人员的考核、工作职责定位是否合理等等就可以了解这个公司测试大体执行情况。

     

    NO3 :知己知彼

    看看自己目前的能力是否能胜任所应聘的岗位,看看公司的企业文化、办公环境是否能适应,看看公司的福利待遇是否能接受了。正如 testage 论坛上关河发起的讨论“ 测试工程师希望什么样的工作环境?”嘿嘿,我的回答是:

    嘿嘿,对于目前的我来说,我希望在下面这样条件的公司做测试工作:

    1 、公司的开发流程是按照正规流程走:需求分析 -- 概要设计 -- 详细设计 -- 单元测试 -- 集成测试 -- 系统测试 -- 验收测试,并对每一阶段的成果物进行有效的评审。因为:把时间花在做正确的事情上才是正确有效的工作方式。

    2 、公司要重视软件的质量,测试可以参与到开发的整个活动过程,进行软件开发全过程测试。因为:测试对软件开发的过程、进度,对所测试软件产生的原因(即用户需求)以及使用的场景了解(即用户为什么要这么做)越清晰,测试的工作才能是准确、有效和高效的。

    3 、公司要有懂的测试工作、理解测试工作的人,特别是测试、开发的领导者。因为:对牛弹琴,牛到死了都不知道你是在干嘛,琴弹的在好都没有办法领悟和理解。

    4 、公司有学习氛围、有良好的沟通环境,大家可以互相的交流自己的思想、经验和对工作成果的意见。因为:有些工作,经过交流会得出新的、更好、更合理有效的处理方法。开发人员和测试人员有效、友好的沟通工作建议和经验会使整个团队的研发水平、测试水平、工作效率、工作质量向上发展。

    5 、公司对测试人员的绩效考核是正确合理的,既不能用其它工种(如:开发人员、技术支持人员)的绩效考核方式来考核测试人员的工作,绩效考核的目的是激励员工工作的积极性。

    6 、公司能够长期生存,公司领导能够规划好整个公司的发展方向、测试部门领导能够很好的规划部门的发展方向。

    7 、公司的生意好好的,能接很多的项目进行研发。

  • C#对Java

    2007-09-08 14:13:19

     

     

    C#对Java

    • 作者:佚名    来源:不详    

    华山论剑:C#对Java
    (仙人掌工作室 2001年06月29日 17:01)

    C#(C-Sharp)是Microsoft的新编程语言,被誉为“C/C++家族中第一种面向组件的语言”。然而,不管它自己宣称的是什么,许多人认为C#更像是Java的一种克隆,或者是Microsoft用来替代Java的产品。事实是否是这样的呢?

      本文的比较结果表明,C#不止是Java的同胞那么简单。如果你是一个Java开发者,想要学习C#或者了解更多有关C#的知识,那么本文就是你必须把最初10分钟投入于其中的所在。

    一、C#、C++和Java

    C#的语言规范由Microsoft的Anders Hejlsberg与Scott Wiltamuth编写。在当前Microsoft天花乱坠的宣传中,对C#和C++、Java作一番比较总是很有趣的。考虑到当前IT媒体的舆论倾向,如果你早就知道C#更接近Java而不是C++,事情也不值得大惊小怪。对于刚刚加入这场讨论的读者,下面的表1让你自己作出判断。显然,结论应该是:Java和C#虽然不是孪生子,但C#最主要的特色却更接近Java而不是C++。

    表1:比较C#、C++和Java最重要的功能
    功能 C# C++ Java
    继承 允许继承单个类,允许实现多个接口 允许从多个类继承 允许继承单个类,允许实现多个接口
    接口实现 通过“interface”关键词 通过抽象类 通过“interface”关键词
    内存管理 由运行时环境管理,使用垃圾收集器 需要手工管理 由运行时环境管理,使用垃圾收集器
    指针 支持,但只在很少使用的非安全模式下才支持。通常以引用取代指针 支持,一种很常用的功能。 完全不支持。代之以引用。
    源代码编译后的形式 .NET中间语言(IL) 可执行代码 字节码
    单一的公共基类
    异常处理 异常处理 返回错误 异常处理。

    了解表1总结的重要语言功能之后,请继续往下阅读,了解C#和Java的一些重要区别。

    二、语言规范的比较

    2.1、简单数据类型

    简单数据类型(Primitive)在C#中称为值类型,C#预定义的简单数据类型比Java多。例如,C#有unit,即无符号整数。表2列出了所有C#的预定义数据类型:

    表2:C#中的值类型
    类型 说明
    object 所有类型的最终极的基类
    string 字符串类型;字符串是一个Unicode字符的序列
    sbyte 8位带符号整数
    short 16位带符号整数
    int 32位带符号整数
    long 64位带符号整数
    byte 8位无符号整数
    ushort 16位无符号整数
    uint 32位无符号整数
    ulong 64位无符号整数
    float 单精度浮点数类型
    double 双精度浮点数类型
    bool 布尔类型;bool值或者是true,或者是false
    char 字符类型;一个char值即是一个Unicode字符
    decimal 有28位有效数字的高精度小数类型

    2.2、常量

    忘掉Java中的static final修饰符。在C#中,常量可以用const关键词声明。

    public const int x = 55;

    此外,C#的设计者还增加了readonly关键词。如果编译器编译时未能确定常量值,你可以使用readonly关键词。readonly域只能通过初始化器或类的构造函数设置。

    2.3、公用类的入口点

    在Java中,公用类的入口点是一个名为main的公用静态方法。main方法的参数是String对象数组,它没有返回值。在C#中,main方法变成了公用静态方法Main(大写的M),Main方法的参数也是一个String对象数组,而且也没有返回值,如下面的原型声明所示:

    public static void Main(String[] args)

    但是,C#的Main方法不局限于此。如果不向Main方法传递任何参数,你可以使用上述Main方法的一个重载版本,即不带参数列表的版本。也就是说,下面的Main方法也是一个合法的入口点:

    public static void Main()

    另外,如果你认为有必要的话,Main方法还可以返回一个int。例如,下面代码中的Main方法返回1:

    using System;
    public class Hello {
    public static int Main() {
    Console.WriteLine("Done");
    return 1;
    }
    }

    与此相对,在Java中重载main方法是不合法的。

    2.4、switch语句

    在Java中,switch语句只能处理整数。但C#中的switch语句不同,它还能够处理字符变量。请考虑下面用switch语句处理字符串变量的C#代码:

    using System;
    public class Hello {
    public static void Main(String[] args) {
    switch (args[0]) {
    case "老板":
    Console.WriteLine("早上好!我们随时准备为您效劳!");
    break;
    case "雇员":
    Console.WriteLine("早上好!你可以开始工作了!");
    break;
    default:
    Console.WriteLine("早上好!祝你好运!");
    break;
    }
    }
    }

    与Java中的switch不同,C#的switch语句要求每一个case块或者在块的末尾提供一个break语句,或者用goto转到switch内的其他case标签。

    2.5、foreach语句

    foreach语句枚举集合中的各个元素,为集合中的每一个元素执行一次代码块。请参见下面的例子。

    using System;
    public class Hello {
    public static void Main(String[] args) {
    foreach (String arg in args)
    Console.WriteLine(arg);
    }
    }

    如果在运行这个执行文件的时候指定了参数,比如“Hello Peter Kevin Richard”,则程序的输出将是下面几行文字:

    Peter
    Kevin
    Richard

    2.6、C#没有>>>移位操作符

    C#支持uint和ulong之类的无符号变量类型。因此,在C#中,右移操作符(即“>>”)对于无符号变量类型和带符号变量类型(比如int和long)的处理方式不同。右移uint和ulong丢弃低位并把空出的高位设置为零;但对于int和long类型的变量,“>>”操作符丢弃低位,同时,只有当变量值是正数时,“>>”才把空出的高位设置成零;如果“>>”操作的是一个负数,空出的高位被设置成为1。

    Java中不存在无符号的变量类型。因此,我们用“>>>”操作符在右移时引入负号位;否则,使用“>>”操作符。

    2.7、goto关键词

    Java不用goto关键词。在C#中,goto允许你转到指定的标签。不过,C#以特别谨慎的态度对待goto,比如它不允许goto转入到语句块的内部。在Java中,你可以用带标签的语句加上break或continue取代C#中的goto。

    2.8、声明数组

    在Java中,数组的声明方法非常灵活,实际上有许多种声明方法都属于合法的方法。例如,下面的几行代码是等价的:

    int[] x = { 0, 1, 2, 3 };
    int x[] = { 0, 1, 2, 3 };

    但在C#中,只有第一行代码合法,[]不能放到变量名字之后。

    2.9、包

    在C#中,包(Package)被称为名称空间。把名称空间引入C#程序的关键词是“using”。例如,“using System;”这个语句引入了System名称空间

    然而,与Java不同的是,C#允许为名称空间或者名称空间中的类指定别名:

    using TheConsole = System.Console;
    public class Hello {
    public static void Main() {
    TheConsole.WriteLine("使用别名");
    }
    }

    虽然从概念上看,Java的包类似于.NET的名称空间。然而,两者的实现方式不同。在Java中,包的名字同时也是实际存在的实体,它决定了放置.java文件的目录结构。在C#中,物理的包和逻辑的名称之间是完全分离的,也就是说,名称空间的名字不会对物理的打包方式产生任何影响。在C#中,每一个源代码文件可以从属于多个名称空间,而且它可以容纳多个公共类。

    .NET中包的实体称为程序集(Assembly)。每一个程序集包含一个manifest结构。manifest列举程序集所包含的文件,控制哪些类型和资源被显露到程序集之外,并把对这些类型和资源的引用映射到包含这些类型与资源的文件。程序集是自包含的,一个程序集可以放置到单一的文件之内,也可以分割成多个文件。.NET的这种封装机制解决了DLL文件所面临的问题,即臭名昭著的DLL Hell问题。

    2.10、默认包

    在Java中,java.lang包是默认的包,它无需显式导入就已经自动包含。例如,要把一些文本输出到控制台,你可以使用下面的代码:

    System.out.println("Hello world from Java");

    C#中不存在默认的包。如果要向控制台输出文本,你使用System名称空间Console对象的WriteLine方法。但是,你必须显式导入所有的类。代码如下:

    using System;
    public class Hello {
    public static void Main() {
    Console.WriteLine("Hello world from C#");
    }
    }

    2.11、面向对象

    Java和C#都是完全面向对象的语言。在面向对象编程的三大原则方面,这两种语言接近得不能再接近。

    • 继承:这两种语言都支持类的单一继承,但类可以实现多个接口。所有类都从一个公共的基类继承。
    • 封装与可见性:无论是在Java还是C#中,你都可以决定类成员是否可见。除了C#的internal访问修饰符之外,两者的可见性机制非常相似。
    • 多态性:Java和C#都支持某些形式的多态性机制,且两者实现方法非常类似。

    2.12、可访问性

    类的每个成员都有特定类型的可访问性。C#中的访问修饰符与Java中的基本对应,但多出了一个internal。简而言之,C#有5种类型的可访问性,如下所示:

    • public:成员可以从任何代码访问。
    • protected:成员只能从派生类访问。
    • internal:成员只能从同一程序集的内部访问。
    • protected internal:成员只能从同一程序集内的派生类访问。
    • private:成员只能在当前类的内部访问。

    2.13、派生类

    在Java中,我们用关键词“extends”实现继承。C#采用了C++的类派生语法。例如,下面的代码显示了如何派生父类Control从而创建出新类Button:

    public class Button: Control { . . }

    2.14、最终类

    由于C#中不存在final关键词,如果想要某个类不再被派生,你可以使用sealed关键词,如下例所示:

    sealed class FinalClass { . . }

    2.15、接口

    接口这个概念在C#和Java中非常相似。接口的关键词是interface,一个接口可以扩展一个或者多个其他接口。按照惯例,接口的名字以大写字母“I”开头。下面的代码是C#接口的一个例子,它与Java中的接口完全一样:

    interface IShape { void Draw(); }

    扩展接口的语法与扩展类的语法一样。例如,下例的IRectangularShape接口扩展IShape接口(即,从IShape接口派生出IRectangularShape接口)。

    interface IRectangularShape: IShape { int GetWidth(); }

    如果你从两个或者两个以上的接口派生,父接口的名字列表用逗号分隔,如下面的代码所示:

    interface INewInterface: IParent1, IParent2 { }

    然而,与Java不同,C#中的接口不能包含域(Field)。

    另外还要注意,在C#中,接口内的所有方法默认都是公用方法。在Java中,方法声明可以带有public修饰符(即使这并非必要),但在C#中,显式为接口的方法指定public修饰符是非法的。例如,下面的C#接口将产生一个编译错误。

    interface IShape { public void Draw(); }

    2.16、is和as操作符

    C#中的is操作符与Java中的instanceof操作符一样,两者都可以用来测试某个对象的实例是否属于特定的类型。在Java中没有与C#中的as操作符等价的操作符。as操作符与is操作符非常相似,但它更富有“进取心”:如果类型正确的话,as操作符会尝试把被测试的对象引用转换成目标类型;否则,它把变量引用设置成null。

    为正确理解as操作符,首先请考虑下面这个例子中is操作符的运用。这个例子包含一个IShape接口,以及两个实现了IShape接口的类Rectangle和Circle。

    using System;
    interface IShape {
    void draw();
    }
    public class Rectangle: IShape {
    public void draw() {
    }
    public int GetWidth() {
    return 6;
    }
    }
    public class Circle: IShape {
    public void draw() {
    }
    public int GetRadius() {
    return 5;
    }
    }
    public class LetsDraw {
    public static void Main(String[] args) {
    IShape shape = null;
    if (args[0] == "rectangle") {
    shape = new Rectangle();
    }
    else if (args[0] == "circle") {
    shape = new Circle();
    }
    if (shape is Rectangle) {
    Rectangle rectangle = (Rectangle) shape;
    Console.WriteLine("Width : " + rectangle.GetWidth());
    }
    if (shape is Circle) {
    Circle circle = (Circle) shape;
    Console.WriteLine("Radius : " + circle.GetRadius());
    }
    }
    }

    编译好代码之后,用户可以输入“rectangle”或者“circle”作为Main方法的参数。如果用户输入的是“circle”,则shape被实例化成为一个Circle类型的对象;反之,如果用户输入的是“rectangle”,则shape被实例化成为Rectangle类型的对象。随后,程序用is操作符测试shape的变量类型:如果shape是一个矩形,则shape被转换成为Rectangle对象,我们调用它的GetWidth方法;如果shape是一个圆,则shape被转换成为一个Circle对象,我们调用它的GetRadius方法。

    如果使用as操作符,则上述代码可以改成如下形式:

    using System;
    interface IShape {
    void draw();
    }
    public class Rectangle: IShape {
    public void draw() {
    }
    public int GetWidth() {
    return 6;
    }
    }
    public class Circle: IShape {
    public void draw() {
    }
    public int GetRadius() {
    return 5;
    }
    }
    public class LetsDraw {
    public static void Main(String[] args) {
    IShape shape = null;
    if (args[0] == "rectangle") {
    shape = new Rectangle();
    }
    else if (args[0] == "circle") {
    shape = new Circle();
    }
    Rectangle rectangle = shape as Rectangle;
    if (rectangle != null) {
    Console.WriteLine("Width : " + rectangle.GetWidth());
    }
    else {
    Circle circle = shape as Circle;
    if (circle != null)
    Console.WriteLine("Radius : " + circle.GetRadius());
    }

    }
    }

    在上面代码的粗体部分中,我们在没有测试shape对象类型的情况下,就用as操作符把shape转换成Rectangle类型的对象。如果shape正好是一个Rectangle,则shape被转换成为Rectangle类型的对象并保存到rectangle变量,然后我们调用它的GetWidth方法。如果这种转换失败,则我们进行第二次尝试。这一次,shape被转换成为Circle类型的对象并保存到circle变量。如果shape确实是一个Circle对象,则circle现在引用了一个Circle对象,我们调用它的GetRadius方法。

    2.17、库

    C#没有自己的类库。但是,C#共享了.NET的类库。当然,.NET类库也可以用于其他.NET语言,比如VB.NET或者Jscrīpt.NET。值得一提的是StringBuilder类,它是对String类的补充。StringBuilder类与Java的StringBuffer类非常相似。

    2.18、垃圾收集

    C++已经让我们认识到手工管理内存是多么缺乏效率和浪费时间。当你在C++中创建了一个对象,你就必须手工地拆除这个对象。代码越复杂,这个任务也越困难。Java用垃圾收集器来解决这个问题,由垃圾收集器搜集不再使用的对象并释放内存。C#同样采用了这种方法。应该说,如果你也在开发一种新的OOP语言,追随这条道路是一种非常自然的选择。C#仍旧保留了C++的内存手工管理方法,它适合在速度极端重要的场合使用,而在Java中这是不允许的。

    2.19、异常处理

    如果你听说C#使用与Java相似的异常处理机制,你不会为此而惊讶,对吧?在C#中,所有的异常都从一个名为Exception的类派生(听起来很熟悉?)另外,正如在Java中一样,你还有熟悉的try和catch语句。Exception类属于.NET System名称空间的一部分。

    三、Java没有的功能

    C#出生在Java成熟之后,因此,C#拥有一些Java(目前)还没有的绝妙功能也就不足为奇。

    3.1、枚举器

    枚举器即enum类型(Enumerator,或称为计数器),它是一个相关常量的集合。精确地说,enum类型声明为一组相关的符号常量定义了一个类型名字。例如,你可以创建一个名为Fruit(水果)的枚举器,把它作为一个变量值的类型使用,从而把变量可能的取值范围限制为枚举器中出现的值。

    public class Demo {
    public enum Fruit {
    Apple, Banana, Cherry, Durian
    }
    public void Process(Fruit fruit) {
    switch (fruit) {
    case Fruit.Apple:
    ...
    break;
    case Fruit.Banana:
    ...
    break;
    case Fruit.Cherry:
    ...
    break;
    case Fruit.Durian:
    ...
    break;
    }
    }
    }

    在上例的Process方法中,虽然你可以用int作为myVar变量的类型,但是,使用枚举器Fruit之后,变量的取值范围限制到了Applet、Banana、Cherry和Durian这几个值之内。与int相比,enum的可读性更好,自我说明能力更强。

    3.2、结构

    结构(Struct)与类很相似。然而,类是作为一种引用类型在堆中创建,而结构是一种值类型,它存储在栈中或者是嵌入式的。因此,只要谨慎运用,结构要比类快。结构可以实现接口,可以象类一样拥有成员,但结构不支持继承。

    然而,简单地用结构来取代类可能导致惨重损失。这是因为,结构是以值的方式传递,由于这种传递方式要把值复制到新的位置,所以传递一个“肥胖的”结构需要较大的开销。而对于类,传递的时候只需传递它的引用。

    下面是一个结构的例子。注意它与类非常相似,只要把单词“struct”替换成“class”,你就得到了一个类。

    struct Point {
    public int x, y;
    public Point(int x, int y) {
    this.x = x;
    this.y = y;
    }
    }

    3.3、属性

    C#类除了可以拥有域(Field)之外,它还可以拥有属性(Property)。属性是一个与类或对象关联的命名的特征。属性是域的一种自然扩展――两者都是有类型、有名字的类成员。然而,和域不同的是,属性不表示存储位置;相反,属性拥有存取器(accessor),存取器定义了读取或者写入属性值时必须执行的代码。因此,属性提供了一种把动作和读取、写入对象属性值的操作关联起来的机制,而且它们允许属性值通过计算得到。

    在C#中,属性通过属性声明语法定义。属性声明语法的第一部分与域声明很相似,第二部分包括一个set过程和/或一个get过程。例如,在下面的例子中,PropertyDemo类定义了一个Prop属性。

    public class PropertyDemo {
    private string prop;
    public string Prop {
    get {
    return prop;
    }
    set {
    prop = value;
    }
    }
    }

    如果属性既允许读取也允许写入,如PropertyDemo类的Prop属性,则它同时拥有get和set存取过程。当我们读取属性的值时,get存取过程被调用;当我们写入属性值时,set存取过程被调用。在set存取过程中,属性的新值在一个隐含的value参数中给出。

    与读取和写入域的方法一样,属性也可以用同样的语法读取和写入。例如,下面的代码实例化了一个PropertyDemo类,然后写入、读取它的Prop属性。

    PropertyDemo pd = new PropertyDemo();
    pd.Prop = "123"; // set
    string s = pd.Prop; // get

    3.4、以引用方式传递简单数据类型的参数

    在Java中,当你把一个简单数据类型的值作为参数传递给方法时,参数总是以值的方式传递――即,系统将为被调用的方法创建一个参数值的副本。在C#中,你可以用引用的方式传递一个简单数据类型的值。此时,被调用的方法将直接使用传递给它的那个值――也就是说,如果在被调用方法内部修改了参数的值,则原来的变量值也随之改变。

    在C#中以引用方式传递值时,我们使用ref关键词。例如,如果编译并运行下面的代码,你将在控制台上看到输出结果16。注意i值被传递给ProcessNumber之后是如何被改变的。

    using System;
    public class PassByReference {
    public static void Main(String[] args) {
    int i = 8;
    ProcessNumber(ref i);
    Console.WriteLine(i);
    }
    public static void ProcessNumber(ref int j) {
    j = 16;
    }
    }

    C#中还有一个允许以引用方式传递参数的关键词out,它与ref相似。但是,使用out时,作为参数传递的变量在传递之前不必具有已知的值。在上例中,如果整数i在传递给ProcessNumber方法之前没有初始化,则代码将出错。如果用out来取代ref,你就可以传递一个未经初始化的值,如下面这个修改后的例子所示。

    using System;
    public class PassByReference {
    public static void Main(String[] args) {
    int i;
    ProcessNumber(out i);
    Console.WriteLine(i);
    }
    public static void ProcessNumber(out int j) {
    j = 16;
    }
    }

    经过修改之后,虽然i值在传递给ProcessNumber方法之前没有初始化,但PassByReference类能够顺利通过编译。

    3.5、C#保留了指针

    对于那些觉得自己能够恰到好处地运用指针并乐意手工进行内存管理的开发者来说,在C#中,他们仍旧可以用既不安全也不容易使用的“古老的”指针来提高程序的性能。C#提供了支持“不安全”(unsafe)代码的能力,这种代码能够直接操作指针,能够“固定”对象以便临时地阻止垃圾收集器移动对象。无论从开发者还是用户的眼光来看,这种对“不安全”代码的支持其实是一种安全功能。“不安全”的代码必须用unsafe关键词显式地标明,因此开发者不可能在无意之中使用“不安全”的代码。同时,C#编译器又和执行引擎协作,保证了“不安全”的代码不能伪装成为安全代码。

    using System;
    class UsePointer {
    unsafe static void PointerDemo(byte[] arr) {
    .
    .
    }
    }

    C#中的unsafe代码适合在下列情形下使用:当速度极端重要时,或者当对象需要与现有的软件(比如COM对象或者DLL形式的C代码)交互时。

    3.6、代理

    代理(delegate)可以看作C++或者其他语言中的函数指针。然而,与函数指针不同的是,C#中的代理是面向对象的、类型安全的、可靠的。而且,函数指针只能用来引用静态函数,但代理既能够引用静态方法,也能够引用实例方法。代理用来封装可调用方法。你可以在类里面编写方法并在该方法上创建代理,此后这个代理就可以被传递到第二个方法。这样,第二个方法就可以调用第一个方法。

    代理是从公共基类System.Delegate派生的引用类型。定义和使用代理包括三个步骤:声明,创建实例,调用。代理用delegate声明语法声明。例如,一个不需要参数且没有返回值的代理可以用如下代码声明:

    delegate void TheDelegate();

    创建代理实例的语法是:使用new关键词,并引用一个实例或类方法,该方法必须符合代理指定的特征。一旦创建了代理的实例,我们就可以用调用方法的语法调用它。

    3.7、包装和解除包装

    在面向对象的编程语言中,我们通常使用的是对象。但为了提高速度,C#也提供了简单数据类型。因此,C#程序既包含一大堆的对象,又有大量的值。在这种环境下,让这两者协同工作始终是一个不可回避的问题,你必须要有一种让引用和值进行通信的方法。

    在C#以及.NET运行时环境中,这个“通信”问题通过包装(Boxing)和解除包装(Unboxing)解决。包装是一种让值类型看起来象引用类型的处理过程。当一个值类型(简单数据类型)被用于一个要求或者可以使用对象的场合时,包装操作自动进行。包装一个value-type值的步骤包括:分配一个对象实例,然后把value-type值复制到对象实例。

    解除包装所执行的动作与包装相反,它把一个引用类型转换成值类型。解除包装操作的步骤包括:首先检查并确认对象实例确实是给定value-type的一个经过包装的值,然后从对象实例复制出值。

    Java对该问题的处理方式略有不同。Java为每一种简单数据类型提供了一个对应的类封装器。例如,用Integer类封装int类型,用Byte类封装byte类型。

    【结束语】本文为你比较了C#和Java。这两种语言很相似,然而,说C#是Java的克隆或许已经大大地言过其实。面向对象、中间语言这类概念并不是什么新东西。如果你准备设计一种面向对象的新语言,而且它必须在一个受管理的安全环境内运行,你难道不会搞出与C#差不多的东西吗?

  • apache+tomcat+mysql 负载平衡和集群『转载』

    2007-09-07 12:56:11

    摘自 http://www.wujianrong.com/archives/2007/08/apachetomcatmysql.html

    前言:
    公司开发了一个网站,估计最高在线人数是3万,并发人数最多100人。开发的网站是否能否承受这个压力,如何确保网站的负荷没有问题,经过研究决定如下:
    (1) 采用负载平衡和集群技术,初步机构采用Apache+Tomcat的机群技术。
    (2) 采用压力测试工具,测试压力。工具是Loadrunner。
    硬件环境搭建:
    为了能够进行压力测试,需要搭建一个环境。刚开始时,测试在公司局域网内进行,但很快发现了一个问题,即一个脚本的压力测试结果每次都不一样,并且差别很大。原来是受公司网络的影响,于是决定搭建一个完全隔离的局域网测试。搭建后的局域网配置如下:
    (1) 网络速度:100M
    (2) 三台服务器:
    负载服务器 :操作系统windows2003,
    Tomcat服务器:操作系统windows2000 Professional
    数据库服务器:操作系统windows2000 Professional
    三台机器的cpu 2.4 G, 内存 1G。
    软件环境搭建:
    软件的版本如下:
    Apache 版本:2.054,
    Tomcat5.0.30,
    mysql :4.1.14.
    JDK1.5
    压力测试工具:Loadrunner7.8。

    负载平衡方案如下:
    一台机器(操作系统2003)安装apache,作为负载服务器,并安装tomcat作为一个worker;一个单独安装tomcat,作为第二个worker;剩下的一台单独作为数据库服务器。
    Apache和tomcat的负载平衡采用JK1.2.14(没有采用2.0,主要是2.0不再维护了)。
    集群方案:
    采用Tomcat本身的集群方案。在server.xml配置。
    压力测试问题:
    压力测试后,发现了一些问题,现一一列出来:
    (1)采用Tocmat集群后,速度变得很慢。因为集群后,要进行session复制,导致速度较慢。Tomcatd的复制,目前不支持 application 复制。复制的作用,主要用来容错的,即一台机器有故障后,apache可以把请求自动转发到另外一个机器。在容错和速度的考虑上,我们最终选择速度,去掉 了Tomcat集群。
    (2) 操作系统最大并发用户的限制:
    为了采用网站的压力,我们开始的时候,仅测试Tomcat的最大负载数。 Tomcat服务器安装的操作系统是windows2000 Professional。当我们用压力测试工具,并发测试时,发现只要超过15个并发用户,会经常出现无法连接服务器的情况。经过研究,发现是操作系统 的问题:windows2000 Professional 支持的并发访问用户有限,默认的好像是15个。于是我们把操作系统全部采用windows2003 server版本。
    (3) 数据库连接池的问题:
    测试数据库连接性能时,发现数据库连接速度很慢。每增加一些用户,连接性能就差了很多。我们采用的数据库连接池是DBCP,默认的初始化为50个,应该不 会很慢吧。查询数据库的连接数,发现初始化,只初始化一个连接。并发增加一个用户时,程序就会重新创建一个连接,导致连接很慢。原因就在这里了。如何解决 呢?偶尔在JDK1.4下的Tomcat5.0.30下执行数据库连接压力测试,发现速度很快,程序创建数据库连接的速度也是很快的。看来JDK1.5的 JDBC驱动程序有问题。于是我们修改 JDK的版本为1.4.


     

    (4) C3P0和DBCP
    C3P0是Hibernate3.0默认的自带数据库连接池,DBCP是Apache开发的数据库连接池。我们对这两种连接池进行压力测试对比,发现在并发300个用户以下时,DBCP比C3P0平均时间快1秒左右。但在并发400个用户时,两者差不多。


     

    速度上虽然DBCP比C3P0快些,但是有BUG:当DBCP建立的数据库连接,因为某种原因断掉后,DBCP将不会再重新创建新的连接,导致必须重新启动Tomcat才能解决问题。DBCP的BUG使我们决定采用C3P0作为数据库连接池。
    调整后的方案:
    操作系统Windows2003 server版本
    JDK1.4
    Tomcat 5.0.30
    数据库连接池C3P0
    仅采用负载平衡,不采用集群。
    软件的配置:
    Apache配置:主要配置httpd.conf和新增加的文件workers.properties
    Httpd.conf:
    #一个连接的最大请求数量
    MaxKeepAliveRequests 10000
    #NT环境,只能配置这个参数来提供性能
    <IfModule mpm_winnt.c>
    #每个进程的线程数,最大1920。NT只启动父子两个进程,不能设置启动多个进程
    ThreadsPerChild 1900
    每个子进程能够处理的最大请求数
    MaxRequestsPerChild 10000
    </IfModule>


     

    # 加载mod_jk
    #
    LoadModule jk_module modules/mod_jk.so
    #
    # 配置mod_jk
    #
    JkWorkersFile conf/workers.properties
    JkLogFile logs/mod_jk.log
    JkLogLevel info
    #请求分发,对jsp文件,.do等动态请求交由tomcat处理
    DocumentRoot "C:/Apache/htdocs"
    JkMount /*.jsp loadbalancer
    JkMount /*.do loadbalancer
    JkMount /servlet/* loadbalancer
    #关掉主机Lookup,如果为on,很影响性能,可以有10多秒钟的延迟。
    HostnameLookups Off
    #缓存配置
    LoadModule cache_module modules/mod_cache.so
    LoadModule disk_cache_module modules/mod_disk_cache.so
    LoadModule mem_cache_module modules/mod_mem_cache.so


     

    <IfModule mod_cache.c>
    CacheForceCompletion 100
    CacheDefaultExpire 3600
    CacheMaxExpire 86400
    CacheLastModifiedFactor 0.1

    <IfModule mod_disk_cache.c>
    CacheEnable disk /
    CacheRoot c:/cacheroot
    CacheSize 327680
    CacheDirLength 4
    CacheDirLevels 5
    CacheGcInterval 4
    </IfModule>
    <IfModule mod_mem_cache.c>
    CacheEnable mem /
    MCacheSize 8192
    MCacheMaxObjectCount 10000
    MCacheMinObjectSize 1
    MCacheMaxObjectSize 51200
    </IfModule>
    </IfModule>
    worker. Properties文件
    #
    # workers.properties ,可以参考
    http://jakarta.apache.org/tomcat/connectors-doc/config/workers.html
    # In Unix, we use forward slashes:
    ps=


     

    # list the workers by name


     

    worker.list=tomcat1, tomcat2, loadbalancer


     

    # ------------------------
    # First tomcat server
    # ------------------------
    worker.tomcat1.port=8009
    worker.tomcat1.host=localhost
    worker.tomcat1.type=ajp13


     

    # Specify the size of the open connection cache.
    #worker.tomcat1.cachesize


     

    #
    # Specifies the load balance factor when used with
    # a load balancing worker.
    # Note:
    # ----> lbfactor must be > 0
    # ----> Low lbfactor means less work done by the worker.
    worker.tomcat1.lbfactor=900


     

    # ------------------------
    # Second tomcat server
    # ------------------------
    worker.tomcat1.port=8009
    worker.tomcat1.host=202.88.8.101
    worker.tomcat1.type=ajp13

     

    # Specify the size of the open connection cache.
    #worker.tomcat1.cachesize


    #
    # Specifies the load balance factor when used with
    # a load balancing worker.
    # Note:
    # ----> lbfactor must be > 0
    # ----> Low lbfactor means less work done by the worker.
    worker.tomcat1.lbfactor=2000


    # ------------------------
    # Load Balancer worker
    # ------------------------

     

    #
    # The loadbalancer (type lb) worker performs weighted round-robin
    # load balancing with sticky sessions.
    # Note:
    # ----> If a worker dies, the load balancer will check its state
    # once in a while. Until then all work is redirected to peer
    # worker.
    worker.loadbalancer.type=lb
    worker.loadbalancer.balanced_workers=tomcat1,tomcat2

     

    #
    # END workers.properties
    #

    Tomcat1配置:
    <!--配置server.xml
    去掉8080端口,即注释掉如下代码:-->
    <Connector
    port="8080" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
    enableLookups="false" redirectPort="8443" acceptCount="100"
    debug="0" connectionTimeout="20000"
    disableUploadTimeout="true" />


    <!--配置8009端口如下:-->
    <Connector port="8009"
    maxThreads="500" minSpareThreads="400" maxSpareThreads="450"
    enableLookups="false" redirectPort="8443" debug="0"
    protocol="AJP/1.3" />
    <!--配置引擎-->
    <Engine name="Catalina" defaultHost="localhost" debug="0" jvmRoute="tomcat1">

     

    启动内存配置,开发configure tomcat程序即可配置:
    Initial memory pool: 200 M
    Maxinum memory pool:300M
    Tomcat2配置:
    配置和tomcat1差不多,需要改动的地方如下:
    <!--配置引擎-->
    <Engine name="Catalina" defaultHost="localhost" debug="0" jvmRoute="tomcat2">

     

    启动内存配置,开发configure tomcat程序即可配置:
    Initial memory pool: 512 M
    Maxinum memory pool:768M
    Mysql配置:
    Server类型:Dedicated MySQL Server Machine
    Database usage:Transational Database Only
    并发连接数量:Online Transaction Processing(OLTP)
    字符集:UTF8
    数据库连接池的配置:
    我们采用的是spring 框架,配置如下:
    <property name="hibernateProperties">
    <props>
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
    <prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop>
    <prop key="hibernate.connection.url">jdbc:mysql://202.88.1.103/db</prop>
    <prop key="hibernate.connection.username">sa</prop>
    <prop key="hibernate.connection.password"></prop>

     

    <prop key="hibernate.show_sql">false</prop>
    <prop key="hibernate.use_sql_comments">false</prop>

     

    <prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
    <prop key="hibernate.max_fetch_depth">2</prop>

     

    <prop key="hibernate.c3p0.max_size">200</prop>
    <prop key="hibernate.c3p0.min_size">5</prop>
    <prop key="hibernate.c3p0.timeout">12000</prop>
    <prop key="hibernate.c3p0.max_statements">50</prop>
    <prop key="hibernate.c3p0.acquire_increment">1</prop>
    </props>
    </property>
    其他的没有额外配置。
    LoadRunner 常见问题:
    (1)sofeware caused connction:这种情况,一般是脚本有问题,或者loadrunner有问题。解决方法:重新启动机器,或者重新录制脚本,估计是loadrunner的bug。
    (2)cannot connect to server:无法连接到服务器。这种情况是服务器的配置有问题,服务器无法承受过多的并发连接了。需要优化服务器的配置,
    如操作系统采用windows 2003 server,
    优化tomcat配置:maxThreads="500" minSpareThreads="400" maxSpareThreads="450"。但是tomcat 最多支持500个并发访问
    优化apache配置:
    ThreadsPerChild 1900
    MaxRequestsPerChild 10000
    其他的错误如:
    Action.c(10): Error -27791: Server has shut down the connection prematurely
    HTTP Status-Code=503 (Service Temporarily Unavailable)
    一般都是由于服务器配置不够好引起的,按照问题(2)处理,如果仍旧不行,需要优化硬件和调整程序了。
    Apache问题:
    (1) File does not exist: C:/Apache/htdocs/favicon.ico:
    这个问题是apache,htdocs目录没有favicon.ico文件引起的,该文件是网站的图标,仅在firefox,myIE等浏览器出现。
    (2) 图片无法显示:
    配置apache后,却无法显示图片。
    解决方法:把程序的图片,按照程序结构copy到apache的htdocs目录下。
    (3) 无法处理请求:
    当我们输入 ***.do 命令后,apache确返回错误信息,而连接tomcat却没有问题。原因是没有把.do命令转发给tomcat处理。解决方法如下:
    在apache配置文件中配置如下内容:
    DocumentRoot "C:/Apache/htdocs"
    JkMount /*.jsp loadbalancer
    JkMount /*.do loadbalancer



    总结:
    网站的压力测试,涉及的知识面挺广的,不仅要熟悉压力测试工具,还要知道如何配置和优化应用服务器和数据库,并且需要知道如何优化网络、操作系统、硬件系统。
    测试中不仅要善于发现问题,要知道如何解决。最重要的一点,要有良好的测试方法。刚开始测试时,可以从最简单的测试脚本入手,不需要太复杂的脚本,这样便 于发现问题。如我们刚开始时,就从一个简单的下载登陆界面的脚本入手,测试一个tomcat的压力负载。一个简单的获取登陆的脚本,帮助我们优化了 tomcat的配置;后来再测试数据库连接,也是一个简单的数据库连接脚本,帮助我们优化了数据库连接池;然后利用这些简单的脚本,测试apache的负 载平衡,优化了apache配置。最后运行复杂的脚本,模拟多种角色的用户在不同时间下的处理,以测试网站压力负载。

  • C Functions referring String in LoadRunner『转载』

    2007-09-05 13:07:22

    摘自http://www.51testing.com/?53222/action_viewspace_itemid_9116.html


    r([ hav$y4lA^$^18755strlen

      功能:计算字符串s的长度
    (]k9T7w)O)k WcLK18755  51Testing软件测试网wb`^J
      说明:返回s的长度,不包括结束符NULL。51Testing软件测试网\ cH;W-V/N
     
    Sw}#b W+|R[q ag18755  举例:51Testing软件测试网RZ5S:Q"@zUS
          // strlen.c51Testing软件测试网$Pm [ @T+N Kd
          51Testing软件测试网2\v:y0x:d)dn C
          #include <syslib.h>
    S/b*D)c#u/Cw+BA N18755      #include <string.h>

          main()51Testing软件测试网 |vy3n+_ T\R
          {
    +Sk7faxu bp*E;S18755        char *s="Golden Global View";51Testing软件测试网L#s2U!CF1W-C-gi
           
    R'} j GHb V18755        clrscr();
    H4Z"q `Wn18755        51Testing软件测试网p2SS6j9J'W*V
            printf("%s has %d chars",s,strlen(s));

            getchar();51Testing软件测试网EE?%U's-n@
            return 0;
    8wvE.y+[)s18755      }

    strcpy

      功能:把src所指由NULL结束的字符串复制到dest所指的数组中。
    @b5C8TA5__I#_-s w18755  51Testing软件测试网 r8jS(V\7F qS
      说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
    {C/j lH6}"O;}?6\18755        返回指向dest的指针。51Testing软件测试网Qj|(u1A
      51Testing软件测试网0W9y8C`+x'oS6I i2b
      举例:
    9p'QlM:gS6w7S(f18755      // strcpy.c51Testing软件测试网$c.M F~;o(Y(aG8P
         
    4g2Q'Z@W%J}%YB,b18755      #include <syslib.h>51Testing软件测试网0]?6c}tO
          #include <string.h>

          main()
    6q@RC2NC18755      {51Testing软件测试网)TL(O3R_(`S}6MR
            char *s="Golden Global View";51Testing软件测试网_ |N]cbJ|h
            char d[20];51Testing软件测试网2EM`?4X L`]
           
    Bz \{:d2g18755        clrscr();
    z-Sb+G:S18755       
    :S ~9zG5i/jn18755        strcpy(d,s);
    T#Y5H+pU`18755        printf("%s",d);

            getchar();
    @8] bI%V@18755        return 0;
    !RM(P]c`D;O!na18755      }

    strncpy

      功能:把src所指由NULL结束的字符串的前n个字节复制到dest所指的数组中。51Testing软件测试网6\B*X-Bd s d
      51Testing软件测试网\]}k w8T5@l
      说明:
    1pEW'lJ'u7U18755        如果src的前n个字节不含NULL字符,则结果不会以NULL字符结束。51Testing软件测试网7W0L&H9\6Ovb
            如果src的长度小于n个字节,则以NULL填充dest直到复制完n个字节。51Testing软件测试网6g[C*f)RO6C
            src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。51Testing软件测试网m;L-Bj2vk@{a/G
            返回指向dest的指针。
    G u Meie18755 
    #c's9Fe+jb$l18755  举例:51Testing软件测试网%IX9a#^r v4O
          // strncpy.c51Testing软件测试网2W Aq W C T9}A?+U
         
    *B$b7oI]'uJ6ND18755      #include <syslib.h>51Testing软件测试网C6b#[ ?6th
          #include <string.h>

          main()51Testing软件测试网YK\j-e(Y H
          {
    w.jv&Y2f;{6|7aF18755        char *s="Golden Global View";
    #o4dDdv18755        char *d="Hello, GGV Programmers";51Testing软件测试网E:Ft-?$NR)J-V`yt
            char *p=strdup(s);51Testing软件测试网 w,?B-S6A(rC
            51Testing软件测试网F2Ke.T`p
            clrscr();
    +] {8b,s2`e#s je18755        textmode(0x00);  // enable 6 lines mode
    0d RV$oS18755                51Testing软件测试网i6]jDM(^(A
            strncpy(d,s,strlen(s));
    6FS#t0WrI%k18755        printf("%s\n",d);51Testing软件测试网#s$@b*}7C xwe
            51Testing软件测试网5gr$v _&ud E,TTU8Ifm
            strncpy(p,s,strlen(d));51Testing软件测试网JuK!s9c:yw
            printf("%s",p);
    0J.Zc \]d18755       

            getchar();
    bmF@wH/]18755        return 0;51Testing软件测试网0mA`7V%r#Y |
          }

    strcat

      功能:把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。
    :g9L(LK\0haB9{18755  51Testing软件测试网b Y5UjqBk
      说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
    @4lox2`"[18755        返回指向dest的指针。51Testing软件测试网x7o8G"l@"@R
     
    "XJ&F;m|.q,z3}18755  举例:
    -C eJ9@o-s18755      // strcat.c51Testing软件测试网m Y1c-Q+BZ+A3H
          51Testing软件测试网 `"I-?5k;r'HV
          #include <syslib.h>
    @_F#Y2hf`18755      #include <string.h>

          main()
    Y)A2r$`3H18755      {
    N4Cp {KejR18755        char d[20]="Golden Global";51Testing软件测试网Z.dab Kh:xT$f
            char *s=" View";
    ]4UY4Q~"aO$l*d/u18755       
    `/tZKd)E C18755        clrscr();51Testing软件测试网v'h(L F Qn ?8GF
           
    /Pi9Y*~x"G8c V18755        strcat(d,s);
    _g`P)f GMF18755        printf("%s",d);

            getchar();
    &W{6H \.i-o18755        return 0;51Testing软件测试网E4Oz3\ xy
          }

    strncat

      功能:把src所指字符串的前n个字符添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。
    )@ sb z ~6uNf18755  51Testing软件测试网5EL7C` x1op
      说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。51Testing软件测试网/w2T2t&j%P\ C
            返回指向dest的指针。51Testing软件测试网/Ii6STo{._)LQ
      51Testing软件测试网Q(nJ/E(mt
      举例:51Testing软件测试网B~6P%FDq4a*hj9G ~
          // strncat.c
    -En d*d6F [#Cw18755      51Testing软件测试网8_5`!m Y.O-og
          #include <syslib.h>51Testing软件测试网Rw|4C(\6T
          #include <string.h>

          main()
    0[ Z j}'pgd n18755      {51Testing软件测试网:I&Gh km;PHL#F
            char d[20]="Golden Global";51Testing软件测试网4y h/v-AM3r6W+X
            char *s=" View WinIDE Library";51Testing软件测试网lc:|bi1gz
           
    +mv6W)O LeBy;p`u5\18755        clrscr();
    C.?LW `2Q ]18755       
    R7A w/\6hh]18755        strncat(d,s,5);
    E{7_1t'?\$PK18755        printf("%s",d);

            getchar();51Testing软件测试网 Z,RJ i!w
            return 0;51Testing软件测试网:?sD~@o\
          }

    strcmp

      功能:比较字符串s1和s2。
    :@(Ss|4b_18755 
    Y@X[;]:Sg18755  说明:51Testing软件测试网$I6N7uQpwZc/wR
            当s1<s2时,返回值<051Testing软件测试网zdw` gS
            当s1=s2时,返回值=051Testing软件测试网}A+Zxlo
            当s1>s2时,返回值>0
    5A8lRz,S O|^F3j18755 
    (\0D&D5P3v)[ h18755  举例:

          // strcmp.c
    jR5}9OE18755     
    ~ htMtb18755      #include <syslib.h>51Testing软件测试网 {!Ks(y\ X Yau
          #include <string.h>

          main()51Testing软件测试网8T#A#hJfkI"w |
          {51Testing软件测试网9QE o {zHUI
            char *s1="Hello, Programmers!";51Testing软件测试网dy C!m1nJ,p&`:K+s?v
            char *s2="Hello, programmers!";
    _%F6N/\[O:|18755        int r;
    ,KQ_?;f)\`18755       
    o.S*`lF2iKh*L&s18755        clrscr();51Testing软件测试网)g0Vv;I o
           
    dG MJ$FZG;pm18755        r=strcmp(s1,s2);
    k bToJ}18755        if(!r)51Testing软件测试网"]U]r5f]/{RE5LbR
              printf("s1 and s2 are identical");
    TVS|rvF/Or#k/?18755        else
    5{ ?+TkaSoR uh)k*`18755        if(r<0)
    #Wf;N6GyM,yR18755          printf("s1 less than s2");
    [;N?-iiE&Q.y18755        else
    &owr` Ii8`hQ18755          printf("s1 greater than s2");51Testing软件测试网;}n j~"L3s
           

            getchar();51Testing软件测试网2u V r;kq fVU+K`
            return 0;51Testing软件测试网 `:Q Cc!{-W.ps
          }

    strncmp

      功能:比较字符串s1和s2的前n个字符。
    8d#Z.E G\ ip18755  51Testing软件测试网_8Q9m{ o AJ s.y
      说明:51Testing软件测试网 Jm7JD` ^#V
            当s1<s2时,返回值<0
    V,^^ }K`8wx18755        当s1=s2时,返回值=0
    |&iQ+r1D/IJ/S?18755        当s1>s2时,返回值>0
    1\7ng-l8}2k-bX1?w~18755  51Testing软件测试网I`SzU\2Lf
      举例:

          // strncmp.c51Testing软件测试网Q6u tX%S k@K'w-G c
          51Testing软件测试网k$D(Ph"o{s$x
          #include <syslib.h>51Testing软件测试网?*W.QQ(r t;u1H~
          #include <string.h>

          main()
    +Y?5e$s[ C4S H q&N18755      {
    9zt4WVAo2`VY18755        char *s1="Hello, Programmers!";
    1Y V1`1O|BKR Wk18755        char *s2="Hello, programmers!";
    1X8Y gC p&W0b X-iB18755        int r;
    6zl!k$c _H-`fv18755        51Testing软件测试网*Lu @8QF%m
            clrscr();51Testing软件测试网|,E4yF bs^
            51Testing软件测试网L2d-Bs`8ow1rU
            r=strncmp(s1,s2,6);
    N7Qv9G0TY9{L m9U18755        if(!r)51Testing软件测试网\+nIiMS*W5a!T
              printf("s1 and s2 are identical");51Testing软件测试网ra{1M|h6@#x
            else51Testing软件测试网;irH V5^l"p0q6F5e
            if(r<0)51Testing软件测试网jq3G(p-SN0QX
              printf("s1 less than s2");
    8}7Vy;`-K*J18755        else
    #Y%V0Y m+} sV}| _18755          printf("s1 greater than s2");
    |\'Mf&Yh \']:T18755        51Testing软件测试网IY @}[(z lx
            getchar();
    j?,A D&F3F t v LM2jU'h18755        clrscr();
    t c \(D-D9vMj3w8zU18755        51Testing软件测试网+u4G'o3f/G j6D
            r=strncmp(s1,s2,10);
    $Y^!Vf Wa Jt ^18755        if(!r)51Testing软件测试网M(m!a8x,M7z
              printf("s1 and s2 are identical");51Testing软件测试网4Y3e ?v4AW/sB
            else51Testing软件测试网h$e.LO(^Q f
            if(r<0)51Testing软件测试网 s%zw3yZ
              printf("s1 less than s2");51Testing软件测试网![ubn1R$U-RY&@
            else51Testing软件测试网2v7R Ugh
              printf("s1 greater than s2");

            getchar();
    '_ lD"nIK18755        return 0;51Testing软件测试网$z%T9OI"Qo,cg
          }

    strstr

      功能:从字符串haystack中寻找needle第一次出现的位置(不比较结束符NULL)。
    4BM7MrKaT18755  51Testing软件测试网IPJ Y"\ L(Vo&s
      说明:返回指向第一次出现needle位置的指针,如果没找到则返回NULL。51Testing软件测试网9_$`G9o-B |4KZJ
     
    hqp\;sO"jg+x8Q]18755  举例:
    V)kdQ,R(P DF18755      // strstr.c
    Nah1D;D|t{18755     
    'W0S1p4W }T8u D7z \18755      #include <syslib.h>
    Za J6x2k~!Z-n18755      #include <string.h>

          main()51Testing软件测试网0m.Y1g4c"xI,B
          {51Testing软件测试网*eQ(J_ T)w:{
            char *s="Golden Global View";
    +Qe,C)lC X18755        char *l="lob";
    7P,C0_ G)^ n18755        char *p;51Testing软件测试网O zeUy2n
            51Testing软件测试网'T)_7TKp"y'zP h]
            clrscr();
    B O"z#ucb/jI18755       
    "Y4l0f;uua:\18755        p=strstr(s,l);
    P ^"M(K0Y$Q g8x9{F18755        if(p)51Testing软件测试网 L9LfQ2Gx
              printf("%s",p);
    -Y3~J/_#ZCoq4P?18755        else51Testing软件测试网KQ.td Z J@a-W
              printf("Not Found!");

            getchar();51Testing软件测试网4?w7B` WVsS:u `1t:s
            return 0;51Testing软件测试网{&z#ah Nc|
          }

    strchr

      功能:查找字符串s中首次出现字符c的位置51Testing软件测试网]~Y wX G{
     
    id8at;S6N18755  说明:返回首次出现c的位置的指针,如果s中不存在c则返回NULL。
    VO Ev:]7o~18755  51Testing软件测试网T;K&u$h8Oh
      举例:51Testing软件测试网X3`;V@/[4x
          // strchr.c
    ev o6Ly.q18755     
    ;uFD*{X4y'KA5R;R18755      #include <syslib.h>51Testing软件测试网@ Ih1]b{ p Ib
          #include <string.h>

          main()51Testing软件测试网kWO'A%J
          {51Testing软件测试网H,n5SfDc%B'd
            char *s="Golden Global View";
    [*F8y_ [8Ty1y18755        char *p;
    M t/[3Q+e.x,I$A18755       
    (Rp#}4y5ks5LM18755        clrscr();51Testing软件测试网WmNbi1o
            51Testing软件测试网] NRpqr,e
            strchr(s,'V');
    7Z4uByZB,}h18755        if(p)
    B rX;duH!OQ&?m18755          printf("%s",p);
    a)Cb KJ+P5b C [ l18755        else51Testing软件测试网U;^5V@"`:Bb [&z
              printf("Not Found!");

            getchar();
    -P2vJWi;P+}18755        return 0;
    3P%SgHl2T0Q!M:\18755      }

    strdup

      功能:复制字符串s51Testing软件测试网Q1|'QQ \ E&g Je
      51Testing软件测试网R-V_(Btx
      说明:返回指向被复制的字符串的指针,所需空间由malloc()分配且可以由free()释放。51Testing软件测试网 ?,`V3hg^D7XQ4nr
      51Testing软件测试网F"M X"U U
      举例:
    gE6a'hs_ }i5};U18755      // strdup.c51Testing软件测试网6}6eB2i&jb
         
    O5m8U&N~18755      #include <syslib.h>
    j \0cMY0J18755      #include <string.h>

          main()51Testing软件测试网bV S W2T4eX
          {51Testing软件测试网!\q0FrM#d/Vy
            char *s="Golden Global View";
    *h6o*yhh8b W;b18755        char *d;51Testing软件测试网NnNX{~N
            51Testing软件测试网r(y"Q2H%B l%I.T}
            clrscr();51Testing软件测试网QG8wE4B9xd$e0^KZ
            51Testing软件测试网i~ ? Q@c*^dS
            d=strdup(s);51Testing软件测试网 B]yp,` ?9caJ
            printf("%s",d);

            getchar();51Testing软件测试网5t0[c,@"y LG
            return 0;
    ]x6f_7Mf0R18755      }

     

  • 测试员的工作效率和所查毛病的数量『转载』

    2007-09-05 12:59:23

    摘自 http://www.51testing.com/?29251/action_viewspace_itemid_15658.html

     

    测试员的工作效率和所查毛病的数量

    测试员的工作效率是否应该用所查毛病的数量来测量?回答“不可以。”我原来以为这样的衡量方式是正确的业绩衡量方式。但是这种想法只能肤浅地表达一个测试员工作业绩,而且在不同的因素影响下,和不同的情况下,是无法真正反映一个测试员的业绩,如果简单利用测试员在一定周期内找到的毛病数量来评判业绩,对测试员来说是不公平的,同时会促使测试员以对抗的态度和开发者较劲,将合作关系变成相互歧视的关系。

    有许多各种因素能够影响一个测试员找到的毛病的数量,举几个例子来说,如果一个测试员进行头到尾的测试,他的测试任务中很大一部分时间用于清理系统,重装系统,然后进行测试,在整个过程中,测试占用20分钟,这些清理和重装需要4小时,这样的活动,肯定会影响找到的毛病的数量。这并不是一个很好的例子。因为很多步骤可能可以自动化,然后提高测试员的工作效率。但总有一些情况下,手动安装是必须或是必须等待自动化安装完成,然后才能进行测试,由于这些活动(清除,重装)花掉的时间过多,而给测试的时间段过短而造成测试员无法查找更多的错误。

    著名的测试专业培训师和作家Cem Kaner曾经提到过一个案例,在一个工程开发完毕后的测试中,他手下的一个测试员在测试自己的部件时找到很少一些毛病,但是这些毛病的影响是很坏的,这些毛病的数量远不及其他测试员找到的多。当时开发组的老板对这个测试员发现的毛病的数量不够信任,于是要求Cem Kaner再增加更多的人手来进行同一方面的测试,Cem Kaner找了一个资深的测试员协同那个原来的员工,两人后来一直没有发现太多的毛病,但是两人还是找到了一些很糟糕的问题。这些重大的问题把整个产品的推出时间推后了6个月。在工程结束后,后来的测试员高度赞誉了前面的员工的工作。再后来等到产品卖出后,客户在这个部件中发现的问题和其他部件相比是微乎其微。

    我在测试过程中,发现另外一个问题,就是开发者的工作能力和测试员所发现的毛病数量是成反比的。开发者的设计水平越高,测试员在其产品中找到的问题也是越少。我曾经对两个不同程序员开发的部件中进行源码测试,第一个是很有能力的,第二个就有点马虎。我在第一个程序员开发的产品中找到几个问题不大的毛病,但是在第二个程序员的开发的产品中找到找到不少各总各样的问题。这也说明产品自身的质量好坏决定测试员拿到产品后所发现的毛病数量。这也顺便带出一个新的问题,如果测试员接到一个已经经过不少修改的产品,里面的能找到的毛病数量已经很少了,这个测试员不一定能在测试过程中找到多少问题。还有就是测试员自己的技术问题,刚出校的大学生,和刚从开发者转变成测试员的,技术不一定很好,这也会影响他们找到的毛病数量。对这些新人,不能苛求发现的毛病数量。

    如果测试员在老板的允许下,进行流程改进,自己设计开发自动化测试工具,为以后的工作奠定基础,但是一时间没有足够的时间进行测试,这也会影响自己找到的毛病的数量。或是帮助新人适应工作环境,给新人提供问题解答,这也会影响自己找到的毛病的数量。同时也影响很多好的测试员花费时间在文档总所有这些例子,还有更多各种各样其他未列举的例子都能很好地说明不能轻易用毛病的数量来说明一个测试员的业绩。

    如果老板使用毛病的数量来说明一个测试员的业绩会造成什么后果,首先,测试员会故意将影响力小,微不足道的各种毛病,甚至已经存在的毛病报告出来,以增加自己发现的毛病数量。这种做法浪费所有人的时间,开发者,老板,测试员。开发者会开始怀疑,甚至轻视测试员的报告造成毛病泄漏错误。同时造成开发者测试员之间的政治性冲突。再者,测试员会开始制造大量肤浅测试案例来进行大网捞大鱼的,他们不会用心设计覆盖面更深,更复杂的案例来找出潜伏更深,影响更大的问题。使用毛病的数量来说明最终是个很不公平的做法,它能伤害好的测试者在帮助他人,仔细做好文档总结工作,在测试中花费时间来设计更好的测试工具和改进工作流程, 甚至妨碍测试员之间的技术交流,和帮助新人上手。

    在考核测试员的业绩方面,没有什么准确地手段能百分百地保证主管来进行公平的评估,最好的方法是注意每个人的日常动向,向测试员周围的人来问取这个测试员的平时的工作能力,交流能力,在测试中有没有做出什么贡献。从其他方面也可以评判测试员的业绩,比如他的毛病报告的质量,他的文档总结,他在工作实践中的工具开发,他和其他工作人员的交流互动等等。考核要全面,才能显示管理者的开明和公正,也能显示出管理者对整个项目的进展有一定的了解,让大家信服。作为管理者,时不时地关注下属的工作进度能够帮助评估一个下属的工作业绩。管理者最好能了解每个员工保证完成的任务和期内真正完成的任务来对比,获得下属的实际工作进度。管理者通过了解和下属工作的开发者的反馈,诸如测试员能够查找出重大的毛病问题,能够为开发者的设计提供建设性的建议,能够分担毛病解析,能准确详细地描述毛病。管理者所要做的另一件事是,和组里其他的测试员了解属下的工作情况,看看属下是否帮助其他组员解决面对的问题,是否能够很好地进行工作上的交流,是否和其他组员一起合作做好本职工作,在本职工作的基础上能够完成更多的工作等等。最后,在评估时,要了解下属的在工作范围内外所完成的任务,在整个开发中发挥的作用等等。只有这样才能给测试员公正的业绩评估。

     

  • Web安全测试学习笔记(Cookie&Session) 『转载』

    2007-08-29 09:18:45

     

    一,Session:含义:有始有终的一系列动作\消息
    1,  隐含了“面向连接” 和“保持状态”两种含义
    2,  一种用来在客户端与服务器之间保持状态的解决方案
    3,  也指这种解决方案的存储结构“把××保存在session里”

    二, http 协议本来是无状态的,所以引进了cookiesession机制来保持连接状态

    cookiesession 机制之间的区别与联系:
    cookie机制采用的是在客户端保持状态的方法
    session机制采用的是在服务器端保持状态的方案,由于在服务器端保  持状态的同时必须要求客户端提供一个标识,

    三,关于cookie机制
    Cookie 的使用是由浏览器按照一定的原则在后台自动发送给服务器的,浏览器会检查所有存储的cookie,如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置,则把该cookie附在请求资源的http请求头上发送给服务器。
    存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而保存在内存里的cookie,不同的浏览器有不同的处理方式,对于IE,在一个打开的窗口上按CTRL N(从文件菜单)打开的窗口可以与原窗口共享cookie,而使用其他方式新开的IE进程则不能共享已经打开的窗口的内存cookie
    Cookie的内容包括: 名字,值,过期时间,路径和域

    四,关于session的机制
        当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个请求是否含了一个session 标识(session id),如果有,则说明以前为该客户创建了一个session,服务器就按照session id把这个session检索出来用,一般一个cookie的名字就是类似于session ID,如果cookie被禁止的时候(cookie可以被人为的禁止),经常使用重写URL的方式,把session ID附加在URL路径后面,为了在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id
        人们以为:“把浏览器关闭了,session 就小时了”其实不对,除非程序通知服务器删除一个session,否则服务器会一直保留,而程序一般都是在用户作log off的时候发个指令去删除session。人们之所以会产生这种错觉,是因为大部分session会采用cookie来保存session,而关闭浏览器后这个session就消失了,如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的http请求头,把原来的session id发送给服务器,则再次打开浏览器,其实是可以再次找到之前的session id的。所以设置失效时间可以起到一定的保护作用。

    五,关于session的一些问题
    1,  session何时被创建: 不是在客户端访问时就被创建,而是在服务器端调用httpservletRequest.getSession(true)时才被创建。
    2,  session何时被删除:  A,程序调用httpSession.invalidate(),B距离上一次收到客户端发送的session id时间间隔超过了session的超时设置 C  服务器进程被停止(非持久session
    3,  如何做到关闭浏览器同时关闭session  严格说做不到,可以让所有的客户端页面使用window.onclose来监视浏览器的关闭东西,然后向服务器发送一个请求来删除session,但是对于浏览器崩溃或者强行杀死进程时仍然无能为力。

351/212>
Open Toolbar