qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

谈数据库主键选取策略

  INT和GUID,究竟选谁?

  关于数据库主键的选取策略,大家都是在INT和GUID两者中徘徊。忘了那些喋喋不休的争论吧!毕竟鱼与熊掌,不可兼得。在这篇文章中,我们不再关注它们的优缺点,自觉先行做点功课哦!

  如小标题,如果真要选,我会选谁?肯定地说,我会选GUID,又或者两者都选上。后者情形下,使用GUID做主键、INT做小二,INT在业务层生成,这要即使重复了,也不碍事,且INT是要反馈给前端的,定时做一个防冲突检测。如果让用户记忆或反馈那GUID字符串(去连接字符后32位),可以直接去跳楼了!

  INT和GUID,究竟谁快?

  使用INT或GUID做主健,究竟谁更快?为回答这个问题,我们先看下面的表格内容:

  解释一下:

  1、uniqueidentifier存储为二进制值,为什么是16字节呢?0~f 共16 种表示,有16*16=256,也有2^8=256(值域为0~255),去掉四个连接字符,即表示为16字节。

  2、varchar和nvarchar属变长型,存储时会增加一个int类型(四个字节)记录内容长度。

  3、nchar和nvarchar类型存储为Unicode数据,占用两个字节,所以字节数要算双份。

  谁会更快?

  1、勿庸置疑,INT肯定是最快的,甚至你会选择int而不是bigint。

  2、其次,谁会更快?当选uniqueidentifier。

  3、项目中,选用了varchar、nchar、nvarchar中某一类型?只怕你会是神,不是人或妖。

  INT和GUID,谁主沉浮?

  项目中,如果你是使用INT做主健,那么接下来的内容可以直接略过?因为你已经得到了答案。

  写这篇随笔的主要目的,是要告诉大家,使用GUID做主键时,特别要注意索引与排序问题。

  GUID做主键,字段类型为char(36),数据记录索引与排序依据肯定是字符串的从左到右,即:12345678-0000-0000-0000-000000000000

  GUID做主键,字段类型为uniqueidentifier,数据记录索引与排序依据将是后六字节,即:00000000-0000-0000-0000-1234567890ab

  为什么会这样?数据存储为uniqueidentifier时,会体现为SqlGuid 结构。

  MSDN描述有:SqlGuid使用 SQL Server行为实现CompareTo,该行为只计算值的最后6个字节。Guid 计算全部 16 个字节。

  结束语

  为了验证所说,你可以这样做:建表并添加uniqueidentifier字段类型,随机插入几万条记录,然后观察后十二位字符的排序情况,或参考下面截图。

posted @ 2012-08-01 10:46 顺其自然EVO 阅读(904) | 评论 (0)编辑 收藏

软件工程的实现与测试

  实现

  编码注意事项

  ● 写程序前先简化算数表达式和逻辑表达式,并用括号使逻辑表达式和算术表达式次序清晰

  ● 尽量避免大量使用镶套结构,仔细研究镶套循环,以确定是否存在有语句可以从内层往外移

  ● 不要节约空间而把多个语句写在一行中

  ● 尽量避免复杂的条件测试,减少对非条件的测试

  ● 尽量避免使用多维数组,指针和复杂的表

  ● 使用执行时间短的算数运算

  ● 尽量使用整数运算和布尔表达式,不要混合使用不同的数据类型

  输入输出

  1、所有输入输出都应该有缓冲,以减少用于通信的额外开销

  2、对二级存储(如磁盘)应选用最简单的访问方式

  3、二级存储器的输入输出应该以信息组为单位进行

  4、如果超高效的输入输出很难被人理解,则不应该采用这种方式

  5、设计良好的输入报表,保持输入格式简单

  6、使用数据结束标记,不要要求用户指定数据数目

  测试

  测试步骤

  ● 模块测试

  ● 子系统测试

  ● 系统测试

  ● 验收测试

  在测试的类型上有以下几种

  ● 回归测试:把现在的软件测试结果和上个版本的测试结果做比较看有没有退步

  ● 功能测试:侧重于系统功能测试,看是不是达到了用户的要求

  ● 单元测试:针对每个相对独立的模块的测试,在软件的层次上看该模块能否完成设计要求

  ● 负载测试:在整个系统在大负载仿真条件下,测试系统的实际能力

  ● 验收测试:测试的不只是功能问题,还有许多细节问题

单元测试重点

  ● 先判断功能是不是错误引起(如舍入误差就不是由错误引起的)

  ● 模块接口:模块接口测试主要检查下述几个反面-参数数目,次序,属性,单位系统与单元是否保持一致;是否修改只作输入用的变元;全局变量的定义和用法在各个模块中是否一致

  ● 局部数据结构

  ● 重要执行通路:在测试期间选择最有代表性,最可能发现错误的执行通路进行测试十分关键

  ● 出错处理通路:

    ● 对错误的描述是难以理解

    ● 记下错误与实际遇到的错误不同

    ● 在对错误进行处理之前,错误条件已经引起系统干预

    ● 对错误的处理不正确

    ● 描述错误的信息不足以帮助确定造成错误的位置

  调试途径

  ● 蛮干法:仅当所有其他方法都失败了得情况下才用

  ● 回溯法:从症状发现地方开始,人工沿着程序的控制流往回追踪分析源程序代码,知道找到错误为止,调试小程序最有效的方法

  ● 原因排除法:

    ● 对分查找法:如果已经知道每个变量在程序内的若干个关键的正确值,则可以用赋值语句或输入语句在程序中的附近注入这些变量的正确值,然后运行程序并检查所得到的输出

    ● 归纳法:是从个别现象推断出一般性结论的思维方式,使用这种调试程序时,首先把和错误有关的数据组织在一起分析,以便发现错误原因

    ● 演绎法:从一般原理或前提出发,经过排除和精华的过程推导出结论,采用这样的方法,首先设想出所有可能出错的原因,然后试图用测试来排除每一个假设的原因

  两个重要测试技术

  白盒子技术

  目的:

  在测试者完全知道程序的结构和处理算法.按照程序内部的逻辑测试程序,检测程序中的主要执行通路是否都能按照预定的要求工作.又称机构测试.

  逻辑测试的覆盖种类:

  ● 语句覆盖: 至少每个语句都应该执行一次.

  ● 判断覆盖: 每种判断的每种可能的结果都因该至少执行一次.也就是每个判断的分子都至少执行一次.

  ● 条件覆盖: 每个判断表达式的每个条件都取到各种可能的结果

  ● 判定条件覆盖: 有时候判断覆盖不一定包含条件覆盖,条件覆盖不一定包含判断覆盖.所以为了满足两种覆盖出现了这个覆盖.

  ● 条件组合覆盖: 选取足够多的测试数据,使的每个判断表达式中条件的各种可能组合都至少出现一次.

  ● 路径测试:选取足够多的测试数据.使程序的每条可能路径都被执行一次.

  ● 其他覆盖: 点覆盖/边覆盖

  三种基本测试:

  ● 基本路径测试步骤:

    ● 根据过程设计结果画出相应的流图

    ● 计算流程图的复杂度

    ● 确定线独立路径的基本集合

  ● 条件测试:

    ● 每个判断的分子都至少执行一次

    ● 每个判断表达式的每个条件都取到各种可能的结果

    ● 如果条件不正确,则至少条件的一个成分不正确

      ● 布尔运算符错

      ● 布尔变量错

      ● 布尔括弧错

      ● 关系算符错

      ● 算数表达式错

  ● 循环测试:

    ● 简单循环:

      ● 跳过循环

      ● 只通过一次循环

      ● 通过两次循环

      ● 通过m次循环(m<n-1)

      ● 通过n-1次循环,通过n次循环,通过n+1次循环(n最大允许循环数)

    ● 镶套循环:

      ● 从最内层循环开始测试,把其他循环都设置为最小值

      ● 对最小层实行简单循环测试,而外层循环的迭代参数(如循环计数器)取最小值,并为一些越界值.

      ● 由内向外,对下一个循环进行测试,但保持所有其他外层循环为最小值。


 黑盒子技术

  特点:

  完全不考虑程序内部结构,只检测程序功能是不是正常,是否适当地接受输入数据并产生正确的输出信息,运行时是不是能保持外部信息的完整性

  力图发现的错误类型:

  ● 功能不正确或遗漏功能

  ● 界面错误

  ● 数据结构错误或外部数据库访问错误

  ● 性能错误

  ● 初始化和终止错误

  设计黑盒子方案时应该考虑的问题:

  ● 怎样测试功能有效性

  ● 哪些类型的输入可构成好的测试用例

  ● 系统是否对特定的输入值特别敏感

  ● 怎样划定数据类的边界

  ● 系统能承受什么样的数据率和数据量

  ● 数据的特定组合将对系统运行产生什么影响

  黑盒子技术测试的标准:

  ● 测试用例要少但合理测试所需要设计的测试用例数

  ● 测试用例能指出某些类型的错误,而不是单单指出与特定测试相关的错误是否存在

  等价划分:

  ● 解释:

    ● 把程序的输入域划分成若干个数据类

  ● 等价划分的六条经验:

    ● 如果规定了输入值范围,可分输入在范围类,和输入值小于范围或大于范围

    ● 如果规定了输入数据的个数,分输入个数在个数内,在个数外,和等于个数


    ● 如果如果规定了输入数据的一组值,而程序对不同输入值做不同处理,则每个允许的输入值是一个划分,不输入是一个划分

    ● 如果规定输入数据必须遵循规则,则分为符合规则输入与各种不同角度不符合规则的无效输入

    ● 如果输入为整形,可分为正整数,零,负整数

    ● 如果程序的处理对象是表格,则分为用空表格,含一项或多项的表格

  ● 等价设计方案的主要两步骤:

    ● 尽可能多覆盖未覆盖的等价有效输入值,重复到有效等价输入值都被覆盖

    ● 尽可能多覆盖未覆盖的等价无效输入值,重复到无效等价输入值都被覆盖

  边界值分析:经验表明,处理边界情况时程序最容易发生错误

    ● 使输出刚好等于有效范围的最小值

    ● 使输出刚好等于有效范围的最大值

    ● 使输出刚好小于有效范围的最小值

    ● 使输出刚好大于有效范围的最大值

  在改正错误前软件工程师应该仔细考虑的问题

  ● 是否相同错误在程序其他什么地方?

  ● 修改后是否会引入新的错误?

  ● 为防止以后这类错误该如何做?





