qileilove

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

Java初学者都必须理解的六大问题

问题一:我声明了什么!
  String s = "Hello world!";
  许多人都做过这样的事情,但是,我们到底声明了什么?回答通常是:一个String,内容是“Hello world!”。这样模糊的回答通常是概念不清的根源。如果要准确的回答,一半的人大概会回答错误。
  这个语句声明的是一个指向对象的引用,名为“s”,可以指向类型为String的任何对象,目前指向"Hello world!"这个String类型的对象。这就是真正发生的事情。我们并没有声明一个String对象,我们只是声明了一个只能指向String对象的引用变量。所以,如果在刚才那句语句后面,如果再运行一句:
  String string = s;
  我们是声明了另外一个只能指向String对象的引用,名为string,并没有第二个对象产生,string还是指向原来那个对象,也就是,和s指向同一个对象。
  问题二:"=="和equals方法究竟有什么区别?
  ==操作符专门用来比较变量的值是否相等。
  比较好理解的一点是:
  int a=10;    int b=10;
  则a==b将是true。
  但不好理解的地方是:
  String a=new String("foo");    String b=new String("foo");
  则a==b将返回false。
  根据前一帖说过,对象变量其实是一个引用,它们的值是指向对象所在的内存地址,而不是对象本身。a和b都使用了new操作符,意味着将在内存中产生两个内容为"foo"的字符串,既然是“两个”,它们自然位于不同的内存地址。a和b的值其实是两个不同的内存地址的值,所以使用"=="操作符,结果会是false。诚然,a和b所指的对象,它们的内容都是"foo",应该是“相等”,但是==操作符并不涉及到对象内容的比较。
  对象内容的比较,正是equals方法做的事。
  看一下Object对象的equals方法是如何实现的:
  boolean equals(Object o){    return this==o;    }
  Object对象默认使用了==操作符。所以如果你自创的类没有覆盖equals方法,那你的类使用equals和使用==会得到同样的结果。同样也可以看出,Object的equals方法没有达到equals方法应该达到的目标:比较两个对象内容是否相等。因为答案应该由类的创建者决定,所以Object把这个任务留给了类的创建者。
  看一下一个极端的类:
  Class Monster{   private String content;   ...   boolean equals(Object another){  return true;  }   }
  我覆盖了equals方法。这个实现会导致无论Monster实例内容如何,它们之间的比较永远返回true。
  所以当你是用equals方法判断对象的内容是否相等,请不要想当然。因为可能你认为相等,而这个类的作者不这样认为,而类的equals方法的实现是由他掌握的。如果你需要使用equals方法,或者使用任何基于散列码的集合(HashSet,HashMap,HashTable),请察看一下java doc以确认这个类的equals逻辑是如何实现的。
  问题三:String到底变了没有?
  没有。因为String被设计成不可变(immutable)类,所以它的所有对象都是不可变对象。请看下列代码:
  String s = "Hello";  s = s + " world!";
  s所指向的对象是否改变了呢?从本系列第一篇的结论很容易导出这个结论。我们来看看发生了什么事情。在这段代码中,s原先指向一个String对象,内容是"Hello",然后我们对s进行了+操作,那么s所指向的那个对象是否发生了改变呢?答案是没有。这时,s不指向原来那个对象了,而指向了另一个String对象,内容为"Hello world!",原来那个对象还存在于内存之中,只是s这个引用变量不再指向它了。
  通过上面的说明,我们很容易导出另一个结论,如果经常对字符串进行各种各样的修改,或者说,不可预见的修改,那么使用String来代表字符串的话会引起很大的内存开销。因为String对象建立之后不能再改变,所以对于每一个不同的字符串,都需要一个String对象来表示。这时,应该考虑使用StringBuffer类,它允许修改,而不是每个不同的字符串都要生成一个新的对象。并且,这两种类的对象转换十分容易。
  同时,我们还可以知道,如果要使用内容相同的字符串,不必每次都new一个String。例如我们要在构造器中对一个名叫s的String引用变量进行初始化,把它设置为初始值,应当这样做:
  public class Demo {  private String s;  ...  public Demo {  s = "Initial Value";  }  ...  }
  而非
  s = new String("Initial Value");
  后者每次都会调用构造器,生成新对象,性能低下且内存开销大,并且没有意义,因为String对象不可改变,所以对于内容相同的字符串,只要一个String对象来表示就可以了。也就说,多次调用上面的构造器创建多个对象,他们的String类型属性s都指向同一个对象。
  上面的结论还基于这样一个事实:对于字符串常量,如果内容相同,Java认为它们代表同一个String对象。而用关键字new调用构造器,总是会创建一个新的对象,无论内容是否相同。
  至于为什么要把String类设计成不可变类,是它的用途决定的。其实不只String,很多Java标准类库中的类都是不可变的。在开发一个系统的时候,我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优点,比如因为它的对象是只读的,所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如每个不同的状态都要一个对象来代表,可能会造成性能上的问题。所以Java标准类库还提供了一个可变版本,即StringBuffer。
