51Testing软件测试培训单元测试最佳实践(JAVA)Copyright©2011第一部分:理解面向对象1.面向对象概述无论是单元测试还是集成测试,均要求测试开发人员具备一定的编码能力。而编码能力除了基本的三种程序结构(顺序结构,分支结构,循环结构)以外,最重要的知识莫过于程序设计中的面向对象相关的原理和基本概念。而对于JAVA这一纯面向对象的编程语言而言,其语言核心就是面向对象,如果不能很好地掌握面向对象,将很难理解代码级的自动化测试。那么何为面向对象呢?要理解面向对象,我们先来看看与面向对象相对应的另外一种程序设计方法:面向过程。面向过程的编程的基本构成便是“过程”,过程实现的方式就是“函数”,我们通过不同函数来实现不同的功能,并按照程序的执行顺序调用相应的函数,组成一个完整的可以运行的应用程序。我们可以通过把不同的功能在不同的函数中实现或者给函数传递不同的参数来实现不同的功能,这是面向过程中模块化设计的原理。但是面向过程有很多问题,当我们总是按照教科书上的小例子来学习程序设计时是永远也体会不到面向过程中存在的这些问题的,反而会觉得面向过程更简单,更容易理解。而事实是当我们设计一些大型的应用的时候将会发现使用面向过程编程是多么的痛苦和无奈,代码极难维护,我们不得不为相似功能设计不同的函数,天长日久,代码量越来越大,函数越来越多,而重复的代码越来越多,噩梦就此产生。于是产生了另外一种程序设计思想:面向对象,从此程序员发现编程是多么快乐的一件事情。我们可以把现实世界的很多哲学思想或者模型应用于编程,这是计算机的一次伟大的革命。那么究竟何为面向对象?要理解这两个重要的字“对象“,我们首先需要理解一下类和实例:何为类?类就是“一类东西”,比如“门”是一类东西,“防盗门”,“汽车门”也是一类东西。何为实例?实例就是明确告知哪一类东西的哪一个,比如“小明家的入户门”,或者“车牌为A12345的汽车左前门”就属于一个实例。何为对象?在面向对象的程序设计中,“一切皆对象”(对面向对象理解得有多深取决于对这句话的理解有多深)。一个类是一个对象,一个实例是一个对象,一个变量也是一个对象,甚至一个数据类型,也都可以视为一个对象。对象有什么特性?对象不同于过程的最基本的特质有两点:1)对象有方法,比如门可以“开”,可以“关”,可以“锁”,这些属于方法。51Testing软件测试培训单元测试最佳实践(JAVA)Copyright©2011)对象有属性,比如门有“宽度”,“高度”,“厚度”,“重量”等,这些属于属性。对于属性,这在面向过程中是没有相关概念与之对应的,而对于方法,方法本身来说就是一段处理程序,方法与面向过程的函数其实是类似的(方法和函数都由一段代码组成,可以包括参数,可以有返回值或没有返回值),它们之间唯一的区别在于函数是不存在公有私有一说的,而方法却有类型修饰符(public,private,protected等),这种类型修饰符直接决定了该方法能不能被别的子对象使用。何为子对象呢?这里牵涉着面向对象另一个非常重要的特性:继承。简单理解继承就是“子承父业”,与生物学上的继承,遗传的概念没有区别。就拿人类来说,父亲有的方法(如走,跑,跳,吃,睡等)同样儿子也可以有,儿子还可以自创一个自己的方法(如射击,冲浪,骑车)。现实生活中还有一个很有趣的现象是:父亲是儿子的父亲,同样父亲也是爷爷的儿子,所以父亲这个对象它有时候也是儿子,那么还有可能是丈夫。。。。。。,这表示一个对象可以有多种形态,这就是“多态”。关于面向对象的基本概念再次总结如下:1)一切皆对象2)类表示一类事物3)实例表明类的真实存在4)对象有方法和属性5)对象可以被继承6)对象可以有多种形态2.类与实例在开始学习面向对象特性及如何使用Java代码实现前,读者需要首先在RFT开发环境中建立一个开发和运行纯Java代码的环境,请按如下步骤进行:1)在RFTLearn项目根目录中新建目录code。2)切换透视图到Java,并打开视图Navigator。3)确认菜单ProjectBuildAutomatically被勾上,这样可以自动编译Java代码。4)右键点击code,选择NewClass,在Name中输入Door作为类名,其它保持默认即可。现在我们已经将RFT切换到一个纯Java开发环境,用于学习面向对象特性及实现,类的本质就是一类事物,我们使用“门”来作为我们的类,门有哪些方法呢?“开”和“关”,门有哪些属性呢?“高”和“宽”,好,那么我们现在就来定义这样的一个类:packagecode;publicclassDoor{//定义属性height为私有变量类型,仅在Door类中可调用privateintheight;//定义属性width为公用变量类型,可在Door的实例中调用publicintwidth;51Testing软件测试培训单元测试最佳实践(JAVA)Copyright©2011定义方法openDoorpublicvoidopenDoor(){System.out.println(Doorisopen...);}//定义方法closeDoorpublicvoidcloseDoor(){System.out.println(Doorisclose...);}//经典的setter和getter方法publicvoidsetHeight(intheight){//本处this.height引用类的私有变量height,等号后的height为参数this.height=height;}publicintgetHeight(){//getter方法,用于返回值returnthis.height;}}光有门这个类还不行,类只是一类事物的统称,“门”这类事物并不能真正实现“开”和“关”的动作,只有具体的“门”才能实现“开”和“关”的动作,才有真实的“高”和“宽”的属性,所以我们需要将这个类实例化,“实例”就是一个看得见摸得着的“门”,比如我家的“门”。现在我们就用我家的“门”来实例化刚才定义的“门”这个类:packagecode;publicclassMyDoor{publicstaticvoidmain(String[]args){DoormyDoor=newDoor();myDoor.openDoor();myDoor.closeDoor();myDoor.setHeight(1000);System.out.println(Heightis:+myDoor.getHeight());//由于在类Door中将width定义为公用变量,所以可在此直接调用该变量//下面两句代码其实实现了跟setHeight()和getHeight()相同的功能myDoor.width=500;System.out.println(Widthis:+myDoor.width);51Testing软件测试培训单元测试最佳实践(JAVA)Copyright©2011}}MyDoor这个类实现了方法main,所以可以直接运行,点击工具栏上的运行按钮运行MyDoor这个类,输出如下结果:Doorisopen...Doorisclose...Heightis:1000Widthis:5003.继承继承中有4个概念是需要理解的:父类,子类,重写,扩展。先简单介绍一下这几个概念:1)父类:用来被子类继承的称作父类,或叫超类,比如在此我们把“门”定义成一个父类2)子类:继承父类的类称作子类,在此我们可以把“防盗门”定义成一个子类3)重写:父类“门”有一个方法叫做openDoor(),而由于“防盗门”打开的方式不一样,我们需要在子类中重新实现openDoor()这个方法,此时子类中的openDoor()便重写了父类中的openDoor()。4)扩展:父类“门”只有openDoor()和closeDoor()两个方法,而对于“防盗门”这个子类,还存在一个方法叫做“锁”,此时子类“防盗门”便可以新增一个方法lockDoor(),这就是“扩展”。与上节一样,我们仍然使用Door这个类来作为父类,里面不做任何修改。接着我们创建一个子类叫SafeDoor,里面什么都不做,只做一下继承,代码如下(注意关键字extends用于继承):packagecode;publicclassSafeDoorextendsDoor{//此类不做任何实现,只继承自Door}在这种情况下,实例化SafeDoor这个类,此类将会拥有所有Door类中的作用域为public和protected的方法和属性(特别注意一下private修饰的方法和属性将不能被继承),现在我们实例化SafeDoor并调用相应的方法:packagecode;publicclassMyDoor{51Testing软件测试培训单元测试最佳实践(JAVA)Copyright©2011(String[]args){SafeDoorsafeDoor=newSafeDoor();safeDoor.openDoor();safeDoor.closeDoor();safeDoor.setHeight(1000);System.out.println(Heightis:+safeDoor.getHeight());safeDoor.width=500;System.out.println(Widthis:+safeDoor.width);}}运行,输出结果为:Doorisopen…Doorisclose…Heightis:1000Widthis:500我们可以看到,虽然SafeDoor类中什么也没有,但是所有Door类中的方法和属性均可用于SafeDoor这个类的实例,这便是继承的强大之处,通过这样的方式我们便可很容易地实现重用。最后,我们为SafeDoor这个类添加一个新的方法扩展其功能,方法名为lockDoor():packagecode;publicclassSafeDoorextendsDoor{//此类不做任何实现,只继承自DoorpublicvoidlockDoor(){System.out.println(Doorislocked...);}}这个新的方法便是一个扩展,这样SafeDoor不仅可以使用Door的方法,也可以扩展自己的方法和属性,使面向对象这种程序设计思想轻易实现重用性和扩展性。4.接口何为接口?既然是面向对象,所有的概念都是从对象中来,对象又从何而来?从真实世界中来,接口也不例外,我们对接口的理解只需要两个字即可概括:规格。51Testing软件测试培训单元测试最佳实践(JAVA)Copyright©2011举个简单的例子,大家应该都有过攒机的经历,那么我们是否考虑过一个问题:为什么各个厂家的零部件居然可以安装在一起工作呢?答案当然谁都知道,因为我们对每一个零部件都定义了规格,内存条的插脚必须满足规格才能刚好与主板上的插槽相吻合,哪怕是一根网线,也必须满足RJ45的规格,才能刚好插到网卡的插口中,一旦特立独行,将没有市场,同样的,大家可以想像,如果世界上没有规格,将会变得乱七八糟。就像现在的操作系统一样,没有一个统一的规格,特别是嵌入式操作系统,更是五花八门,带来的最大的问题就是一款软件需要开发N多的不同平台下的版本,于是乎如果你能开发出一个号称可以跨平台的软件的话,那么将备受欢迎。这只是没有办法的办法,如果在N多年前,当刚有操作系统的时候就能把操作系统的统一规格定义,