posted @ 2012-08-01 10:45 顺其自然EVO 阅读(329) | 评论 (0)编辑 收藏

性能测试知多少---了解前端性能

我的上一篇博文中讲到了响应时间,我们在做性能测试时,能过工具可以屏蔽客户端呈现时间,通过局域网的高宽带可以忽略数据传输速度的障碍。这并不是说他们不会对系统造成性能影响。相反,从用户的感受来看,虽然传输速度受用户带宽的限制。但我们可以通过很多技术来使用户想要看到的页面更快的显示。这就web是前端性能。

  如果考虑到web应用本身的特性,响应时间的构成应该会更加复杂。

  Web应用的基础是超文本传输协议(HTTP)和超文本标记语言(HTML),HTTP协议本身是一种面向非连接的协议,HTML语言则是一种用于制作超文本文档资料的简单标记语言。

  对于一个页面而言,“请求”和“返回数据”都可能是多次发生的。这个我在《在做性能测试之前需要知道什么》一文中举了一个简单的例子来讲解。由于HTTP对浏览器下载资源并发请求数量、Cache等方面都进行定义和限制,以及浏览器对于HTML的处理过程。完全可以说,用户所以感受的响应时间中的相当大的一部分并不完全取决于应用的后台处理所需要的时间,而取决于web应用的前端。在yahoo中,到少50个团队通过纯粹的前端性能相关的技巧,将最终用户的响应时间减少了25%以上。

  HTTP是一个属于应用层的面向对象的协议,用于传送WWW方式的数据,采用请求\响应模型,客户端向服务器发送一个请求,请求头包含请求的方法、URI、协议版本,以及包含请求修饰符、客户信息和内容的类似于HTML的消息结构。服务器以一个状态行作为响应,响应的内容包括消息协议的版本,成功或者错误编码加上包含服务器信息,实体元信息以及可能的实体内容。

  HTML是一种用于制作超文本文档资料的简单标记语言,用HTML编写的超文本文档能够独立于各种操作系统平台。从诞生开始,HTML语言就一直被用于描述web页面格式设计,使用HTML语言描述的文件需要通过WWW浏览器显示效果。

  用于查看前端性能工具太多的。

  嵌入浏览器的有 yslow 、page speed、httpwatch

  独立界面的有 fiddler2、charles 、

  页面性能测试之一 :http://www.51testing.com/html/62/n-249062.html

  下面用两种方式来对比较两种测试响应时间的差别

  Apache  benchmark 简称ab ,是非常有名又小巧的压力测试工具。

  下载安装apache web server 安装或解压之后,在bin\目录下有个ab执行文件。

  打开运行--cmd 打开命令提示符,定位到bin\目录下。

  基本用法:

  ab  -c  [并发用户数]  -n  [发送请求数]   [被测试页面的URL]

  设置一个用户一个请求,对百度首页加压:http://www.baidu.com/

  从上表中我们可以看到请求的总字节数为8024字节;响应时间为0.173 秒,也就是下面显示的173.010毫秒。

Firebug非常有名的debug工具,firefox浏览器最得意的集成工具。

  在firefox浏览菜单栏“工具”---添加组件---搜索firebug下载安装重启浏览器。

  同样对百度首页的访问:http://www.baidu.com/

  从上面图中看到请求的大小为10KB;响应时间1.4秒。清楚的发现这数据可以远远大于ab工具所得到的数据。仔细观察发现,firebug给出的数据,访问 http://www.baidu.com/ 网址时,客户端(浏览器)和应用之间的数据交互并非1次,而是5次。

  我们再分析其中的一个请求,firefox给出的的图形中,有红色和蓝色两种颜色的线条。蓝色表示到此刻发生了DOMContentLoaded事件。红色线条表示onload事件被触发。DOMContentLoaded事件W3C推荐的标准事件,它发生在页面的DOM树建成时,而onload则发生在页面所有的资源(图片文件、CSS文件、js文件等)都被下载完成后。

  从上图的右下角,我们会得到两个响应时间,1.41秒是onload事件被触发的时间,前面的1.4秒则是页面的所有请求都返回所需要的总时间。那么哪个时间才是用户感受到的响应时间呢?准确的说,两个都不是。用户的感受是个不确定的状态,取决于页面本身的类型以及呈现手段。如果某页面仅为用户提供阅读信息,一旦页面上开始出现可供阅读的内容,用户就开始阅读了。那么,用户认为响应时间就是发出请求到页面上出现可阅读信息。如果页面存在大量的交互内容,需要用户填写或在页面上进行拖拽等操作,在这种情况下,只有当页面的所有元素都被下正确的呈现出来,所有的js文件都已经执行完成后,用户才会感受到这个页面已经就绪。

  Web前端性能的研究并不是为了准确地得到一个响应时间数据,实际上,根据friebug图表的结果,web性能一部分取决于web服务器和应用服务器(建立连接,下载连接),别一部分取决于浏览器的实现机制、web页面上的js的执行等。取决于web服务器和应用服务器的响应时间与服务器的负载、压力等相关;而取决于浏览器实现机制与js文件执行所需要的时间则几乎与服务器端的负载和压力无关。那么web端的响应时间也是总响应时间的一部分,那么有必要web端的性能进行了解。

  那么前端性能这么见效,为什么还要去做后端性能测试呢?因为他们关注点不同,前端性能关注单个用户的感受。后端性能关注是更多用户访问系统时,服务器能更稳定、更快的处理用户发来的请求。一个强大的后台是前台的基础。



posted @ 2012-08-01 10:41 顺其自然EVO 阅读(686) | 评论 (0)编辑 收藏