问题四:final关键字到底修饰了什么?
  final使得被修饰的变量"不变",但是由于对象型变量的本质是“引用”,使得“不变”也有了两种含义:引用本身的不变,和引用指向的对象不变。
  引用本身的不变:
  final StringBuffer a=new StringBuffer("immutable");  final StringBuffer b=new StringBuffer("not immutable");  a=b;//编译期错误
  引用指向的对象不变:
  final StringBuffer a=new StringBuffer("immutable");  a.append(" broken!"); //编译通过
  可见,final只对引用的“值”(也即它所指向的那个对象的内存地址)有效,它迫使引用只能指向初始指向的那个对象,改变它的指向会导致编译期错误。至于它所指向的对象的变化,final是不负责的。这很类似==操作符:==操作符只负责引用的“值”相等,至于这个地址所指向的对象内容是否相等,==操作符是不管的。 理解final问题有很重要的含义。许多程序漏洞都基于此----final只能保证引用永远指向固定对象,不能保证那个对象的状态不变。在多线程的操作中,一个对象会被多个线程共享或修改,一个线程对对象无意识的修改可能会导致另一个使用此对象的线程崩溃。一个错误的解决方法就是在此对象新建的时候把它声明为final,意图使得它“永远不变”。其实那是徒劳的。
  问题五:到底要怎么样初始化!
  本问题讨论变量的初始化,所以先来看一下Java中有哪些种类的变量。
  1. 类的属性,或者叫值域
  2. 方法里的局部变量
  3. 方法的参数
  对于第一种变量,Java虚拟机会自动进行初始化。如果给出了初始值,则初始化为该初始值。如果没有给出,则把它初始化为该类型变量的默认初始值。
  int类型变量默认初始值为0
  float类型变量默认初始值为0.0f
  double类型变量默认初始值为0.0
  boolean类型变量默认初始值为false
  char类型变量默认初始值为0(ASCII码)
  long类型变量默认初始值为0
  所有对象引用类型变量默认初始值为null,即不指向任何对象。注意数组本身也是对象,所以没有初始化的数组引用在自动初始化后其值也是null。
  对于两种不同的类属性,static属性与instance属性,初始化的时机是不同的。instance属性在创建实例的时候初始化,static属性在类加载,也就是第一次用到这个类的时候初始化,对于后来的实例的创建,不再次进行初始化。这个问题会在以后的系列中进行详细讨论。
  对于第二种变量,必须明确地进行初始化。如果再没有初始化之前就试图使用它,编译器会抗议。如果初始化的语句在try块中或if块中,也必须要让它在第一次使用前一定能够得到赋值。也就是说,把初始化语句放在只有if块的条件判断语句中编译器也会抗议,因为执行的时候可能不符合if后面的判断条件,如此一来初始化语句就不会被执行了,这就违反了局部变量使用前必须初始化的规定。但如果在else块中也有初始化语句,就可以通过编译,因为无论如何,总有至少一条初始化语句会被执行,不会发生使用前未被初始化的事情。对于try-catch也是一样,如果只有在try块里才有初始化语句,编译部通过。如果在catch或finally里也有,则可以通过编译。总之,要保证局部变量在使用之前一定被初始化了。所以,一个好的做法是在声明他们的时候就初始化他们,如果不知道要出事化成什么值好,就用上面的默认值吧!
  其实第三种变量和第二种本质上是一样的,都是方法中的局部变量。只不过作为参数,肯定是被初始化过的,传入的值就是初始值,所以不需要初始化。
  问题六:instanceof是什么东东?
  instanceof是Java的一个二元操作符,和==,> , <是同一类东东。由于它是由字母组成的,所以也是Java的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回boolean类型的数据。举个例子:
  String s = "I AM an Object!";   boolean isObject = s instanceof Object;
  我们声明了一个String对象引用,指向一个String对象,然后用instancof来测试它所指向的对象是否是Object类的一个实例,显然,这是真的,所以返回true,也就是isObject的值为True。
  instanceof有一些用处。比如我们写了一个处理账单的系统,其中有这样三个类:
  public class Bill {//省略细节}   public class PhoneBill extends Bill {//省略细节}   public class GasBill extends Bill {//省略细节}
  在处理程序里有一个方法,接受一个Bill类型的对象,计算金额。假设两种账单计算方法不同,而传入的Bill对象可能是两种中的任何一种,所以要用instanceof来判断:
  public double calculate(Bill bill) {  if (bill instanceof PhoneBill) {  //计算电话账单  }  if (bill instanceof GasBill) {  //计算燃气账单  }  ...  }
  这样就可以用一个方法处理两种子类。 然而,这种做法通常被认为是没有好好利用面向对象中的多态性。其实上面的功能要求用方法重载完全可以实现,这是面向对象变成应有的做法,避免回到结构化编程模式。只要提供两个名字和返回值都相同,接受参数类型不同的方法就可以了:
  public double calculate(PhoneBill bill) {  //计算电话账单  }  public double calculate(GasBill bill) {  //计算燃气账单  }

posted @ 2014-09-26 11:31 顺其自然EVO 阅读(173) | 评论 (0)编辑 收藏

我对项目管理的一些思考

一,项目管理的模型
  从传统瀑布流到现在的基于快速迭代的各种灵活的模型和管理框架,发展非常迅速,而且也逐步被引入到各个非软件开发领域里去.新的企业也在尝试着比较新的敏捷开发的实践.比如减少冗余繁杂的文档,项目估时,站立会议等.
  有些成功了,有些也失败了.失败的几乎都是因为团队本身的成长限制了执行的力度,或者与团队现有的管理模型有所冲突,导致各种不适应,最终放弃.我们自己也在这方面做着很多的整合尝试,却最终因为缺少比较接地气的工具而受了不少挫.
  也有不少实际的问题,比如:
  1,每个人互相不太知道对方做了什么,所以到了涉及到其它人相关的模块时,无法确定自己是否应该继续还是停下来.
  2,我的代码写完了,测试总是迟迟不能得到通知.
  3,如果总是在需要跟别人交互的时候打扰别人,又会让整体的效率降低.
  4,TM,PM也缺乏对项目的整体的直观的管控.
  …
  这样的类似的问题很多,各自也有各自的解决方案.我们采用了一种比较安静的做法,整个过程不希望总是打断别人.并且可以实时的监控所有人的行为,比如正在做什么,哪些是做完了的,哪些是正在做的,哪些还没有开始.是不是有任务被移交到了我这里(比如需要测试的部分).
  我自己也能一目了然的知道我所有的工作,并且能以非常直观的形式看到我每天的工作.管理者也要能非常清楚的看到整个团队的工作.
  二,工具的用户体验和工具的实际效果.
  如果没有更合手的工具,大家往往不愿意使用.
  比如画软件原型,有很多原型软件如Axure,但是很多人还是更喜欢用笔在纸上画.只有真正某个软件足够便利而且节约很多时间,大家才会转到这个上面来
  在一直以来的项目管理里,也一直在调研不同的项目管理工具,最开始的Project,TFS,很多开源的软件,网站等各种应用.却一直没有找到一个很适合我理想中的工具,我的需求也很简单:
  1,一个自由公开的白板,
  2,一个直观查看所做任务的日历
  3,一个燃尽图,知道项目是否延迟还是提前
  4,跟其它组或者公司进行协同.
  另外一个需求是:我的个人倡导,我希望建立一个共平自由的合作环境.
  我大致说一下传统的软件的做法和我的冲突:
  1,在我调研过的系统中部分是有白板的,但是操作上比较麻烦一些,我希望能直接拖动就能达到目的的.
  2,普通认为表格是最好的表达形式,比如所有的任务列表,bug列表,可以通过搜索,排序等方式进行管理.每次要分析今天哪些人做了哪些事,需要一次一次的筛,一次一次的分类看.我是觉得挺累的.
  3,软件项目往往会产生的情况是前期松,后期紧,甚至超期,我希望知道是什么原因导致了这种情况的发生,当前项目进展是否是健康并且正常的.我只需要一个燃尽图.而现在的往往做得比较复杂.
  4,跟其它组或公司的配合,这个组和公司并不一定是软件开发团队.比如客户公司的营销团队,设计部,开发部等.需要整体协作起来.
  5,我希望所有团队成员都是平等的.没有等级关系,没有项目经理,组长,组员的层级关系,没有谁对谁负责.因为一个项目是大家共同努力的结果,每个人都应该对最终的结果负责,每个人都应该有自我协调能力.
  我的需求不太多,但是我希望足够好用,而且直接有效.
 三,团队协作和软件
  从一个游戏来看团队协作
  我以前曾经玩过一个游戏,相信也有很多同行也玩过,游戏很简单.在一个空房子里,摆满很多凳子,然后由一个人被蒙上眼睛,由另一个人在旁边指挥,什么地方应该转弯,什么地方应该往前走,最后到达目的地,再一次,摘掉眼罩,由他自己决定.两次的速度相关是非常大的,结果也是显而易见的. 所以细节的实现更应该去相信员工自己,让员工自己来解决,而不是事无巨细的管理.
  从版本管理软件的发展来看团队协作
  大家在工作中肯定有用过很多版本管理软件,比如有名的有: vss,svn,git每一个都有各自鲜明的特点.
  Vss: 它有这样比较明显的特点,整个过程基于锁定和解锁,如果你想修改某个文件,需要先锁定签出,然后修改完后再提交,提交结束后便解锁.这时如果有其它人需要修改这些文件,需要等别人提交后才能解锁,签出,然后修改完成后再提交.他对版本的管理是依赖于同时只有一个人使用一个文件,当然你可以选择vss支持的另一种更开发的模式,但是这个已经放弃了vss本身的优点,利用版本管理软件来建立起一个有序的开发的流程.以消除文件编辑的冲突. 同时带来的负作用就是大家往往一半时间在等待其它人提交释放锁,而且在修改完成后,时刻要记得去提交.签出时也小心翼翼.
  Svn:从vss过渡到svn,是一个自我解放的过程.每个人可以自由奔放的修改然后提交,如果提交的文件里没有别人修改的文件,就只管提交,如果有,更新下再提交.在实际工作中,因为大家实现的是不同的模块,90%左右的冲突都由svn本身的合并功能解决了.只有极少部分需要手动合并,这要归功于svn的强大的合并功能还有忽略文件的配置等.它把可能的冲突转给的团队线下自身来解决,事实上,人的可调控性远远好于软件的强制性,很快采用这个版本管理软件的团队,制定出了一套协作的方案,使每个人的工作独立,相互没有影响,当然也同时促进了团队的架构水平和管理水平.
  Git:从vss过渡到git,则是一种更大的自我释放,它的历史版本管理,不再完全依整服务器,文件提交也不再完全依赖网络,他可以仅仅只是先提交到本地,在本地积累到一定程度后,再一起提交到服务器.可以说一个本地副本在提交到服务器前就是一个svn,一个分支,你可以自由的回滚,可以最终提交你的决定.更多的工作交由线下自身来解决.
  他们也呈现出了一种从封闭到开放,从软件限制转到人为管理转化的过程.很可喜的是每一次转化都极大的提高了生产率.也同时提高了团队的管理水平.
  再回顾企业管理,总监下有经理,经理有部门,部门有组长,组长有成员.一级一级管控.如果有个办公室需要买一本书,可能需要给组长申请,组长再提交部门审批.一级一级.从想买到实际买到可能已经过了一周了.一周后,可能这本书就没必要买了.当然在大的企业管理里,这样没什么问题. 但是我想如果把这种层级关系放开,由扁平化的组织结构来管理,再制定一定的机制让人员自我管理.这个效率会高很多.当然可能也会非常混乱.
  对于小的团队来说,如果所有成员扁平化,每个成员都是团队里重要的一员,每个人都有权力做所有的事情.我想这一定会是一个更高效的团队.我举几个例子:
  1,如果团队成员因为有病不能来,但是项目又要求他这方面的工作完成,我可以直接拿过来他的任务然后完成它.
  2,如果我有一个模块开发完成,我可以直接拖到测试员,测试员直接接手测试.
  3,测试员完成测试,反应出一些问题,可以直接递回我做修改.
  我想权力越大,操作就会越谨慎,我们不应该总是把大家绑得死死的.大家有了灵活性,反而不会去做一些实际上会逾越自己权力的事情.只在必要时去做.这个必要性,线下大家讨论制定出一个协议,然后执行即可.就好像我们制造了一把斧头,但是我们不规定别人如何去使用他,线下我可以帮他们推荐一种比较好的挥斧方式,但是如果他喜欢,他也可以用别的方式来挥斧达到更好的效果.
  还想说点什么
  如果你是一个程序员,你是不是很想分享你的一个惊天的发现,可能是一个js的游戏开发框架,可能是你写的一个无比牛比的demo,有可能是你找出一个许久没有解决的程序的bug.也许是你花了两天时间最终配置起来的nodejs成套的开发环境.你是不想希望得到别人的关注,领导的关注,希望有一些成就感.那么你肯定也希望有一个能写点什么的地方.所以也希望有一个知识库,可以展现自己.

posted @ 2014-09-26 11:30 顺其自然EVO 阅读(191) | 评论 (0)编辑 收藏

软件产品需求分析模板

1. 引言
  引言是对这份软件产品需求分析报告的概览,是为了帮助阅读者了解这份文档是如何编写的,并且应该如何阅读、理解和解释这份文档。
  1.1 编写目的
  说明这份软件产品需求分析报告是为哪个软件产品编写的,开发这个软件产品意义、作用、以及最终要达到的意图。通过这份软件产品需求分析报告详尽说明了该软件产品的需求规格,包括修正和(或)发行版本号,从而对该软件产品进行准确的定义。
  如果这份软件产品需求分析报告只与整个系统的某一部分有关系,那么只定义软件产品需求分析报告中说明的那个部分或子系统。
  1.2 项目风险
  具体说明本软件开发项目的全部风险承担者,以及各自在本阶段所需要承担的主要风险,首要风险承担者包括:
  ● 任务提出者;
  ● 软件开发者;
  ● 产品使用者。
  1.3 文档约定
  描述编写文档时所采用的标准(如果有标准的话),或者各种排版约定。排版约定应该包括:
  ● 正文风格;
  ● 提示方式;
  ● 重要符号;
  也应该说明高层次需求是否可以被其所有细化的需求所继承,或者每个需求陈述是否都有其自己的优先级。
  1.4 预期读者和阅读建议
  列举本软件产品需求分析报告所针对的各种不同的预期读者,例如,可能包括:
  ● 用户;
  ● 开发人员;
  ● 项目经理;
  ● 营销人员;
  ● 测试人员;
  ● 文档编写入员。
  并且描述了文档中,其余部分的内容及其组织结构,并且针对每一类读者提出最适合的文档阅读建议。
  1.5 产品范围
  说明该软件产品及其开发目的的简短描述,包括利益和目标。把软件产品开发与企业目标,或者业务策略相联系。
  描述产品范围时需注意,可以参考项目视图和范围文档,但是不能将其内容复制到这里。
  1.6 参考文献
  列举编写软件产品需求分析报告时所用到的参考文献及资料,可能包括:
  ● 本项目的合同书;
  ● 上级机关有关本项目的批文;
  ● 本项目已经批准的计划任务书;
  ● 用户界面风格指导;
  ● 开发本项目时所要用到的标淮;
  ● 系统规格需求说明;
  ● 使用实例文档;
  ● 属于本项目的其它己发表文件;
  ● 本软件产品需求分析报告中所引用的文件、资料;
  ● 相关软件产品需求分析报告;
  为了方便读者查阅,所有参考资料应该按一定顺序排列。如果可能,每份资料都应该给出:
  ● 标题名称;
  ● 作者或者合同签约者;
  ● 文件编号或者版本号;
  ● 发表日期或者签约日期;
  ● 出版单位或者资料来源。
 2. 综合描述
  这一部分概述了正在定义的软件产品的作用范围以及该软件产品所运行的环境、使用该软件产品的用户、对该软件产品己知的限制、有关该软件产品的假设和依赖。
  2.1 产品的状况
  描述了在软件产品需求分析报告中所定义的软件产品的背景和起源。说明了该软件产品是否属于下列情况:
  ● 是否是产品系列中的下一成员;
  ● 是否是成熟产品所改进的下一代产品;
  ● 是否是现有应用软件的替代品(升级产品);
  ● 是否是一个新型的、自主型的产品。
  如果该软件产品需求分析报告定义的软件系统是:
  ● 大系统的一个组成部分;
  ● 与其它系统和其它机构之间存在基本的相互关系。
  那么必须说明软件产品需求分析报告定义的这部分软件是怎样与整个大系统相关联的,或者(同时)说明相互关系的存在形式,并且要定义出两者之间的全部接口。
  2.2 产品的功能
  因为将在需求分析报告的第4部分中详细描述软件产品的功能,所以在此只需要概略地总结。仅从业务层面陈述本软件产品所应具有的主要功能,在描述功能时应该 针对每一项需求准确地描述其各项规格说明。如果存在引起误解的可能,在陈述本软件产品主要功能的作用领域时,也需要对应陈述本软件产品的非作用领域,以利 读者理解本软件产品。
  为了很好地组织产品功能,使每个读者都容易理解,可以采用列表的方法给出。也可以采用图形方式,将主要的需求分组以及它们之间的联系使用数据流程图的顶层图或类图进行表示,这种表示方法是很有用的。
  参考用户当前管理组织构架,了解各个机构的主要职能,将有助于陈述软件产品的主要功能。
  2.3 用户类和特性
  确定有可能使用该软件产品的不同用户类,并且描述它们相关的特征。往往有一些软件需求,只与特定的用户类有关。描述时,应该将该软件产品的重要用户类与非重要用户类区分开。
  用户不一定是软件产品的直接使用者,通过报表、应用程序接口、系统硬件接口得到软件产品的数据和服务的人、或者机构也有他们的需求。所以,应该将这些外部需求视为通过报表、应用程序接口、系统硬件接口附加给软件产品的附加用户类。
  2.4 运行环境
  描述了本软件的运行环境,一般包括:
  ● 硬件平台;
  ● 操作系统和版本;
  ● 支撑环境(例如:数据库等)和版本;
  ● 其它与该软件有关的软件组件;
  ● 与该软件共存的应用程序。
  2.5 设计和实现上的限制
  确定影响开发人员自由选择的问题,并且说明这些问题为什么成为一种限制。可能的限制包括下列内容:
  ● 必须使用的特定技术、工具、编程语言和数据库;
  ● 避免使用的特定技术、工具、编程语言和数据库;
  ● 要求遵循的开发规范和标准
  例如,如果由客户的公司或者第三方公司负责软件维护,就必须定义转包者所使用的设计符号表示和编码标准;
  ● 企业策略的限制;
  ● 政府法规的限制;
  ● 工业标准的限制;
  ● 硬件的限制
  例如,定时需求或存储器限制;
  ● 数据转换格式标淮的限制。
  2.6 假设和约束(依赖)
  列举出对软件产品需求分析报告中,影响需求陈述的假设因素(与己知因素相对立)。如果这些假设因素不正确、不一致或者被修改,就会使软件产品开发项目受到影响。这些假设的因素可能包括:
  ● 计划使用的商业组件,或者其它软件中的某个部件;
  ● 假定产品中某个用户界面将符合一个特殊的设计约定;
  ● 有关本软件用户的若干假定(例如:假定用户会熟练使用SQL语言。);
  ● 有关本软件开发工作的若干假定(例如:用户承诺的优惠、方便、上级部门给予的特殊政策和支持等。);
  ● 有关本软件运行环境的一些问题;
  此外,确定本软件开发项目对外部约束因素所存在的依赖。有关的约束可能包括:
  ● 工期约束;
  ● 经费约束;
  ● 人员约束;
  ● 设备约束;
  ● 地理位置约束;
  ● 其它有关项目约束;
  3. 外部接口需求
  通过本节描述可以确定,保证软件产品能和外部组件正确连接的需求。关联图仅能表示高层抽象的外部接口,必须对接口数据和外部组件进行详细描述,并且写入数 据定义中。如果产品的不同部分有不同的外部接口,那么应该把这些外部接口的全部详细需求并入到这一部分实例中。
  注意:必须将附加用户类的特征与外部接口需求加以区分,附加用户类的特征描述的是通过接口取得软件产品的数据和服务的人的需求;而外部接口需求描述的是接口本身的需求。
  3.1 用户界面
  陈述需要使用在用户界面上的软件组件,描述每一个用户界面的逻辑特征。必须注意,这里需要描述的是用户界面的逻辑特征,而不是用户界面。以下是可能包括的一些特征:
  ● 将要采用的图形用户界面(GUl)标准或者产品系列的风格;
  ● 有关屏幕布局或者解决方案的限制;
  ● 将要使用在每一个屏幕(图形用户界面)上的软件组件,可能包括:
  选单;
  标准按钮;
  导航链接;
  各种功能组件;
  消息栏;
  ● 快捷键;
  ● 各种显示格式的规定,可能包括:
  不同情况下文字的对齐方式;
  不同情况下数字的表现格式与对齐方式;
  日期的表现方法与格式;
  计时方法与时间格式;
  等等。
  ● 错误信息显示标准;
  对于用户界面的细节,例如:一个特定对话框的布局,应该写入具体的用户界面设计说明中,而不能写入软件需求规格说明中。
  如果采用现成的、合适的用户界面设计规范(标准),或者另文描述,可以在这里直接说明,并且将其加入参考文献。
  3.2 硬件接口
  描述待开发的软件产品与系统硬件接口的特征,若有多个硬件接口,则必须全都描述。接口特征的描述内容可能包括:
  ● 支持的硬件类型;
  ● 软、硬件之间交流的数据;
  ● 控制信息的性质;
  ● 使用的通讯协议;
  3.3 软件接口
  描述该软件产品与其它外部组件的连接,这些外部组件必须明确它们的名称和版本号以资识别,可能的外部组件包括:
  ● 操作系统;
  ● 数据库;
  ● 工具;
  ● 函数库;
  ● 集成的商业组件
  说明:这里所说的“集成的商业组件”,是指与系统集成的商业组件,而不是与软件产品集成的商业组件。例如:中间件、消息服务,等等。
  描述并且明确软件产品与软件组件之间交换数据或者消息的目的。描述所需要的服务,以及与内部组件通讯的性质。确定软件产品将与组件之间共享的数据。如果必 须使用一种特殊的方法来实现数据共享机制,例如:在多用户系统中的一个全局数据区,那么就必须把它定义为一种实现上的限制。
  3.4 通讯接口
  描述与软件产品所使用的通讯功能相关的需求,包括:
  ● 电子邮件;
  ● WEB浏览器;
  ● 网络通讯标准或者协议;
  ● 数据交互用电子表格;
  必须定义相关的:
  ● 消息格式;
  ● 通讯安全或加密问题;
  ● 数据传输速率;
  ● 同步和异步通讯机制;
  4. 系统功能需求
  需要进行详细的需求记录,详细列出与该系统功能相关的详细功能需求,并且,唯一地标识每一项需求。这是必须提交给用户的软件功能,使得用户可以使用所提供 的功能执行服务或者使用所指定的使用实例执行任务。描述软件产品如何响应己知的出错条件、非法输入、非法动作。
  如果每一项功能需求都能用一项,也只需要用一项测试用例就能进行验证,那么就可以认为功能需求已经适当地进行描述了。如果某项功能需求找不到合适的测试用例,或者必须使用多项测试用例才能验证,那么该项功能需求的描述必然存在某些问题。
  功能需求是根据系统功能,即软件产品所提供的主要服务来组织的。可以通过使用实例、运行模式、用户类、对象类或者功能等级来组织这部分内容,也可以便用这些元素的组合。总而言之,必须选择一种是读者容易理解预期产品的组织方案。
  用简短的语句说明功能的名称,例如:“4.1系统参数管理”。按照服务组织的顺序,逐条阐述系统功能。无论说明的是何种功能,都应该针对该系统功能重复叙述4.1~ 4.3这三个部分。
  可以通过各种方式来组织这一部分内容,例如采用:使用实例、运行模式、用户类、对象类、功能等级等,也可以采用它们的组合。其最终目的是,让读者容易理解 即将开发的软件产品。一般来说,每个使用实例都对应一个系统功能,因而按照使用实例来组织内容比较容易让用户理解。
  对应一些被共享的独立使用实例,可以定义一些公用系统功能。
  必须特别注意的是,在2.2节“产品的功能”中描述的全部需求,以及它们的规格说明;必须在某个系统功能描述中有所反映,而且不应重复。
  4.1 说明和优先级
  对该系统功能进行简短的说明,并且指出该系统功能的优先级是:高、中、还是低。需要的话,还可以包括对特定优先级部分的评价,例如:利益、损失、费用和风险,其相对优先等级可以从1(低)到9(高)。
  4.2 激励/响应序列
  列出输入激励(用户动作、来自外部设备的信号或者其它触发)并且定义针对这——功能行为的系统响应序列,这些序列将与使用实例中相关的对话元素相对应。
  描述激励/响应序列时,不仅需要描述基本过程,而且应该描述可选(扩充)过程,包括例外(引起任务不能顺序完成的情况称为例外)。疏忽了可选过程,有可能影响软件产品的功能;如果遗漏例外过程,则有可能会引发系统崩溃。
  如果采用流程图来描述激励/响应序列,比较容易让用户理解。
  4.3 输入/输出数据
  列出输入数据(用户输入、来自外部接口的输入或者其它输入)并且定义针对这些输入数据的处理(计算)方法,以及相应地输出数据,描述对应区别:输入数据和输出数据。
  当有大量数据需要描述时,也可以分类描述数据,并且注明各项数据的输入、输出属性。
  对于每一项数据,均需要描述:
  ● 数据名称;
  ● 实际含义;
  ● 数据类型;
  ● 数据格式;
  ● 数据约束;
  对于复杂的处理方法,仅仅给出算法原理是不够的,必须描述详细的计算过程,并且列出每一步具体使用的实际算式;如果计算过程中涉及查表、判断、迭代等处理方法,应该给出处理依据和相关数据。如果计算方法很简单,也可以将其从略,不加描述。
 5. 其它非功能需求
  在这里列举出所有非功能需求,主要包括可靠性、安全性、可维护性、可扩展性、可测试性等。
  5.1 性能需求
  阐述不同应用领域对软件产品性能的需求,并且说明提出需求的原理或者依据,以帮助开发人员做出合理的设计选择。尽可能详细地描述性能需求,如果需要,可以针对每个功能需求或者特征分别陈述其性能需求。在这里确定:
  ● 相互合作的用户数量;
  ● 系统支持的并发操作数量;
  ● 响应时间;
  ● 与实时系统的时间关系:
  ● 容量需求
  存储器;
  磁盘空间;
  数据库中表的最大行数。
  5.2 安全措施需求
  详尽陈述与软件产品使用过程中可能发生的损失、破坏、危害相关的需求。定义必须采取的安全保护或动作,以及必须预防的潜在危险动作。明确软件产品必须遵从的安全标准、策略、或规则。
  5.3 安全性需求
  详尽陈述与系统安全性、完整性问题相关的需求,或者与个人隐私问题相关的需求。这些问题将会影响到软件产品的使用,和软件产品所创建或者使用的数据的保 护。定义用户身份认证,或备授权需求。明确软件产品必须满足的安全性或者保密性策略。也可以通过称为完整性的质量属性来阐述这些需求。一个典型的软件系统 安全需求范例如下:“每个用户在第一次登录后,必须更改他的系统预置登录密码,系统预置的登录密码不能重用。”
  5.4 软件质量属性
  详尽陈述对客户和开发人员至关重要的在软件产品其它方面表现出来的质量功能。这些功能必须是确定的、定量的、在需要时是可以验证的。至少也应该指明不同属性的相对侧重点,例如:易用性优于易学性,或者可移植性优于有效性。
  5.5 业务规则
  列举出有关软件产品的所有操作规则,例如:那些人在特定环境下可以进行何种操作。这些本身不是功能需求,但是他们可以暗示某些功能需求执行这些规则。一个 业务规则的范例如下:“进行达到或者超过10,000,00元人民币的储蓄业务时,必须通过附加的管理员认证。”
  列举业务规则时,可以根据规则的数量,选取合适的编目方式。
  5.6 用户文档
  列举出将与软件产品一同交付的用户文档,并且明确所有己知用户文档的交付格式或标准,例如:
  ● 安装指南
  纸质文档,16开本;
  ● 用户手册
  纸质文档,16开本;
  ● 在线帮助
  ● 电子文档,与软件产品一同分发、配置;
  ● 使用教程电子文档,与软件产品一同分发、配置。
  6. 词汇表
  列出本文件中用到的专业术语的定义,以及有关缩写的定义(如有可能,列出相关的外文原词)。为了便于非软件专业或者非计算机专业人士阅读软件产品需求分析 报告,要求使用非软件专业或者非计算机专业的术语描述软件需求。所以这里所指的专业术语,是指业务层面上的专业术语,而不是软件专业或者计算机专业的术 语。但是,对于无法回避的软件专业或者计算机专业术语,也应该列入词汇表并且加以准确定义。
  7. 数据定义
  数据定义是一个定义了应用程序中使用的所有数据元素和结构的共享文档,其中对每个数据元素和结构都准确描述:含义、类型、数据大小、格式、计量单位、精度 以及取值范围。数据定义的维护独立于软件需求规格说明,并且在软件产品开发和维护的任何阶段,均向风险承担者开放。
  如果为软件开发项目创建一个独立的数据定义,而不是为每一项特性描述有关的数据项,有利于避免冗余和不一致性。但是却不利于多人协同编写需求分析报告,容 易遗漏数据,也不方便阅读。因此还是建议为每个特性描述有关的数据项,汇总数据项创建数据定义,再根据数据定义复核全部数据,使得它们的名称和含义完全一 致。必须注意的是,为了避免二义性,在汇总数据项时应该根据数据项所代表的实际意义汇总,而不是根据数据项的名称汇总。
  在数据定义中,每个数据项除了有一个中文名称外,还应该为它取一个简短的英文名称,该英文名称应该符合命名规范,因为在软件开发时将沿用该英文名称。可以使用等号表示数据项,名称写在左边,定义写在右边。常见数据项的描述方式如下:
  ● 原数据元素
  一个原数据元素是不可分解的,可以将一个数量值赋给它。定义原数据元素必须确定其
  含义、类型、数据大小、格式、计量单位、精度以及取值范围。采用以星号为界的一行
  注释文本,描述原数据元素的定义。
  ● 选择项
  选择项是一种只可以取有限离散值的特殊原数据元素,描述时一一枚举这些值,并用方
  括号括起来写在原数据元素的定义前。在两项离散值之间,使用管道符分隔。
  ● 组合项
  组合项是一个数据结构或者记录,其中包含了多个数据项。这些数据项可以是原数据元
  素,也可以是组合数据项,各数据项之间用加号连接。其中每个数据项都必须是数据定
  义中定义过的,结构中也可以包括其它结构,但是绝对不允许递归。如果数据结构中有
  可选项,使用圆括号把该项括起来。
  ● 重复项
  重复项是组合项的一种特例,其中有一项将有多个实例出现在数据结构中,使用花括号
  把该项括起来。如果知道该项可能允许的范围,就按“最小值:最大值”的形式写在花
  括号前。
  8. 分析模型
  这是一个可选部分,包括或涉及到相关的分析模型,例如:
  ● 数据流程图;
  ● 类图;
  ● 状态转换图;
  ● 实体-关系图。
  9. 待定问题列表
  编辑一张在软件产品需求分析报告中待确定问题时的列表,把每一个表项都编上号,以便跟踪调查。
微信扫描,分享到朋友圈

posted @ 2014-09-26 11:29 顺其自然EVO 阅读(257) | 评论 (0)编辑 收藏

如何重现难以重现的bug

 生活中有这么一种现象:如果你关注某些东西,它就会经常出现在你眼前,例如一个不出名的歌手的名字,一种动物的卡通形象,某个非常专业的术语,等等等等。这种现象也叫做“孕妇效应”。还有类似的一种效应叫做“视网膜效应”,它讲的是:你有什么东西或者特质你就特别容易在别处发现你有的这类东西和特质。干了多年测试的我就会经常发现日常使用的系统中有很多的bug,而我老婆就发现不了。今天要说的事儿是“重现难以重现的bug”,这件事儿在本周共遇见了4次:第一次是微博上有一篇《程序员,你调试过的最难的 Bug 是?》(后面会附上);第二次是一个同事跟我抱怨,好几个bug难以重现特心烦,并问我怎么处理比较好;第三次是本周上线的产品出现了一个当时难以重现的bug,我们对它做了初步的分析;第四次是翻看史亮写的书《软件测试实战》,偶尔翻了翻,竟然看到一小节在写“处理难以处理的缺陷”。这时候,脑子里很多东西汇集到了一起,我想还是记录一下吧。下面是正文:
  也许测试人员(尤其是对新手来说)在工作过程中最不愿遇到的一件事情就是:在测试过程中发现了一个问题,觉得是bug,再试的时候又正常了。碰到这样的事情,职业素养和测试人员长期养成的死磕的习性会让她们觉得不能放过这个bug,但是重现这样的bug有时候需要花费大量的时间,有的时候还有一些盲目性(因为黑盒测试的缘故,很多内部状态是不可见的,因此无法获取有效的信息来做跟踪),效率较为低下。在实际工作中,时间和进度摆在那里,在经历了多次痛苦的失败尝试之后,测试人员的处理方法一般会有如下几种:1.向开发人员寻求帮助来重现bug;2.当做一个issue报给开发人员。可是这样的做法存在如下问题:
  1.开发人员责任心不够强,不愿意花太多精力去求证这件事情,常见的回复就是:在我这儿没事儿啊,我也重现不了,bug关了吧。结果随后在生产系统上,bug又开始sui随机出现了。
  2.就跟测试人员不擅长编码和调试一样,开发人员并不擅长找出bug。经过一番尝试以后,他们也找不出什么问题来,常见的回复同第一条是一样的。bug上线后又出现的宿命也是一样的。
  这时候,真正的问题来了:如何捕捉难以重现的bug?这件事儿对于测试人员来说就这么难么?
  答案并不那么乐观,重现“难以”重现的bug本来就是一件“难以”完成的事情。但“难以”并不是不可能,通过一系列的测试、分析方法,我们是能够抽丝剥茧把绝大部分隐藏的很深的bug揪出来的,当然有的时候你要考虑投入产出比,但投入产出比不是本篇要考虑的,本篇只讲一些我积累的经验。
  为什么不能重现bug?
  最大的原因就是:测试人员对被测物的了解还不够深入。
  我曾经做过一段很长时间的收集和统计,那些被称作过“难以重现”的bug最后都可以分为如下几类:
  1.环境的变更造成了bug难以重现,这里的环境包括了:基础软硬件环境(操作系统、网络、存储、中间件、容器等等),被测物自身发生了某些变更。环境的变更一般是由于多人共用环境造成的,也有少量情况下是系统内部或者时间触发的变更(这类bug非常难重现)。
  2.没有找到真正引发bug的操作。这些操作往往是一些不怎么显而易见的操作,测试人员在不经意间完成,而又忽略了这一操作,以致难于重现bug。
  3.没有找到真正会引发bug的操作序列。很多bug的重现需要满足多个条件。在满足多个条件的状态下,你做了对应的操作,bug才会被触发。
  4.bug必须使用特殊的数据才会出现,测试人员没有意识到她使用的数据的特殊性。一种比较难搞的情况是:同一组输入,在不同情况下(不是不同的业务情况)输入会被转化成不同的数据。我曾经见到过这么个例子,程序员用系统当前时间作为随机数的种子来生成id,但是id设置的比较短,一个存储的操作使用这个id,在一些情况下,发生了冲突,当时做功能测试这种小概率事件耗费了测试人员大量时间也没有稳定重现,还是在性能测试的阶段测试了出来。
  5.测试人员由于错误操作,出现了误报(这很常见)。比如,记得自己执行了step3,其实没有,或者没有正确执行step却觉得正确执行了。
  怎样对付这样的bug呢?
  我喜欢James Bach 说的那句话:测试就像CSI。CSI是Criminal Scene Investigation 的缩写,也是我非常喜欢的美国系列剧。
  从我来看CSI的精髓在于:仔细观察,详细记录,科学分析,严密推理,有序求证,大胆假设,持续不懈,团队协作和一点儿运气。找bug其实和CSI探员做犯罪现场调查没什么太大区别。得知道,你工作的重要性一点儿不亚于CSI探员。
  仔细观察:第一件事情就是要观察,观察你所做的一切操作和一切相关的系统反馈。在一开始,观察的重要性要远远大于思考,通过观察你获得蛛丝马迹,这些蛛丝马迹是你进行思考和假设的关键输入。例如,我在一次测试的过程中,发现做某种操作的时候会相当慢,极少数情况下还报错过一两次,当询问了开发人员后得知这个操作的后台实现步骤是:先查看数据是否在缓存中,如果不在,则从远端服务器请求数据。我抓住少数情况下会报错的这一现象,仔细观察它的出错信息后猜测报错并不是因为网络连接不稳定引起的,而是由于远端服务接口实现有问题引起的,后来重新设计了测试用例,果然找到了问题所在。如果不仔细观察出错信息,就会听信开发人员认为这是网络不稳定引发的正常issue而错过这个bug。
详细记录:详细记录你的操作步骤及返回结果非常有助于回朔问题,也有助于后续分析。准备一个word文档,和截图工具有时候非常必要。另外,在观察的时候,你不仅要注意被测物的最终返回,还需要观察过程中的一些中间状态,往往这些中间状态提供的信息才是解开问题的关键。这些中间状态一般会被记录在log文件中,因此知道你的被测物是如何记log的,log被记录在哪里非常重要。log给了你另外一个看系统的角度。log是有级别的,如果级别可以动态调整,在找比较难找的bug时,可以将log记录的级别调至最低(DEBUG级)让它们记录更多内容。利用系统的错误转储文件(比如linux的core dump文件,windows下也有相应的记录转储文件的方式)分析也是个不错的办法(需要较高技术能力),但一般建议测试人员把这些转储文件交给更专业的开发人员来分析。在我短暂的C++开发岁月中,有使用过GDB阅读转储文件的经历,那绝对不是愉快的回忆。你瞧,测试人员的主要工作是找出可重现的bug,并不是定位它们,不是么?
  除了log,如果能有监控信息,也要查看他们。比如系统提供的监控平台,监控日志;应用自己的监控平台、监控日志(如果有的话);采用一些外部技术手段截取一些中间状态信息,如使用sniffer抓取通讯包,使用Fiddler截获HTTP报文内容;给运行程序插桩来查看内存,堆栈,线程,函数被调用情况等情况,如Jprofile,gpertool等等。
  科学分析:对于黑盒测试人员来说,科学分析意味着你需要有一定的分析策略。我们需要采取一些形式化的方法来完成我们的分析。基于我的统计,缺陷难以重现有很大一部分原因是因为“没有找到真正引发bug的操作序列“。测试人员不可能像开发人员那样去跟入到代码内部,设置断点调试程序,他们主要的测试方式是直接来操纵被测物,并从外部观察被测物状态的改变。显而易见,“状态转换图分析法”是测试人员对付“难以重现bug”的最强有力武器之一。状态转化图能够帮助测试人员很好的选择操作路径,并且知道这么做有什么意义。“状态图转化法”绝对是测试人员值得花时间学习和研究的一种方法,你可以走的很深,也可以研究得很远(可以从MBT的方向进行拓展),限于篇幅,这里就不展开了。在这里推荐《探索吧!深入理解探索式软件测试》这本书,它的第八章对“状态转换”做了非常实用的描述。
  上文分析的让bug难于重现的另一种原因是没有找到“真正引发bug的特殊数据”。我的常用做法是这样的:1.画出系统交互图(要真正弄清系统的边界,这很重要),并识别出每种交互会有什么样的输入、输出数据和中间数据,识别出这些数据的规约和格式,这样你就不会对数据有遗漏。2.考虑数据的等价类、边界值,对这些输入进行组合,分析数据之间是否有耦合关系,如果有耦合关系,弄明白关系是什么,设计违背这些关系的用例,最后采用组合测试工具初步生成测试集,再人工选取最可能出问题的数据集(直觉有时候非常管用)。
  严密推理:天马行空对测试人员很重要,但是当你试图重现一个bug的时候,这并不是一个非常好的方法。抓住了蛛丝马迹,你就要推理是为什么产生了这种蛛丝马迹。限于工作性质,测试人员更多的会从:业务完整性、数据完整性、业务正确性、数据正确性等方面考虑问题。但是,如果测试人员对被测物的IT架构有比较深入了解的话,推理的范围会扩大到技术实现层面,如:多线程可能引发的问题,网络引发的问题,excepiton处理不当引发的问题,全局事务设计不当引发的问题,内存泄漏引发的问题,数据库表设计不合规引发的问题等等等等,这些会让你的分析推理能力如虎添翼。当然,如果限于条件,测试人员不具备这类能力,则应该在适当的时候请求开发人员协助。
  有序求证:这里只有一点需要注意。那就是,在求证的过程中不要打散弹枪,按照你的推理一步一步的来,一个个推理的来验证,一次只引入一处修改。这样才能让你的捕虫网编制的足够细密。
  大胆假设:有的时候,看似八竿子打不着的东西竟然存在着千丝万缕的联系,而你获取信息的过程总是一个由少及多的过程,一开始这些联系是无法被识别出来的。通过推理,逐步验证,你慢慢的识别出了大部分内在联系。但有时候这种逐步推进的工作也会有局限性,工作如果出现了瓶颈(你试遍了你所有的假设,都没有重现bug),这时候就需要发挥一点儿想象力了,天马行空这时候从一定程度上又变得有用起来,当然天马行空也不是无厘头,还得靠我们所谓的“灵光一闪”,这号称是潜意识在帮助你。CSI的剧情中不也总是出现这种柳暗花明的桥段么?
  坚持不懈:话不多说,有的时候你差的就是那么一点儿点儿耐心。
  团队协作:很多情况下,重现bug不是一个人能搞定的。我们需要测试环境ready,测试数据ready,各种监控、分析工具ready,各种不同的视角开拓思路、加深对被测试物的认识。这是team work!!!独行侠有时候很管用,但是终究有极限。这就是为什么CSI是一票人在做而不是一两个人在做。
  一点儿运气:说实在的,有的时候重现bug就是靠运气,你不得不承认这一点。事实上很多美好的事情发生都得依靠运气,比如中彩票。要记住的一点是,运气是建立在你不懈努力的基础上的。如果你一张彩票不买,你肯定什么也中不了。但如果你坚持买上几年,中个五块十块甚至二百也不是梦。
  Let it go:全试过了,连运气都没有。你只能放手,回到最上面我说的那两条了:找开发来帮忙,或者给开发报issue。btw,即使不能重现bug,也应该给开发人员提供更多信息:如log、dump文件、监控记录、屏幕截图等。做一个负责人的测试人员,把烦恼真实的留给下家,这很重要:)

posted @ 2014-09-26 11:28 顺其自然EVO 阅读(1040) | 评论 (0)编辑 收藏

让我们区分质量保证与测试

 概念与思辨深度
  一个行业的发展似乎总伴随着更多的概念被塑造出来。拿测试来说,我们有单元测试、集成测试、系统测试、回归测试、冒烟测试,等等。我们缘何塑造如此多的概念来“为难”自己呢?答案可以用我从@李智勇SZ老师那学到的“概念越纯粹表示思辨深度越深”这句话加以解释,而这一切又为了提高同行间的沟通效率。需要特别指出的是,多个相似但不同的概念想表达的是各自的不同之处,而非共同之处。为此,如果人家在讨论单元测试时,你冒出一句“写好程序,编译完,跑一跑,看看写得对不对,这就是最简单的UT啊!”就不大合适,因为这说明你根本没有理解单元测试的概念(可以读一下我写的《明晰单元测试》一文)。如果你再加上一句“靠,都是测试,分那么清干什么?”,那还表明你逻辑不清。
  我近期所写的《对软件测试团队“核心价值”的思考》一文引发了一些讨论。比如,@朱少民老师(后面简称朱老师)指出:“‘(文中所述测试)帮助开发人员提高其开发质量和效率’是软件测试团队的价值取向之一,但还不是软件测试团队的主要核心价值“。于是我向朱老师请教他所理解的测试核心价值,得到的回复是“软件测试最核心的价值还是能够快速发现问题以提供产品的质量反馈,有能力提供准确的、客观的、完整的质量评估,并通过缺陷分析、用户行为分析等,确定缺陷模式和开发人员不良行为、习惯等,帮助开发人员预防缺陷(从设计到编程、单元测试,不仅仅是设计)”。
  之后我的回复是,“我们应将QA(Quality Assurance,质量保证)与测试区分开来”,因为我认为朱老师将测试的范围定义得太大了。但朱老师却帮我指出“我这是地地道道的测试,看来你对QA理解不够。QA的主要对象是(包括开发、测试)流程,QA人员评审、审计和改进流程,以保证质量。测试的对象是产品,包括阶段性半成品。从严格意义看,测试就是对软件产品的质量评估”。
  类似与QA和测试相关的讨论发生在@左耳朵耗子老师写了《我们需要专职的QA吗?》一文之后。这些讨论又为我们带来了@程序员邹欣老师写的《测试QA的角色和分工》,以及@段念-段文韬老师写的《对《我们需要专职QA吗?》的回应》。在本文我想顺便谈一谈以前读这些文章的看法。
  谁对谁错?
  如果读过我所写的《软件开发:个人与团队是永远的核心》一文的话,知道我给出了高质高效软件开发的一个效能模型。从模型所涵盖的内容来看,其范围非常广,包括行为、能力和方法三大支柱。某种程度上,我们在软件行业的职场旅程有点象是“盲人摸象”(但我们能沟通),这个摸索的过程与我们从事的软件细分行业(如互联网、通讯、银行)、服务公司(如国企、外企、私企)、工种(如开发、测试)等都有着很直接的关系,所获得的一种成功经验很可能在另一种情形下根本行不通。摸索的过程很容易通过现实去理解书本上的东西,这不是坏事,但千万不要以为所“眼见的”就是“宇宙真理”,也千万别放弃自己的独立思考。
  存在争议并不是坏事,我们之所以争议,是因为我们有着不同的成长途径和思考深度(年龄起着一定的作用)。争议的焦点不是为了“你死我活”地相互“拉黑”,而应最大可能地达成共识和完善自我认识。所达成的共识越多就越是知道“象的模样”,这对所有的从业人员都有意义。正因如此,作为技术人,我时常会告诫自己“多放下一点自大与自尊去接受别人的想法,这对于自己来说是一种很好的成长途径。”而且,我对于自己所不熟悉的技术领域更多持敬畏而非否定态度。总的说来,谁对谁错并非争论的关键,而是我们有哪些想法其实是相通或相同的、如何摆事实讲逻辑地让对方了解自己的想法。我希望每一位读者都能理性对待所碰到的争议,这算是一个小小的呼吁吧。
  QA不包含测试
  我认为引起QA与测试相关的很多争议出现在我们没有明晰概念,或者有的概念太泛了容易导致问题。QA这个词就是一个例子!
  质量保证很容易让人想到与软件质量相关的方方面面,比如测试、流程、缺陷数据分析等。既然这样,开发工程师的水平是不是也影响着软件质量呢?那人员的招聘为什么不由QA部门管,而是由HR和开发部门管?这个问题问得是不是很无厘头?但这个问题也告诉我们,各种部门的职责定义其实并非由其名字表意所定,而是由公司根据组织架构的需要指派的。既然如此,我们在使用这些名词时,一定要根据职责加以展开,而不能依据名字意思本身,否则很容易因为不当言语而引发没有价值的争议。有些争议甚至影响到了他人的“饭碗”了,你叫人如何理性?这间接地指出,我们的言语应尽可能严谨。
  如果QA不是测试,那它是干什么的?老实说,我不敢凭空给一个角色定义职责,加上我并不是QA(与测试)方面的专家,在此只能以我曾经服务过的Motorola公司为例说一说我的大致理解。简单说来,Motorola的QA是一个与测试部门完全独立的部门,她关注二大事务,一是缺陷数据分析与缺陷预防,二是流程规范与改善。QA会根据测试与开发两大部门所产生的缺陷数据进行数据分析(或叫数据挖掘吧),发现各产品的缺陷模型(常犯错误、缺陷数趋势等),通过模型去预测可能潜在的遗留缺陷,以帮助开发部门进行改进(最终作用于流程)。另外,QA会全程参与软件开发活动以跟踪公司所制定流程的执行情况。比如,以前我就职的Motorola杭州研发中心通过了TL9000认证,QA必须确保开发活动完全符合TL9000的要求,以免出现资质复审时无法通过的状况。
  读者请注意,我以Motorola公司为例去定义QA的职责就一定对吗?未必!对于就职于一些测试隶属于QA部门的同仁可能很难接受以上的定义。在这种情况下,我们需要思考的是,这个定义是否有助于我们更方便地沟通?如果定义有助于我们的沟通,则这种定义就是可取的,否则值得商榷。理性思考不能忘!
 我们需要QA吗?
  如果问“我们需要测试吗?”答案很清楚,不是吗?那公司是依据什么决定是否需要一个工种的?很简单,不同的技能!
  不少软件公司需要通过象CMMI、ISO9000系列、TL9000等这样的质量体系认证,并定期复审。这些质量体系主张“质量源于过程”,因此,一定需要有人为公司制定相应的开发流程并监督流程在公司的到位实施。流程驱动研发的质量意识是需要培养的,这就离不开象“Quality begins with me”这样的培训。缺陷数据通过挖掘能帮助发现其他有价值的东西,这就需要相应的数据建模与分析技能。
  不难认同,以上知识与相关技能不能由开发或测试团队的人去兼顾,因此我们需要独立的QA部门。
  QA部门的作用与重视程度在不同的行业完全不同。平均说来,互联网行业的产品因为对质量问题具有更高的容忍度(大多互联网产品直接上线,有问题可以直接回退),而非象通讯行业那样得交由象中国移动这样的运营商去运营,也不存在因质量事故引发的第三方惩罚性费用。另外,互联网产品的用户根本不关心产品开发过程是否遵循CMMI等质量体系,这与通讯行业运营商对之可能有要求完全不同。我在《离开通讯业入职互联网圈的一些感悟》一文中进一步谈到了两个行业的不同。
  至此,我希望读者接受我将QA与测试两个概念区分开的建议。
  一点重申
  无论使用何种天花乱缀的技法和理论,探寻测试团队核心价值时一定要打破测试与开发团队之间的心理博弈防线,否则没有成功的可能。以我长期在开发一线的经历,测试的价值困惑首先源于缺乏开发工程师对之的认可,这是种心理感受问题,不是技术问题。《对软件测试团队“核心价值”的思考》虽没有直接给出核心价值的定义,但给出了探索方向,希望值得我们共同思考。
  测试工程师思考从开发工程师的“痛点”寻找突破口,或许能找到出路。当然,要真从开发的“痛点”下手,测试团队必须有些“刷子”,否则只能游离在质量与效率的边缘。
  对朱老师所言的回复
  朱老师:软件测试最核心的价值还是能够快速发现问题以提供产品的质量反馈,有能力提供准确的、客观的、完整的质量评估,并通过缺陷分析、用户行为分析等,确定缺陷模式和开发人员不良行为、习惯等,帮助开发人员预防缺陷(从设计到编程、单元测试,不仅仅是设计)。
  回复:这个定义存在将测试与QA混为一谈的问题。如果我是一名测试工程师,看到这样的定义真的会吓一跳,要求太高了。我认为质量度量很容易出现主观现象,难以做到“1+1=2”这样的真实。软件质量度量的目的不是为了“真实”了解软件的质量状况,因为团队级的质量无法直接度量,度量的目的是为了帮助开发团队找到改善点。软件质量管理应重实践、轻量化,以帮助工程师改善工作习惯和提升开发环境的效率为目标。我欣赏朱老师身兼QA与测试双重身份,但就测试核心价值的探讨上,我希望能采纳所提出的将QA与测试分开的建议。概念只有清晰了、轻量了,才不容易引起歧义,也更利于我们达成更多的共识和提高沟通效率。
  朱老师:我这是地地道道的测试,看来你对QA理解不够。QA的主要对象是(包括开发、测试)流程,QA人员评审、审计和改进流程,以保证质量。测试的对象是产品,包括阶段性半成品。从严格意义看,测试就是对软件产品的质量评估。
  回复:第一话既讲测试又讲QA,很容易引起误解。第二句与第三句的观点我认同。对于第四句,我的问题是“测试真能评估软件质量吗?”
  对《我们需要专职的QA吗?》相关文章的看法
  《我们需要专职的QA吗?》这篇文章的论点是QA,但内容其实谈的是测试,文不对题引发没有必要的争议属于情理之中。该文中还是有很多值得我们思考的观点,其中不足之处后面两篇文章对之加以反驳了。
  《测试QA的角色和分工》一文同样存在将QA与测试混在一起讨论的问题,但其中还是能看出QA与测试的痕迹。比如,其中谈到了认证。其对于分工的论述我很欣赏,也阐述了为什么需要专职测试人员。
  《对《我们需要专职QA吗?》的回应》一文明确区别了QA和测试,且只关注于测试的讨论。我与段老师有很多共识,虽没有听过他的演讲,但看过他一些分享主题的PPT,能从开发人员的角度找到共鸣点。注意文中的最后一句话,“测试和开发之间有更多配合,更多相亲相爱,把测试当成提高和推动质量的手段,不正应该是测试的方向吗?”

posted @ 2014-09-26 11:27 顺其自然EVO 阅读(130) | 评论 (0)编辑 收藏

QTP不识别树结构中的点击事件

 QTP不识别树结构中的点击事件,未生成该点击事件的脚本,解决办法:
  1、未生成点击"auto分类c1"的脚本
  2、点击1、对象库-2、添加对象库-3、选中对象-点击OK,即将该对象加到对象库中。
  3、脚本中添加该对象的点击事件
  Browser("通用呼叫中心后台").Page("通用呼叫中心后台_2").Frame("iframe_main").WebElement("auto分类c1").Click
  4、回访成功

posted @ 2014-09-26 10:11 顺其自然EVO 阅读(169) | 评论 (0)编辑 收藏

Jmeter在命令行运行技巧

  For non-interactive testing, you may choose to run JMeter without the GUI. To do so, use the following command options
  -n This specifies JMeter is to run in non-gui mode
  -t [name of JMX file that contains the Test Plan].
  -l [name of JTL file to log sample results to].
  -r Run all remote servers specified in JMeter.properties (or remote servers specified on command line by overriding properties)
  The script also lets you specify the optional firewall/proxy server information:
  -H [proxy server hostname or ip address]
  -P [proxy server port]
  Example : JMeter -n -t my_test.jmx -l log.jtl -H my.proxy.server -P 8000
  -n 该参数表示Jmeter运行在非图形化模式下(即命令行模式)。
  -t 保存有测试用例的JMX文件
  -l 保存样本结果的JTL文件
  -r 运行所有在JMeter.properties 中定义的远程服务(或者通过命令行覆盖配置文件中定义的远程服务)。脚本还允许您指定可选的防火墙/代理服务器信息:
  -H 代理服务器主机名或者IP地址
  -P 代理服务器的端口号
  上面这段说明来自 JMeter 的官方用户手册。其中提到了使用命令行方式运行 JMeter 脚本的方法。只有几个简单的参数,很直观,用起来也很方便。好处是可以节省一些系统资源。
  今天尝试 300 个虚拟用户连续运行 5 分钟时——使用 GUI 方式,发现开始运行后不久 UI 就失去了响应,并提示一个有关  AWT 的错误,最终只能把 Java 进程结束掉。但是使用命令行方式时却很稳定。
  不过当在命令行方式下尝试 500 个虚拟用户连续运行 5 分钟时,JMeter 抛出了一个 Out of Memory 的异常并退出了进程。
  Note:
  1.执行命令前要检查当前目录是否是 %JMeter_Home%\bin 目录;
  2.如果 JMeter 脚本不在当前目录,需要指定完整的路径;如果要把执行的结果保存在其他地方也要指定完整的路径。

posted @ 2014-09-26 10:11 顺其自然EVO 阅读(2689) | 评论 (0)编辑 收藏

使用SoapUI测试Web Service

 如何测试写好的Webservice?你当然可以写代码来测试,但还是太麻烦,你得花时间去学习各语言的关于Webservice调用的相关API。这里推荐一个Webservice开发的必备工具- SoapUI,无须了解底层细节,就能快速测试你的Webservice开发的是否正确。
  SoapUI是一个开源测试工具,通过Soap/HTTP来检查、调用、实现Web Service的功能,而且还能对Webservice做性能方面的测试。
  SoapUI下载地址:http://sourceforge.net/projects/soapui/files/
  (SoapUI也有收费的Pro版本,对于一般的开发人员来说,如果只是调试下,开源的免费版就足够用了)
  Demo
  首先新建一个SoapUI Project,在Initial WSDL/WADL中输入wsdl的地址
  Project建立好后,SoapUI会根据WSDL的格式生成左边的列表树,包括CUX_0_WS_SERVER_PRG_Binding为WSDL Binding,INVOKEFMSWS为Binding中的Operation。双击Request1就能看到Soap请求报文的内容。
  在请求报文中填写必要的请求信息,并在左下角的Request Properies中输入用户名,密码及WSS-Pasword Type,再点击绿色的运行按钮,就能在右侧生成Soap响应报文。
  只是对SoapUI 做了简单的介绍,主要用其来查看web service提供的接口,以及返回的结果,SoapUI的功能远不止这些,其可以对web service进行功能上和性能上的测试。

posted @ 2014-09-26 10:11 顺其自然EVO 阅读(483) | 评论 (0)编辑 收藏

解析软件测试需要变革的因素

世易时移,现今的科技发展一日千里,软件测试这门科学也到了该进行革命的时候了,“这是变革者的路!。”Bhumika Mehta的这篇文章很好的诠释了为什么软件测试需要变革以及如何进行变革。他认为,软件测试需要的就是想法与创意。没有想法的测试人员可能在测试这条路上不会走得太远。
  用户变得更有想法:
  集万千宠爱于一身的用户与客户有了更多的选择空间。破除商业薄弱环节的竞赛在激烈地进行着,企业者们煞费苦心地去想争夺市场和讨好用户,时间、成本、产品本身都是孕育商业里程碑的重要营养元素。
  对于用户和客户来说,你的产品是否足够完美,是否兼具美学观感,是否值得信赖都是他们目前所关心和关注的。此外,客户对自己提出的要求更为明确更为苛刻,不再是含糊不清亦或语焉不详而将就附和。
  在这种情况下,传统的软件测试方法亟需改革创新以满足用户思维和观念上的转变需求。
  我们不妨先问问自己几个问题:
  我们做需求分析时是否到了无从入手的境地?
  我们是否很难再给自己或团队写出简明扼要的说明文档?
  我们是否很难再在沟通技能上有所加强?
  我们是否很难再在报表研究和分析上有所进步?
  如果答案是肯定的,我们还在等待什么?现在就该即刻动身去计划,去执行,去改变,去观察,去记录。
  技术每天都在转变:
  当初桌面系统横行的时候,移动端的软件应用还只是襁褓里的娃娃。时过境迁,如今人手一机,特别是智能手机,成了地铁、公交上独特的咏叹调。移动端的软件测试完全有别于传统的测试范畴,我们必须适应这种转变。
  应该尝试的事情:
  我们需要考虑更多的应用场景;
  我们需要更多观察人们是如何使用移动设备的;
  我们需要更了解清楚产品或应用的真正意图。
  工具常有,但鲁班不常有:
  自动化的需求日渐增长,成为衡量软件测试员优劣与否的标尺。但实际上并非想象的那么美好。任何工具都不能替代人的意志。好的工具固然能事半功倍,但是若没有其背后人的想法和努力,再好的工具也只是花瓶。没有工具可以完全脱离人而独立工作,至少目前仍然如此。
  市场上过百款的新工具和套件可供选择,但时间对于测试环节依旧弥足珍贵,所以自动化是个必然选择,但必须与人和谐共处,通力合作。
  应该尝试的事情:
  每天都学习一定的新事物并付诸实践;
  就当前应用或产品想出另外5种的测试方法;
  对工具运用进行更深入细致的研究直至找出最合适最优化的选择或组合;
  对产品或应用开展更紧密的监察以及就错误之处作出更深入的调查分析。
  有多少人会认同——若减免考试压力,会使我们学得更多走得更远?或许多年后再回首,纯粹的应试学习换来的只是冰冷冷的通过与不通过,对实际工作或职业的帮助实在。我不是对认证考试有个人偏见,但其不能成为衡量技术高低的全部。受时间所限,考试中并不能完全反映个人的真正实力。放之于软件测试,时间意味着成长。
  你或许不能每天都提出上百个新点子;
  你或许不能在数小时内就掌握一个自动化工具;
  你或许不能在测试的第一周就发现多于100处的差错;
  你或许不能刚入职场马上就能与他人进行良好有效的沟通。
  但不论高低,成长是个必然之物。随着阅历的沉淀与经验的累积,我们的技术和为人处事会相应增加了厚度。过去所犯的种种差错都应该好好反省与保持警惕,避免重滔覆辙,重复犯错,这会使我们少走不少弯路。
  生于忧患:
  开发主管或经理或许可以从基层代码工作中抽离,但对于测试经理来说却应该始终工作在第一线。当我们想忘却基本技能时,我们同时也会被职业生涯所忘却。即使拥有再丰富的测试经验,我们都应该一如既往地做好测试的本职工作。
应该尝试的事情:
  测试真正的产品;
  提出让产品更好用的建议;
  学习研究市场上那些销售得最好或没有销路的产品;
  想明白如何让想法与实际更好地融合。
  写在最后:
  无论本文怎么论述,软件测试需要的就是想法与创意。没有想法的测试人员可能在测试这条路上不会走得太远。所以要学会思考。研究那些与自己有关的真正的产品,换位思考如果这是你的产品,你会怎么做,你会如何测试。同时,要把沟通与报表分析技能武装好。一个不懂沟通与阅读报表数据的测试人员,同样会走得比别人艰辛。

posted @ 2014-09-26 10:10 顺其自然EVO 阅读(158) | 评论 (0)编辑 收藏

安装BugFree 3.0.2时出现的问题

今天在公司机器上安装了BugFree 3.0.2,就安装过程中出现的问题记录如下,以备将来查阅。
  问题1:xampp中的Apache不能启动,而且80端口也没有被占用。
  原因和解决:XAMPP Control Panel提示visual svn server占用了443端口。点击Apache后的Config按钮,将Apache(httpd-ssl.conf中的Listen 443改为其它值就好了,比如433)。
  问题2:在第一步环境检查页面时,显示xampp/htdocs/BugFile目录读写失败。
  解决办法: 在xampp/htdocs/下新建一个BugFile文件夹就好了!
  问题3:在第二步配置页面时,不知道数据库用户名和密码应该输入什么。写错了会报错:Access denied for user '****'@'*****' (using password: YES)
  解决:用户名默认输入:root,密码为空。
  问题4:添加用户时,用户名中不可包含大写字母。否则在登录的时候总是提示“用户名不存在”
  问题5:添加的用户在登录时提示“无产品访问权限”
  解决:用户要至少有一个可以访问的产品。如果是刚装的bugfree,还没有用户组和产品的话。先在用户组管理页面添加一个用户组,比如GroupA,将这个用户加入这个用户组,在产品管理页面添加一个产品,指定这个产品的用户组为GroupA。这样这个用户就可以登录了。
  最后记得在xampp control panel中将Apache和MySql前面对应的svc勾上,这样每次开机他们就会作为服务自动启动了。

posted @ 2014-09-26 10:10 顺其自然EVO 阅读(202) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 40 41 42 43 44 45 46 47 48 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