专家眼中的QA、敏捷测试、探索式测试及测试的开放性

  编者按:测试、QA一直是大家关注的话题,只要有软件开发,就离不开QA和软件测试。本次特别邀请到一淘网测试架构师 @公直_黄利 ,诺基亚敏捷及精益教练 @徐毅-Kaveri 和百度高级测试工程师杨进,请他们谈下各自对QA和测试的理解,内容涉及如何衡量软件测试的有效性,探索式测试,敏捷测试,开源对测试的影响,测试的开放性以及测试框架推荐等。

  请先做下自我介绍。

  徐毅:我叫徐毅,现在在诺基亚北京担任敏捷及精益教练的工作。我是从05年在杭州诺基亚网络的时候开始转做专职测试的,同期也加入公司刚成立的测试自动化小组,这对我的理念有很大的影响,基本上我认为所有的测试都应该自动化。06年初加入当时的第一个Scrum试点项目,体会了一把敏捷测试,当时还根据我们的经验总结出了一套轻量化的测试流程。后来我们在公司内推广使用robotframework这个工具,作为培训师指导大家学会使用这个工具来进行测试自动化。后来还担任了一段时间的测试自动化教练的工作。

  公直:阿里巴巴一淘网测试架构师。

  杨进:百度高级测试工程师,06年加入百度,之前有过4年的测试开发工作,加入百度以来,主要从事自动化开发、测试方法改进以及系统测试相关的工作。

  最近主要在从事哪方面的工作?

  徐毅:最近主要是在敏捷及精益教练这个方面做得比较多,辅助组织和个人进行敏捷转型,由于有很强的测试背景,所以同时也做敏捷测试相关的工作。

  公直:最近半年一直在做代码质量的相关工作。在一淘业务线测试团队支持之下,与测试、产品架构师、PE等合作,从系统层面出发,优化目前的测试策略和方法,提升系统的可测试性和可部署性。

  杨进:近1年主要focus在系统测试和效果监控等系统层面的工作,目前是线下百度和大搜索效果监控的负责人,线下百度是一个基础的系统测试平台,对外提供预上线、故障预演、数据测试等系统层面的服务,而效果监控目标是快速发现产品严重影响用户体验的效果问题,它和线下百度相互相成,共同提升百度对外服务的质量。

  国内外一直有很多人把测试与质量保证混为一谈,其实测试属于质量控制(QC),而QA还有更多内容,请谈谈您对QA和测试的理解。

  徐毅:其实不管是保证还是控制,都很难达到名副其实的效果。测试做得再充分、再彻底、再快速,也无法把质量给控制起来,最多只能够更频繁地展现出质量的现状。关于QA么,我曾经在微博上发起过一个讨论,还是比较热闹的,大家可以去看看,What is the value of Quality Manager。至于“质量保证”这个词,大家可以想一想,如果我跟你拍胸脯说某件事情包在我身上,我保证办到,但实际情况是,回过头去我得催着一拨人做这个做那个才能保证你的事情办妥,你觉得这是你理解中的“保证”吗? 更重要的问题在于,“质量是什么”。如今,我们可以说质量的外延发生了变化,已经涵盖了许多方面;也可以说,质量已经不再重要,用户体验才是最重要的。温伯格在他的《质量 软件 管理》书中说到“quality is value to some person”,对于不同的人来说,同一件东西的价值可以是不同的。

  公直:其实一直以来个人不太喜欢把测试工程师称呼为QA,QA一般是指质量保证,范畴更大一些,在一淘,像过程改进工程师、配置管理工程师都在做质量控制的事情。单纯地靠测试工程师本身也是没有办法控制质量的,因为对决定软件质量的还是开发工程师。这个在博客中的《Google如何测试》系列文章中提及,对于质量来说,预防问题比发现问题本身更重要。质量更多是开发人员的问题,而不是测试人员的。通过把测试工作融入到开发过程中,我们能降低那些富产Bug的人的出错机会,不仅可以避免了大量最终用户的使用问题,而且还可以极大地降低测试人员报无效Bug的数量。测试的未来在于发现设计和编程人员解决问题方法上的局限、思路中的狭隘和技能方面的不足,这是我对测试的理解,也认为是以后测试发展的一个方向。

  杨进:我理解测试关注的更多是被测对象上线前的质量,而QA关注的是宏观意义上的质量,包括开发环节的质量控制(如何提高代码本身质量)、测试环节、上线环节以及运维环节(如线上出现问题后如何快速止损),甚至还包括用那种开发模式能更有效的提升项目开发质量和效率,因而是一个更宽泛的领域。

  如何衡量软件测试的有效性?

  徐毅:衡量一个东西的有效性,对我来说就看比较有无之间的区别,也就是说比较“有软件测试”和“无软件测试”在“效果”上面的差异,那就是有效性啦,也即是有效的程度。那么,你所期望的“效果”又是什么呢?

  公直:从90年代末开始,测试进入所谓的“Prevention oriented period ”(参见wiki)阶段,强调2点,第一个缺陷预防,第二就是软件度量。就是这个问题本身(如何衡量软件测试的有效性),如何度量你做的测试有什么收益,如何判断你的测试活动的有效性,无论是学术界还是工业界,好像也还没有什么比较好的方法,特别是在国内目前的现状(人治,部门经理或者项目经理决定太多东西),度量系统(例如sonar)计算出的测试ROI本身可能也不一定准确,人的因素变化太多。我就简单说下我们这边判断测试有效性做法好了,基本上还是还是从结果来看,上线失败次数、线上故障、线上Bug几个维度来评估测试的有效性。

  杨进:要想全面评判测试的有效性是比较困难的,目前比较通用的手段是在产品发布以后,利用用户报告bug的数量和趋势来判断测试的有效性,然后这种判断方法需要上线后才能进行因而显得价值有限,上线前也有一些可参考的手段,比如UT完成后的代码覆盖率,测试用例完后的评审,测试报告的评审等。我自己比较喜欢手段是代码覆盖率,因为代码覆盖率是一个利用客观标准进行判定的方法。此外基于测试需求覆盖率也是一个好方法。

请谈下您对探索式测试的理解,请分享下这方面的实践经验?

  徐毅:其实探索式测试是什么,Cem Kaner和James Bach的一些文章、PPT都已经写得非常清楚。

  首先探索式测试是一种测试的“方式”(Way,或Approach),而不是测试“技术”(Technique),方式也即是指完成整体测试工作所选择的办法,而技术则是指对于局部测试工作进行操作的方法。

  其次,ET的目的在于“探索”,也即有一个明确的测试目标,但是目标的细节或是达成目标的步骤尚不清晰,所以需要边走边看,同时间地进行学习、设计、执行、解析的结果,与PDCA循环颇有相似之处。

  第三要区分开ET和手工测试的关系。“手工测试”所强调的是执行的手段,也即“手工”。而ET主要强调目的,也即“探索”,当然还有就是,执行只不过是ET中的一部分而已,而这一部分,可以借助自动化。例如,修改某个已有自动化测试脚本中的部分测试数据,借助于脚本快速地执行某些操作,而去掉或暂停分析部分的脚本执行,因为此时测试的结果未知,需要依赖人工来判断、分析测试结果。

  公直:探索式测试最近2年异常火爆,很多人以为是最新出的一个测试技术或者方法。Cem Kaner 在1983年(都快30年了)就提出了。这是一种强调个人自由与责任的测试方法,让独立测试人员可以借由不断的学习来改善测试的规划与测试的执行,而在测试的过程中也会同时改善测试用例从而达到相辅相成的效果。在一淘这边,其实很早就开始使用这种实践方法了,但很多一线的测试人员并不知道自己的做法就是探索式测试,在互联网研发模式下,一般都或多或少地使用敏捷模式,或者其他的土方法,但迭代周期都很短,一个月就要上线。在这样的环境下,文档少,在测试计划制定设计上都不可能完善,一般在测试过程中是用freemind等脑图工具来记录测试执行过程的同时做测试用例的设计,这种方式可以做常规测试的补充。

  杨进:我很喜欢探索性测试,它让测试工作变得轻松和富有创造力,它能让你无需复杂的测试准备,就直接进入最核心的测试工作,并且不拘泥用什么方法、什么工具,也不用考虑能否能被自动化,只需要关注能否快速的找到bug就行。当然好的探索性测试实际上对工程师的逻辑分析能力和产品整体理解要求很高,这种依赖于个人能力的测试手段,执行的效果也比较难以控制。

  探索性测试的实践方面,我们之前尝试过多人组队测试,这种方式适用于多人进行的大型项目,大家一起进行探索性测试,bug系统即时显示你在这个版本发现了多少个bug,并且排名,我们每天乐于寻找更多的bug,并且分享找bug的技巧,在这个过程中我们都得到了很多的成就感,并且对产品的理解和测试技巧也大幅提升。现在回想起来也还是一个很有意思的事情。

  您怎么看敏捷测试,执行后会质量有哪些明显的改善?

  徐毅:我认为,敏捷测试(关于敏捷测试的定义、介绍,请参考Lisa Crispin书中的描述)并无法单独的执行,必须在敏捷的环境下,结合开发人员方面的敏捷实践(以及组织结构)齐头并进方可实现。而此时,质量的提升乃是源于软件开发工作整体的改善,很难说一定是测试的功劳。另一方面则在于,测试本来就无法“控制”质量,自然也无法改善质量,因为测试工作本身并不改变那些可以影响质量产生的因素。但敏捷测试的实践对于质量的提升是肯定有影响的。

  ● 敏捷中对于团队内外参与、交流的追求,能够更容易“do things right”

  ● 快速地交付和反馈,有助于做到更多地“do right things”

  ● 完整团队、跨职能团队等实践,团队负责自己的工作方式改进,更容易做到“do things rightly”

  公直:敏捷测试是一个被过度炒作的概念,和架构师、云计算一起被大家私下称呼“大忽悠”的工具,特别是最近几年。传统上将敏捷测试就是在敏捷研发流程下的测试,例如使用XP、或者scrum的研发流程下的测试活动,怎样在这样的研发背景下做测试,挑战在于如何使用敏捷的流程。另外一种敏捷测试,就是按照敏捷宣言中的几个关键词,“速度快”、“反馈”、“持续”,做的测试。由于敏捷强调的重点,还是在“快”上,无论中文含义的字面解释,“敏”、“捷”其实都是快的意思,这正是自动化程序的特长,机器的运行速度总是比人的操作要快,所以我们一般在敏捷项目中使用了非常多的自动化技术。个人感觉十分使用敏捷测试与质量提升方面没有直接关系。

  杨进:我理解敏捷测试就是让项目相关的角色全体直接承担项目最终目标,由于都是为最终目标服务,因而角色也变得模糊,并且每个人的工作也需要考虑是否对当前最急迫的事情,这种集中所有角色力量为共同目标前进的开发方式,减少了大家沟通和项目迭代成本,最终很容易得到项目整体效率和质量的提升。由于各角色对目标理解一致,对产品理解都很深入,因而可以更多的把bug消灭在开发的早期,比如单元测试、新功能测试阶段,使得后期的集成和系统测试问题变得更少,尤其是产品最终的效果问题也会减少。

  开源对测试的影响,如何看待测试的开放性?

  徐毅:平台、工具、框架在我看来属于比较相同的情况,我就拿我自己的经历来做例子吧。在诺西的时候,我们有使用过一个叫robotframework的测试自动化框架,它最开始是一个和诺西合作的芬兰专家开发出来的,在诺西(当时还叫诺基亚网络)最先开始使用, 而后逐步推广,在此过程中这个框架也在不断地更新、改进、完善。后来在公司之外也有很多的使用者,于是开发者和诺西把这个框架开源出来,也吸引了更多的人加入到这个框架的开发中来,包括衍生工具的开发,这都推动了这个工具的广泛使用和不断完善。诺西作为最主要的支持者,并没有因为开源而受损,反而因为这个开源框架庞大的用户群体和开发者队伍而受益颇多,有更多的人可以分享经验、讨论问题,也有更强大的开发力量提供所需的功能。不过,开源的软件,或者开源的社区相对来说更倾向于Linux的设计理念,也即是更专注于某一个领域、某一块功能,做精,而不像是Windows那样的设计理念,强调易用性、一站式体验。这意味着,企业内要完成所有的测试工具,可能需要和多个开源工具、框架打交道,整体上如何协调使用并不容易,需要培养相关方面的人才。

  测试开放性,没有特别想法,也没啥体验,只能凭感觉谈谈。个人观点比较悲观或者比较现实。测试就是测自己产品的功能、特性,让别人知道自己的测试,也就是知道了自己产品的细节和特性。出于商业上的考虑,我认为各企业恐怕会较难把最核心部分的东西拿出来公开。不过这个很可能会是一个趋势,即使拿出来的测试用例的范围比较小而已。对于产品也有要求,得要是相对标准化程度比较高的产品,不然拿出来的测试最多别人参考一下,而无法直接使用,也无法反馈改进,意味着拿出来的那一方也无法受益,这样的话这些测试也就等同于是“死亡的文档”(dead documentation),没有实效。

  公直:开源意味着更多可以利用的资源,特别是在测试工具上,开源也是一种开放的心态。测试的开放性,在于比较坦诚地把自己在怎样的场景下如何去做测试给大家做个介绍。非常典型的就是Google,在James的带领下,有一系列的博客、文章、工具在介绍他们的测试,介绍他们测试中遇到的问题已经他们是怎么解决的。非常期望各个公司,无论大小,测试做的程度,都可以把自己的测试通过微博、博客、文章、公开演讲等形式公布出来,毕竟这一部分不太涉及太多的商业机密或者核心技术。

  杨进:测试的开放性,或者说基于某种特性测试的开放性是未来发展的趋势,原因是互联网的创业越来越依托一些基础的平台,比如iOS、Android,而就一个公司内部而言,云的广泛应用也使得不同产品基于一个相同的基础,由于有了共同的基础,这些都表征出测试也会慢慢走向开放,从部门走向公司,从公司内走向开源。一个好的开放性测试框架,是依托于具体测试资源,以满足具体某种测试需求而诞生的。这种测试框架因为和用户的某些需求绑定因而生存能力很强,并且也能很好的一站式完成用户的需求。

  我们把测试当成了质量保证的主要手段,当质量低下时,或者为了达到高质量时,一般的选择都是加大测试的工作量。您怎么看?

  徐毅:临时抱佛脚,没用。就算真要加大,同时也得加大开发的工作量,找出来的bug没人修复的话,质量是不会提高的,只不过是我们更加清楚自己的产品质量很烂而已。

  公直:测试工程师做的测试活动一般都被称之为是“检测”,与之对应的开发工程师做的测试都是在“预防”,质量高低可以通过测试“检测”出来,但测试永远无法提升产品质量。所以,为了达到高质量,可以做更多的测试,加大测试工作量来发现产品的缺陷并修复,但对于质量,这都是“事后”,是一种下策,不是不可以。更好的办法,是测试前移,让开发来做单元测试、简单的功能测试,在这个过程中会发现大量的问题并自行修复,测试更过地关注在用户使用上,这样高质量会更容易达到一些。

  杨进:质量的主体其实是Dev,试想QA完成某个被测对象的测试,它最核心的价值是什么?发现bug 或是证明产品能满足具体应用的需求?我选择后者,因而如何让Dev开发出质量更高的代码是每个产品质量可控的测试团队首先考虑的事情。当然如果当前质量低下的时候,一个比较快速见效的方法就是投入更多的测试,但是这不能是唯一手段,必须有人走到开发的阶段,从上游逐步开始改善代码的质量和可测试性,否则这就是一个死循环。更多的低效投入,更多的测试和debug成本,这足以压坏这个项目的所有角色,而不仅仅是QA。

  工作中推荐的测试框架?使用的范畴?

  徐毅:我推荐使用robotframework,它是一种基于关键字驱动理念的的测试自动化框架(也支持数据驱动),用于敏捷测试象限(参看Lisa的书或者Brian Marick的博客)中的Acceptance Testing。更多的信息可以参看它的主页,www.robotframework.org。最初是由诺基亚西门子网络资助开发的,如今已经开源,大家都可以使用,国内也有许多的实践者可以交流经验。它支持多种的测试文件格式,包括HTML、CSV和文本文件,测试用例的格式主要是一个表格形式,和FIT、FitNesse比较像。然后通过内部的机制驱动底层的Library进行测试,而Library可以用Python和Java编写,目前已经有很多现成的,例如Selenium、Telnet、SSH、AutoIt等。

  我使用这个工具已经很多年,觉得它非常的好用,非常贴合敏捷开发的方式,能够支持我们的ATDD,如今它甚至已经内嵌可以支持BDD格式的关键字脚本。

  公直:Selenium,主要做Web UI级别的功能测试; JUnit/GTest, 代码级别的单元测试或者API调用级别的自动化测试;staf/stax,远程调用,在测试环境部署自动化中可以用到;JMeter/ab/http_load, 性能相关的测试;另外,给大家推荐一款自动化调度的工具TOAST,http://toast.taobao.org/ ,是我们这边的一个开源的测试调度工具,主要解决持续集成中的测试执行。

  杨进:百度内部有一个测试工具平台,里面有百度内部开发的很多很棒的工具和框架,后续这些工具会慢慢开源出来。大家熟知的工具中,比如:代码覆盖率的gcov、BullseyeCoverage(支持逻辑判断的覆盖率统计),代码扫描工具pclint,内存泄露检查工具Valgrind,单元测试工具GTest,如果测试移动产品,MTC会是一个好选择

  在工作中会遇到各种各样的bug或缺陷,能否分享1-2个?

  杨进:在测试分布式系统中,曾经遇到过在同一个目录下出现两个同名文件的情况,导致系统直接crash掉了,这个bug让我觉得一切皆有可能。监控发现过工程师在进行换库导致流量下降的问题,这个case让我明白bug不仅来自程序和数据,也来自每个可能对线上造成影响的环节。

posted @ 2012-08-01 10:24 顺其自然EVO 阅读(847) | 评论 (0)编辑 收藏

我的软件测试之旅:(4)并行——自动化回归测试

  在前一个测试子项目中的表现不错,而后我又被调入一个产品发布版本的回归测试子项目中去。相比之前的测试子项目(软件模块的功能测试),回归测试就很不一样了。回归测试所执行的,都是比较基础的测试用例,也是不管版本如何变迁也都不必要进行太多改动的测试用例。也正因为需要比较频繁地(每一个新的产品发布版本)执行这些测试用例,所以这些用例几乎都有相应的测试脚本,可以缩短测试执行时间,脚本就是利用之前我提到过的内部工具写成的。脚本语言本身可以抽取一些library出来,具有一定的模块化构造,可以减少一些重复的脚本代码,但是后来我从测试自动化(TA,Test Automation)的角度来看,依然是非常低级别(基础,非编译)的自动化实践。

  相比之前跟着导师干活,这一次的工作就需要我自己独立进行,而且工作内容也增加了许多。包括要自己写测试计划,还要组织审核会议(Inspection Meeting),通过审核后的计划会在系统里被标示为“已批准”(Approved),这样我才可以根据这个计划以及测试用例开始执行测试。测试计划还是不难写,毕竟是回归测试嘛,把测试管理系统里以前别的版本的回归测试计划拿出来看一看,修改一些相关的字段,例如产品版本啊、执行人名称即可,大同小异。要随便弄弄蒙混过关倒是不难,依葫芦画瓢就行,难点是在于你是不是想弄明白这些回归测试的用例,毕竟这些用例都是别人写的,而且除了用例之外,还有测试脚本,万一两者之间有些互相冲突的信息,或者脚本报出的一些错误信息在用例中没有描述到,如何能够处理妥当,这需要执行人多花点心思,多消耗点脑细胞才行。

  回归测试的另一个挑战在于,它涉及到的系统架构范围往往不止一个模块。之前在导师的带领下工作,只需要按照用例中所给出的信息,执行相应的命令即可。就算你不太明白命令中一些部分的参数该如何设计,在人机界面上执行这些命令时,它自己也能发现不合规的命令格式并且给出提示,要求你输入正确的值。只是执行、观察、发现错误、修改命令或参数、重新执行、记录结果,还是很轻松的。但如今由于要测试更多的模块、更广的范围,需要了解的命令也逐渐地多起来,在测试中发现一些异常现象后要查看日志、系统状态也需要执行一些命令,而这些命令并不在我负责测试的技术领域中,所以还得去找相关领域的测试同事、专家请教学习,或者不愿意求人的话就得自己找相关文档。在此,沟通以及查阅资料或者摸索的能力就非常重要了。

  只是执行测试是相对简单而且有点枯燥的活,因为这些功能多数都是稳定的,不大会出错。于是我就把一些时间花在思考、理解这些测试用例和脚本上,正好回归测试的用例中总有一些是执行时间比较长的,我就利用这些时间去查阅资料、文档,理解测试用例的设计理念,以及研究多个测试用例之间的关系,看看是不是有漏测的功能。

  在当时,我们的回归测试用例都是从现有的功能测试用例中直接筛选出来的,挑选的是其中比较基础的、通用的测试用例,是否容易实现脚本化也是考量的因素之一。因此,如果只是去看测试计划中的测试用例集,难以看到全貌,不知道为何要选择这些用例,也不知道这些用例之间有什么特别的联系,它们结合在一起是否有足够完整地覆盖了要测试的范围。因而,想要理解这些测试用例以及其关系,找到是否有漏测的功能,需要额外花一些功夫顺藤摸瓜地查看相关技术领域、模块的测试用例和以往的测试计划。看一看某个测试用例在它的模块里,是否还有其他的测试用例也在验证相似的功能,有什么区别,为何不选择其他的测试用例做回归测试,以及是否有一些应该测而没有测的功能(这需要研究功能需求规格说明书文档才行)。研究这些问题其实是蛮有意思的事,它能够帮助你更深刻地理解自己手中正在执行的测试用例,更能够分辨出在执行中你对哪些输出信息应该保持关注,而对其他一些信息则可以睁一只眼闭一只眼(因为有其他的测试用例会专门检查这一块的情况)。做到测试用例或者测试执行有重点、有针对性有着莫大的好处,专注能帮你过滤掉一些不必要关注的信息,延缓测试过程中的紧张感,也能够提高你对重点信息的关注度和敏感度,更容易发现问题。

posted @ 2012-08-01 10:03 顺其自然EVO 阅读(271) | 评论 (0)编辑 收藏

深入浅出理解索引

  (一)深入浅出理解索引结构

  实际上,您可以把索引理解为一种特殊的目录。

  SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引、簇集索引)和非聚集索引(nonclustered index,也称非聚类索引、非簇集索引)。下面,我们举例来说明一下聚集索引和非聚集索引的区别。

  其实,我们的汉语字典的正文本身就是一个聚集索引。比如,我们要查“安”字,就会很自然地翻开字典的前几页,因为“安”的拼音是“an”,而按照拼音排序汉字的字典是以英文字母“a”开头并以“z”结尾的,那么“安”字就自然地排在字典的前部。如果您翻完了所有以“a”开头的部分仍然找不到这个字,那么就说明您的字典中没有这个字;同样的,如果查“张”字,那您也会将您的字典翻到最后部分,因为“张”的拼音是“zhang”。也就是说,字典的正文部分本身就是一个目录,您不需要再去查其他目录来找到您需要找的内容。

  我们把这种正文内容本身就是一种按照一定规则排列的目录称为“聚集索引”。

  如果您认识某个字,您可以快速地从自典中查到这个字。但您也可能会遇到您不认识的字,不知道它的发音,这时候,您就不能按照刚才的方法找到您要查的字,而需要去根据“偏旁部首”查到您要找的字,然后根据这个字后的页码直接翻到某页来找到您要找的字。但您结合“部首目录”和“检字表”而查到的字的排序并不是真正的正文的排序方法,比如您查“张”字,我们可以看到在查部首之后的检字表中“张”的页码是672页,检字表中“张”的上面是“驰”字,但页码却是63页,“张”的下面是“弩”字,页面是390页。很显然,这些字并不是真正的分别位于“张”字的上下方,现在您看到的连续的“驰、张、弩”三字实际上就是他们在非聚集索引中的排序,是字典正文中的字在非聚集索引中的映射。我们可以通过这种方式来找到您所需要的字,但它需要两个过程,先找到目录中的结果,然后再翻到您所需要的页码。

  我们把这种目录纯粹是目录,正文纯粹是正文的排序方式称为“非聚集索引”。

  通过以上例子,我们可以理解到什么是“聚集索引”和“非聚集索引”。

  进一步引申一下,我们可以很容易的理解:每个表只能有一个聚集索引,因为目录只能按照一种方法进行排序。

  (二)何时使用聚集索引或非聚集索引

  下面的表总结了何时使用聚集索引或非聚集索引(很重要)。

动作描述

使用聚集索引

使用非聚集索引

外键列

主键列

列经常被分组排序(order by)

返回某范围内的数据

不应

小数目的不同值

不应

大数目的不同值

不应

频繁更新的列

不应

频繁修改索引列

不应

一个或极少不同值

不应

不应

  事实上,我们可以通过前面聚集索引和非聚集索引的定义的例子来理解上表。如:返回某范围内的数据一项。比如您的某个表有一个时间列,恰好您把聚合索引建立在了该列,这时您查询2004年1月1日至2004年10月1日之间的全部数据时,这个速度就将是很快的,因为您的这本字典正文是按日期进行排序的,聚类索引只需要找到要检索的所有数据中的开头和结尾数据即可;而不像非聚集索引,必须先查到目录中查到每一项数据对应的页码,然后再根据页码查到具体内容。

  聚集索引和非聚集索引深入浅出,希望能帮助您更好的理解两种索引的区别,下一篇博客我们谈下有关索引的基本语法结构及维护。

posted @ 2012-07-31 10:52 顺其自然EVO 阅读(211) | 评论 (0)编辑 收藏

如何进行自动化测试和手工测试

首先抽象地描述一下项目背景,这个项目是一个面向消费者的Web系统(以下简称系统A)。用户访问系统A,输入数据,系统A 接收数据,然后调用系统B 的REST接口返回处理过的数据给用户。其中系统B 是由另一个团队开发和维护的。描述地够抽象的吧,不过你可以想象,比如一个电商网站。

  该项目采用Java,框架是Spring,构建工具是Maven,技术不算很新啦。

  好了,要说到自动化测试,肯定得先说说我们是如何按照需求进行开发的。

  首先,我们不是按照一份全面的12页的需求说明文档来开发,那样的话,无休止的前期的设计讨论会、数据库设计、代码框架设计、架构讨论会,再加上编码和测试的时间,等全部功能都开发出来都已经是一个月以后了。对我们这个面向消费者的互联网应用来说,一个月太长了。等到一个月以后,这些一个月以前收集的需求和实现的功能,对消费者还有没有价值,都不一定呢。

  我们的工作是价值拉动的,所以我们要快速响应变化,我们的哲学是:“先把应用跑起来,完成一小部分可以使用的业务功能,看看反馈再说”。

  所以我们按照故事点来划分需求,比如这三天我们就开发”登录功能“,这里面包括页面的登录框,页面JS校验,后台逻辑校验,数据库表字段调整,调用系统B 的验证接口等。这样,三天以后,团队就能给产品经理/Boss演示“登录功能”,接受产品经理/Boss的反馈,并在第四天就开始改进,第五天就可以再给产品经理/Boss演示改进后的“登录功能”了。

  而不像传统的软件开发方式,团队跟产品经理/Boss说,“一个月以后你才能看到全部功能中的登录功能,到时候你要是不满意,走需求变更流程,需要再等一个月!”。

  那么,这个“登录功能”包括页面的登录框,页面JS校验,后台逻辑校验,数据库表字段调整,调用系统B 的验证接口,这些都是可以自动化验证的。页面的登录框我们用Selenium验证,JS校验逻辑我们用Jasmine验证,后台逻辑校验我们用JUnit验证,数据库表字段调整,我们用DBUnit验证,调用系统B 的接口,我们用Mockito来mock接口调用验证。

  当开发人员对测试人员说,我们已经开发完成了“登录功能”,测试人员会问,“如何证明你们已经开发完成了登录功能?给我看下你们的自动化测试代码!”

  是的,只有通过自动化测试的代码,才能证明功能是正确开发完成的。因为如果没有这些自动化测试,两个星期之后,代码被多处修改,当时写的代码还能不能工作,都不一定呢。

  没错,这些自动化测试代码都是开发人员写的。我们的哲学是:“You build it, You test it!”

  看到这里,你可能会问,Selenium 验证,Jasmine 验证,JUnit验证, DBUnit和 Mockito 验证,写了这么多的自动化测试代码,该怎么运行呢?

  没问题,我们的构建工具是用的Maven嘛,这些测试都有对应的Maven插件,我们把这些测试都集成到了Maven的构建脚本里,这样,在本地命令行,仅仅运行 “mvn clean install”  就能挨个运行这些测试了,当运行到Selenium测试时,我们的脚本还会在本地把Jetty服务器运行起来,打开本地的Firefox进行Web UI测试,运行完毕后退出Firefox,关闭Jett服务器。如果中途有测试失败的话,脚本就会给出失败提示。

  下面是我们项目中实际的自动化测试代码,在powershell中的运行截图:

  上图是我们项目目前总共的532个JUnit测试运行结果。

  上图是76个Jasmine测试运行结果

  那么测试人员如何做测试?

  开发人员都开始写自动化测试代码了,那么测试人员干什么呢?

  我们是这么做的,测试人员负责故事点的测试策略分析,比如“登录功能”有一个要求是:“密码必须包含字母和数字”。

  那么测试人员会事先设计至少三个测试用例

  1)密码全部是字母,不通过

  2)密码全部是数字,不通过

  3)密码有部分字母,部分数字,通过

  当开发人员开始开发“登录功能”时,测试人员会和他说,这里有三个测试用例,你的开发完成时,我需要看到至少三个自动化测试覆盖这三种情况。开发人员说,没问题。

  当开发人员开发完毕,测试人员看到了这三个自动化测试用例后,测试人员说,“可以了,我再进行一些登录的手工测试和探索性测试,你给我一个测试环境吧。”

  那么开发人员如何给测试人员准备测试环境呢?

  这也好办,我们不是有持续集成服务器(以下简称CI)嘛,开发人员提交代码到SVN后,CI检测到有代码提交,会自动运行一遍“mvn clean install”,  如果结果是Success,CI会生成一个构建号码,比如“1292”。

  开发人员会对测试人员说,“我的功能代码对应的CI构建号是1292,你去把1292号版本发布到测试环境吧。”

  这里先说明一下,我们的环境分为DEV,SYS,UAT等。这几个环境的配置大都是一样的,只是给不同的人使用。其中,DEV是给开发人员开发用的,SYS是给测试人员测试用的,UAT是给产品经理和BOSS演示用的。

  这时候,就是自动化带来的威力了。

  如上图,测试人员访问CI服务器,会看到这样的构建流水线,1292号版本已经在CI上运行通过(第一个绿色),并且被部署到DEV环境中(第二个绿色),SYS和UAT还没有部署1292号版本(蓝色)。

  由于我们事先已经在CI上配置好了把代码部署到测试环境的脚本,用Groovy写的,所以测试人员只需要在“1292”号版本的sys环境上点击一个按钮(上图中红色框所示),就能把代码发布到测试环境了。

  上图就是一个已经发布到测试环境的版本。我们也可以用同样的办法发布某个特定版本到UAT环境,随时给BOSS做演示。

  几分钟之后,测试人员就开始Happy地进行手工测试和探索性测试了。

  新功能发布到测试环境后,如果测试人员发现功能不对,想手工验证下当前测试环境的版本,也是可以的。只需要在浏览器输入“http://应用地址/appcheck.jsp”,就能得到如下页面,

  其中的信息包括:应用的maven版本号,CI服务器(我们用的是免费的Jenkins)构建号码,SVN提交版本号,构建时间等信息。

  如果测试人员又发现了一些Bug,就会和开发人员一起尝试着再写一些自动化测试代码,以此保证一些重复的验证都由便宜又听话的机器去做,测试人员则抽出他们宝贵的精力来关注测试策略和探索性测试。

  好了,三天以后,具有自动化测试代码的“登录功能”OK了,产品经理/Boss看后非常满意,说可以发布到产品环境了。

  那么,我们是怎么发布到产品环境,我们的上线流程是怎么样的呢?

  还有和系统B 的联调,我们是怎么做的呢?

  未完待续,敬请期待。。。

posted @ 2012-07-31 10:40 顺其自然EVO 阅读(2986) | 评论 (3)编辑 收藏

我的软件测试之旅:(3)同期——加入测试自动化小组

刚被派遣到诺基亚不久,确切地说是刚刚结束新员工入职培训的时候,小组长问我对测试自动化是否 感兴趣,我觉得好像蛮酷的,而且还可以被派到北京去参加两天的培训,英国人授课,何乐而不为呢。这个英国人就是Mark Fewster,《Software Test Automation》的作者,这本书被认为是该领域的开山之作,详细地描述了测试自动化相关的所有细节、战略和战术。于是就这样我加入了只有两个人的兼职测试自动化小组,之所以成立这个小组是因为在国外的其他研发中心使用测试自动化的效果非常好,所以要把它引入到杭州的研发中心。

  我们很快就接下第一个任务,将一些领域的回归测试用例实现为自动化脚本,以便节省回归测试所使用的时间和人力。产品线的测试自动化专家们已经做了一些工作,他们围绕着我们所使用的测试工具,使用其脚本语言封装出一个测试自动化框架。这个框架提供了若干库(Library),使用库所提供的函数可以快速地创建测试脚本,当有需要时我们也可以自己为库开发一些新的函数。当然,只是这一点还算不得是框架,它还规定了测试脚本要遵循的格式,以及要使用的日志功能,以便生成格式比较统一的测试结果记录和报告。甚至于它自己还有设计的测试脚本文件夹结构,通过一个特殊的INI文件及其内容来记录测试脚本的执行管理。运行这个测试自动化框架,可以看到相应测试脚本库下的所有测试脚本,并且可以配置要执行哪一些脚本。

  跟随着这个测试框架的,还有一些相应的测试自动化理论知识。我们将测试全过程看做五个部分:前置条件检查;设置;执行;结果分析;清理及复原。所有的测试用例都是如此:首先,检查测试用例可以执行的前置条件是否已被满足,如果没有,则退出测试不执行,例如系统中存在某个被测板块;而后根据测试用例所需,将相关的资源或者环境设置到相应的状态,例如将被测板块设置到某个状态或是创建一些资源;而后就是执行测试脚本,并且记录执行的结果,同时需要对结果进行分析,除了每一个测试步骤要检查之外,所有相关测试步骤执行完后也要检查整个测试的结果;最后,在退出当前测试脚本的执行之前,它必须清理在设置阶段所改变或增加的资源及其状态,例如将被测板块恢复到测试开始前的状态,这一步非常必要,要做到执行或不执行当前测试脚本,留给后续测试脚本的被测系统环境都是一致的。不然的话,对于后续测试脚本来说,它们得到的测试环境将是不可预知的,运行脚本所得到的测试结果也是无法肯定的,如果脚本出错了需要调试也会难以定位问题的根源。

  多个测试用例会组成一个测试集合,这个五个部分同样适用于测试集合层面:每一个测试集合都要检查该集合中所有测试用例都关注的前置条件;也要进行共同都需要的设置,例如创建某个文件,以供测试用例验证 该文件的各种操作是否正常;而后是执行测试集合,当然也包括对结果的分析以及生成报告;最后在退出测试集合的执行前,将设置阶段所做的改变全部复位,以便后续测试集合得到当前测试集合相同的执行前环境。集合的集合,集合的集合的集合,循环往复,一直到整个产品线的所有测试用例集合,都适用这五个部分的模型。

  在此过程中,我们的小组不断地发展壮大,当然,依然是兼职状态,吸纳的都是感兴趣的人,以及之前就在回归测试工作组工作的人。于是我们开始面临一些技术之外的问题,也即如何确保大家所写出来的都是统一风格的测试脚本,都能够知道如何开发出符合框架要求的测试脚本,如何使用框架运行测试脚本以及对测试运行进行管理,等等。同样的,我们也需要考虑把测试的一些质量管理流程同样的引入到测试自动化的工作中来,例如如何对测试脚本的开发进行评审和修订,如何确保测试脚本的质量,如何确保每一个测试脚本自身都是一个原子操作,不会给后续的脚本留下烂摊子。

  由于当时产品线整体正在将研发工作的主题转移到杭州研发中心,这个测试自动化框架的用户主题也将会变成杭州研发中心,于是管理层决定要在杭州寻找一个关键用户(Key User)来管理这个框架,负责它的维护工作以及持续地开发。对这个框架有着极高热情的我最终得到了这个机会,于是我也有了机会和足够的时间可以去研究这个框架自身的设计原理。当然,框架本身也是用那个类C的脚本代码实现的,而且代码库也都是内部公开的,所以即使我不是关键用户,也可以学习它的设计原理,但是作为关键用户还需要协调和处理多人并行开发过程中的很多问题。于是我们开发出了一些相关文档和教程,帮助大家理解和使用这个框架,把它推广到测试自动化小组之外的其他测试团队,把普通的功能测试用例(不属于回归测试用例的集合)也纳入到这个框架之中,统一地管理起来。由于框架自身的模块化,功能测试脚本的开发人员可以省去许多重复函数代码的开发,而且也不用再靠自己去处理信息记录、结果分析和生成测试报告了。

  人多了,就有不同的想法和看法,测试自动化的人员也一样。测试自动化和开发的关系其实比它和测试的关系近多了,因为两者都涉及到代码。每个人写的脚本代码风格都不一样,所以我们也有自己的(测试脚本代码)编码规范和命名规则等等一系列的规定。而我们作为测试自动化小组,在审核会议上着重观察的则是测试脚本代码,而不是测试用例的逻辑,或是测试计划、报告之类的东西。

  在此过程中,我们还要承担评估测试自动化工具、框架的工作,除了这个内部自己开发的框架,我们也同时有考虑其他的商用工具,不同的工具各有优势,例如有的工具集成了类似于实验室环境管理的功能。但最终,在当时我们选择了内部开发出来的这个框架,因为大家对它更熟悉,推广使用它进行新脚本开发的成本相对更低,等等一些原因。

  后来这些测试专家推荐给我们一个新的测试自动化框架,由另一个产品线的测试专家们开发出来,也是围绕着公司的测试工具进行封装。但他们的实现思路主要是沿着如今流行的DSL路线前进,他们希望将那些所有测试用例都会用到的操作封装起来,作为一种无关具体实现技术(例如函数代码)的调用。使用这个框架的测试人员无需去查阅那个类C脚本语言,只需要使用这个框架所提供的操作即可。不过由于种种已记不得的原因,这个框架并未流行开来。

相关链接:

我的软件测试之旅:(1)起点——作为软件开发人员

我的软件测试之旅:(2)转变——作为专职测试人员

posted @ 2012-07-31 10:33 顺其自然EVO 阅读(213) | 评论 (0)编辑 收藏

软件测试执行不仅仅是“是非判断”

  测试执行过程中,测试人员在大多数时候面对的是“是非判断”。即对照需求(包括需求文档、原型系统、用户字典、设计文档、其它参考文档等),来判断被测系统的行为是否正确。但实际上测试人员也有许多需要做出“非是非判断”的时候。而这种能力往往对于“测试质量”(指如果将测试作为一种服务,提供给需要者的服务质量)更为关键,也更难培养。本文将分为两大部分来表述笔者对于如下两个问题的理解:

  (1)测试执行过程中有哪些“非是非判断”,它们为什么重要?

  (2)这些“非是非判断”能力可以如何培养?

  “非是非判断”之一:难以重现的问题

  请回忆如下手工测试的场景:你正在执行测试,发现了一个缺陷,却很难重现。这时候你面对的就不是一个判断题了(即是不是缺陷的判断),而是一个证明题,要证明在什么样的前提条件下,如何经过一步步的演绎,程序在此场景下一定会出错。

  解决这类问题为什么是重要的呢?因为大家最害怕的是风险,而难以重现的问题在我们没有重现它之前都蕴藏着无法把握的风险。我们知道风险带来的影响受到两个因素的影响,一个是风险发生的概率,二是风险带来的危害。难以重现的缺陷虽然发生概率也许比较低(也不一定,因为也许只是你没有发现它出现的必要条件,而此条件有可能是经常发生的),但如果后果是严重的,那它带来的影响可能并不小。所以作为第一现场的目击者,测试人员最有责任和义务去多花一些时间精力试图重现它。对于一个可以重现的问题,它的危害往往更容易被相对准确地度量。所以即使这个缺陷最后被决定不予修复,测试人员也不要觉得气馁。因为这个不予修复的结果是经过论证的,与无法重现而直接取消是不一样的。我比较认同Cem Kaner对于测试的定义“Software testing is an empirical technical investigation conducted to provide stakeholders with information about the quality of the product or service under test.”即,软件测试是一个为了给干系人提供关于被测产品或服务提供质量信息而进行的以观察或实验为根据的技术考察工作。所以测试的价值是提供有价值的质量信息,暴露风险,而不是做决定或者直接产生改变。

  “非是非判断”之二:可以重现,但不容易解决的问题

  请再回忆如下自动化测试的场景:你的某个自动化脚本没有语法错,也可以运行,但结果就是不对(明明正确的结果却被误报出错)。例如,我现在手头还搁置着这样一个下载查询结果到本地,结果比对文件名总报失败的脚本问题。又如,执行性能测试的时候出现了异常的服务器自动重启。这两种问题都可以反复重现,但通常你是第一次碰到,你想不通,也没有信心可以解决。这时候你面对的也不是一个判断题了,而是一个应用题,要找到产生这种差异的根源,并且试图解决。

  解决这种问题的重要性比较明显。因为不解决它们,你对于它们提供的信息就没有信心。你没有信心,你就不能给你的干系人信心。从悲观的角度看,这种问题要耗费我们许多的精力,我们也不知道何时才能找到正确的方向和结论。从乐观的角度想,能够重现的问题都是好问题,解决它只是早晚和ROI的问题。

  其实,测试人员在测试执行过程中会碰到的“非是非判断”还有很多,在非执行过程就更多了。如需求的学习、参加设计评审、编写测试计划和进行测试结果分析等等。所以,培养测试人员解决“非是非判断”问题的能力就成为一个值得思考的问题。

  如何培养解决“非是非判断”问题的能力?

  首先,要意识到自己有薄弱环节需要加强

  一般测试人员在经过一到两年的工作之后,对于被测系统的需求有了一定了解,对黑盒测试常用的方法和技术有了一定运用,加上一些责任心和细心,已经能够独立地负责一些测试了。但是在碰到一些棘手的问题,如上面提到的“非是非判断”的时候,往往有些手足无措。感到手足无措是正常的,但是请不要把这些问题当成一个个特殊的问题,然后告诉自己“这个问题我从来没有碰到过,所以我不知道如何解决是正常的。”而是要透过这样一个一个比较有挑战性的问题,看到自己在哪些方面还需要大力地投入和改进。也许是对架构的理解、也许是对设计和编码的了解、也许是多样的测试手法、也许是综合考虑问题的思路。。。

  其次,要珍惜碰到棘手问题的机会

  前阵子我在小区里散步,走到一棵枇杷树下,抬头看到高一些的枝头上挂满了浅黄色成熟的枇杷,略矮一些的树枝上残留的枇杷多半是半青半黄的,而最低的枝头已经没有枇杷了。这象极了我们工作时,有些事情是我们举手之劳,轻易就可以完成的,正如去摘取那低处的枇杷。有些事情我们需要努力去蹦、去跳才能够到,正如摘取那略高处的枇杷。还有些事情是我们觉得有更高的价值,如那高处最甜美的枇杷,但以我们现在的能力,光多蹦几次也无济于事,所以我们需要手脑并用,去创造一些新的条件才可以做到。如通过一些工具武装自己,或者借用一些资源等。这样想来,碰到超出我们能力的棘手问题的时候,我们是否应该从更乐观的一面去看待它,把它当成那高处的枇杷呢?

  当然,工作中有时迫于时间的压力,心急是难免的。但急是解决不了问题的,所以我们要用冷静理性的思考来缓冲自己迫切需要解决问题的情绪,要及时在感觉不对的方向停止前进,避免南辕北辙。更多的时候,我们需要培养自己及时停止在错误的方向前进的能力,而不要侥幸地期盼一下子就找到正确的方向。

  如果你很少碰到棘手的问题,那恐怕你要刻意地去寻找一些这样的问题了。因为人一般是会倾向于蜗居在自己的舒适区里自我感觉良好的。但进步往往要开始于一些你感到不舒服而希望改变的地方。可喜的是这样的问题并不难找。

  再次,运用系统思考方法来锻炼自己认识问题和解决问题的能力

  即使有多年的工作经验,工作中有时我也会手足无措,感到自己面对的是一个小时候弄乱的毛线球,左拉右扯找不到解开打结的关键,甚至越来越乱。但当我有了这种感觉后,我一般让自己喊停,不再对着计算机快速地输入和快速地试错,而是停顿手上的动作,开始更多的思考和整理。我发散地想各种可能的因素,排除一些不可能的因素,重新理解各种已知的信息,重新审视我的思路和操作过程,分解大问题到小问题,逐步验证我的假设和实际结果。。。我相信,计算机不会骗人,解决复杂的计算机问题不能靠碰,也不能仅靠我脑子里原来已有的认识,而要临场学习更多的东西。但每次解决一个棘手的问题,我就得到了对于问题本身的新的认识,也掌握了解决它的至少一种方法。更重要的是,我更多地了解了自己,也为日后摘取更高处的枇杷在自己脚下多垫了一块砖。

posted @ 2012-07-31 10:17 顺其自然EVO 阅读(240) | 评论 (0)编辑 收藏

Java异常的概念和分类

  java异常是java提供的用于处理程序中错误的一种机制。

  所谓错误是指在程序运行的过程中发生的一些异常事件(如:除0溢出,数组下标越界,所要读取的文件不存在)。

  设计良好地程序应该在程序异常发生时提供处理这些错误的方法,使得程序不会因为异常的发生而阻断或产生不可预见的结果。

  Java程序的执行过程中如出现异常事件,可以生成一个异常类对象,该异常对象封装了异常事件的信息,并将被提交给java运行时系统,这个过程称为抛出(throw)异常。

  当Java运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程称为捕获(catch)异常。

  try里面放的是有可能发生错误的语句,catch里面放的是发生异常之后采取的措施。

  异常的分类:

  Error:称为错误,由Java虚拟机生成并抛出,包括动态链接失败,虚拟机错误等,程序对其不做处理。

  Exception:所有异常类的父类,其子类对应了各种各样的可能出现的异常事件,一般需要用户显示的声明或捕获。

  Runtime Exception:一类特殊的异常,如被0除、数组下标超范围等,其产生比较频繁,处理麻烦,如果显示的声明或捕获将会对程序可读性和运行效率影响很大。因此由系统自动检测并将它们交给缺省的异常处理程序(用户可不必对其处理)。

  其实异常部分主要讲的就是五个关键字:try、catch、finally、throw、throws。

  try语句:

  try{……}语句制定了一段代码,这段代码就是一次铺货并处理例外的范围。在执行过程中,该段代码可能会产生并抛出一种或几种类型的异常对象,它后面的catch语句要分别对这些异常做相应的处理。如果没有例外发生,所有的catch代码段都被略过不执行。

  catch语句:

  在catch语句块中是对异常进行处理的代码,每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。

  在catch中声明的异常对象(catch(SomeException e))封装了异常事件发生的信息,在catch语句块中可以使用这个对象的一些方法获取这些信息。

  例如:getMessage()方法,用来得到有关异常事件的信息。

  printStackTrace()方法,用来跟踪异常事件发生时执行堆栈的内容。

  finally语句:

  finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序的其他部分以前,能够对程序的状态做统一的管理。

  无论try所指定的程序块中是否抛出例外,finally所指定的代码都要执行。

  通常在finally语句中可以进行资源的清除工作,如:

  1)关闭打开的文件

  2)删除临时文件

  3)……

  其中throw和throws的区别:

  1、throws关键字通常被应用在声明方法时,用来指定可能抛出的异常。多个异常可以使用逗号隔开。当在住函数中调用该方法时,如果发生异常,就会将异常抛给指定异常对象。

  例如:

<SPAN style="FONT-SIZE: 18px">public class test {
 static void pop() throws NegativeArraySizeException{
  //定义方法并抛出NegativeArraySizeException
  int[] arr=new int[-3];//创建数组
 }
 public static void main(String[] args)//主方法
 {
  try{
   pop();//调用pop()方法
  }catch(NegativeArraySizeException e){
   System.out.println("pop()方法抛出的异常");//输出异常信息
  }
 }
}</SPAN>

  2、throw关键字通常用在方法体中,并且抛出一个异常对象。程序在执行到throw语句时立即停止,它后面的语句都不执行。通常throw抛出异常后,如果想在上一级代码中来捕获并处理异常,则需要在抛出异常的方法中使用throws关键字在方法声明中指明要抛出的异常;如果要捕获throw抛出的异常,则必须使用try{}catch{}语句。

  例如:

<SPAN style="FONT-SIZE: 18px">public class MyException extends Exception{//创建自定义异常类
  String message;//定义String类型变量
  public MyException(String ErrorMessage){//父类方法
   message=ErrorMessage;
  }
  public String getMessage()//覆盖getMessage()方法
  {
   return message;
  }
 }


    public class Captor {//创建类
 static int quotient(int x,int y) throws MyException{
  if(y<0){//判断参数是否小于0
   throw new MyException("除数不能使负数");//异常信息
  }
  return x/y;//返回值
 }
 
 public static void main(String[] args)//主方法
 {
  try{
   int result=quotient(3,-1);
  }catch(MyException e){//处理自定义异常
   System.out.println(e.getMessage());//输出异常信息
  }catch(ArithmeticException e){
   //输出ArithmeticException算术异常
   System.out.println("除数不能为0");//输出提示信息
  }catch(Exception e){//处理其他异常
   System.out.println("程序发生了其他异常");
  }
 }
}</SPAN>



  异常的其他问题:

  注:上图灰色部分为打印出来的堆栈错误信息

  声明并抛出异常:

  重写方法需要抛出与原方法所抛出异常类型一致异常或不抛出异常。





  自定义异常:

  使用自定义异常一般有如下步骤:

  1、通过继承java.lang.Exception类声明自己的异常类。

  2、在方法适当的位置生成自定义异常的实例,并用throw语句抛出。

  3、在方法的声明部分用throws语句声明该方法可能抛出的异常。

  异常总结:

  1、一个图

  2、五个关键字

  3、先捕获小的异常,在捕获大的异常

  4、异常和重写的关系

























posted @ 2012-07-30 10:49 顺其自然EVO 阅读(1228) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 303 304 305 306 307 308 309 310 311 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