资源预览内容
第1页 / 共49页
第2页 / 共49页
第3页 / 共49页
第4页 / 共49页
第5页 / 共49页
第6页 / 共49页
第7页 / 共49页
第8页 / 共49页
第9页 / 共49页
第10页 / 共49页
亲,该文档总共49页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
第10章 面向对象的软件测试基础罗 东 俊ZSUJONE126.COM1主要内容10.1从测试视角看待面向对象 10.2面向对象测试的层次 10.3面向对象测试模型 10.4面向对象测试部分的例子210.1从测试视角看待面向对象10.1.1测试面向对象软件的不同 10.1.2测试视角 10.1.3从测试视角的角度看待面向对象的概念 310.1.1测试面向对象软件的不同 从编程语言看,面向对象编程特点对测试产生了影 响 封装把数据及对数据的操作封装在一起,限制了对象属性 对外的透明性和外界对它的操作权限,在某种程度上避免 了对数据的非法操作,有效防止了故障的扩散;但同时, 封装机制也给测试数据的生成、测试路径的选取以及测试 结构的分析带来了困难。 继承实现了共享父类中定义的数据和操作,同时也可以定 义新的特征,子类是在新的环境中存在,所以父类的正确 性不能保证子类的正确性,继承使代码的重用率得到了提 高,但同时也使故障的传播几率增加 多态和动态绑定增加了系统运行中可能的执行路径,而且 给面向对象软件带来了严重的不确定性,给测试覆盖率的 活动带来新的困难。 4测试面向对象软件的不同 另一方面,面向对象的开发过程以及分析和 设计方法也对测试产生了影响 分析、设计和编码实现密切相关,分析模型可以 映射为设计模型,设计模型又可以映射为代码。 因此,分析阶段开始测试,提炼以后可用于设计 阶段,设计阶段的测试提炼后又可用于实现阶段 的测试。5例如 在传统的面向过程程序中,对于函数 y=Function(x),只需 考虑函数Function()本身的行为特点 在面向对象程序中,不得不同时考虑基类函数 Base:Function()的行为和继承类函数Derived:Function() 的行为。 通常,传统软件中存在的依赖关系有:变量间的数据依赖; 模块间的调用依赖;变量与其类型间的定义依赖;模块与其 变量间的功能依赖。 而在面向对象软件中,除了存在上述依赖关系外,还存在以 下的依赖关系:类与类间的依赖;类与操作间的依赖;类与 消息间的依赖;类与变量间的依赖;操作与变量间的依赖; 操作与消息间的依赖;操作与操作间的依赖。 6面向对象软件的测试内容 模型测试 类测试 交互测试 系统/子系统测试 发布/自我测试710.1.2 测试视角 测试人员必须以一种对软件的方方面面都提 出疑问的态度来思考软件,这种方法被称之 为测试视角。 测试视角包含以下几个方面: 质疑:想验证软件的质量。 客观:确保不能凭空想像。 彻底:确保不要遗漏重要的部分。 系统:检查是可再现的。810.1.3从测试视角的角度看待面向对 象的概念 对象 消息 接口 类 继承 多态 9对象 对象是指包含了一组属性以及对这些属性的 操作的封装体。 对象是软件开发期间测试的直接目标 在程序运行时,对象被创建、修改、访问或删除 ,而在运行期间,对象的行为是否符合它的规格 说明,该对象与和它相关的对象能否协同工作, 这两方面都是面向对象软件测试所关注的焦点。 10从测试视角的角度关于对象的观点 对象的封装:封装使得已定义的对象容易识别,在 系统中容易传递,也容易操纵。 对象隐藏了信息:这使得对象信息的改变有时很难 观察到,也加大了检查测试结果的难度。 对象的状态:对象在生命期中总是处于某个状态的 ,对象状态的多变可能会导致不正常的行为。 对象的生命周期:在对象生命周期的不同阶段,要 从各个方面检测对象的状态是否符合其生命周期。 例如过早地创建一个对象或过早地删除一个对象, 都是造成软件故障的原因。 11消息 执行对象某个操作的一种请求。包含操作的名称、实参,当 然接收者也可返回值给发送者。例:ss.add(5,6) 从测试视角的角度,关于消息的观点; 消息有发送者:发送者决定何时发送消息,并且可能做出 错误的决定; 消息有接收者:接收者可能接收到非预期的特定消息,可 能会做出不正确反应。 消息可能包含实参:参数能被接收者使用或修改,若传递 的参数是对象,则对象在消息处理前和处理后,对象必须 处于正确的状态,而且必须实现接收者所期望的接口。12接口 接口是行为声明的集合。 从测试视角的角度,关于接口的观点: 接口封装了操作的说明,如果接口包含的行为和 类的行为不相符,那么对这一接口的说明就不是 令人满意的。 接口不是孤立的,与其它的接口和类有一定的关 系,一个接口可以指定一个行为的参数类型,使 得实现该接口的类可被当作一个参数传递。13类 类是具有相同属性和相同行为的对象的集合 。 类从规范和实现两个方面来描述对象。 在类规范中,定义了类的每个对象能做什么; 在类实现中,定义了类的每个对象如何做它们能 做的事情。14类规范 类规范包括对每个操作的语义说明,包括前 置条件、后置条件和不变量 前置条件是当操作执行之前应该满足的条件 后置条件是当操作执行结束之后必须保持的条件 不变量描述了在对象的生命周期中必须保持的条 件15发送者和接收者之间接口的定义 当对一个操作进行说明时,可以使用保护性 方法或约束性方法来定义发送者和接收者之 间的接口。 约束性方法强调前置条件也包含简单的后置条件 ,发送者必须保证前置条件得到满足,接收者就 会响应在后置条件或类不变量中描述的请求。 保护性方法强调的则是后置条件,请求的结果状 态通常由一些返回值指示,返回值和每一个可能 的结果联系在一起。16从测试视角的角度关于类规范的观点 从测试视角的角度,约束性方法简化了类的 测试,但使得交互测试更加复杂,因为必须 保证任何发送者都能满足前置条件。 保护性方法使得类的测试复杂了(发送者必须 知道所有可能的结果),交互测试也更复杂(必 须保证产生了所有可能的输出,并且发送者 能够获得这些输出)。 17类的实现 类的实现描述了对象如何表现它的属性,如 何执行操作。 主要包括实例变量、方法集、构造函数和析 构函数、私有操作集。 类测试是面向对象测试过程中最重要的一个 测试,在类测试过程中要保证测试那些具有 代表性的操作。 18从测试视角的角度来研究类 1)类的规范中包含用来构造实例的一些操作,这些操作也可能 导致新实例不正确的初始化。 2)类在定义自己的行为和属性时,也依赖于其他协作的类。例 如,类的成员变量可能是其他类的实例,或者类中的方法的 参数是其他类的实例。如果类定义中使用了包含不正确实现 的其他类,就会使类发生错误。 3)类的实现必须满足类本身的说明,但并不保证说明的正确性 。 4)类的实现也可能不支持所有要求的操作,或者执行一些错误 的操作。 5)类需要指定每个操作的前置条件,在发送消息之前,它也可 能不提供检查前置条件的方法。19继承 是类之间的联系,允许新类可以在一个已有的基础 上进行定义。 继承实现了共享父类中定义的数据和操作,同时也可以定 义新的特征,子类是在新的环境中存在,所以父类的正确 性不能保证子类的正确性,继承使代码的重用率得到了提 高,但同时也使故障的传播几率增加。 从测试视角的角度,关于继承: 继承提供了一种机制,潜在的错误会从基类传递到其派生 类,因此类测试中要尽早消除错误。 子类继承了父类的说明和实现,因此可重复使用相同的测 试方法。 设计模型时,检查是否合理地使用了继承。 使用继承实现代码的复用,可能会增加代码维护的难度 20多态 多态是指同一个操作作用于不同的对象可以有不同 的解释,产生不同的执行结果。 与多态密切相关的一个概念就是动态绑定。 动态绑定是指在程序运行过程中,当一个对象发送消息请 求服务时,要根据接收对象的具体情况将请求的操作与实 现的方法进行连接,即把这种连接推迟到运行时才进行。 从测试视角的角度来看,关于多态的观点: 1)多态允许通过增加类来扩展系统,而无须修改已有类。 但在扩展中可能出现意料之外的交互关系。 2)多态允许任何操作都能够包括类型不确定的参数,这就 增加了应该测试的实参的种类。 3)多态允许操作指定动态引用返回的响应。因为实际引用 的类可能是不正确的,或者不是发送者所期望的。 2110.2面向对象测试的层次 面向对象测试通常采用三层方式: 面向对象单元测试(类测试):针对类中的成员函 数以及成员函数间的交互进行测试; 面向对象集成测试:主要对系统内部的相互服务 进行测试,如类间的消息传递等; 面向对象系统测试:基于面向对象集成测试的最 后阶段的测试,主要以用户需求为测试标准。 2210.2.1面向对象的单元测试类测试 类测试一般也采用功能性测试方法和结构性测试方 法 功能性测试以类的规格说明为基础,主要检查类是否符合 其规格说明的要求。 功能性测试包括两个层次:类的规格说明和方法的规格说明。 结构性测试则是从程序出发,对类中方法进行测试,需要 考虑其中的代码是否正确。 测试分为两层:第一层考虑类中各独立方法的代码,即方法要做 单独测试;第二层考虑方法之间的相互作用,即方法需要进行综 合测试。 测试类中成员函数须考虑的两个问题: 1)继承的成员函数是否都不需要测试? 2)对父类的测试是否能照搬到子类?23继承的成员函数是否都不需要测试? 对父类中已经测试过的成员函数,以下两种情况需 要在子类中重新测试: 继承的成员函数在子类中做了改动。 成员函数调用了改动过的成员函数的部分。 例:假设父类Base中有Inherited()和Redefined() 这两个成员函数,继承父类Base的子类Derived只 对Redefined()做了改动。那么, Derived:Redefined()就需要重新测试;对于 Derived:Inherited(),若它包含了调用 Redefined()的语句(比如:x=x/Redefined(),就需 要重新测试,否则就不需要。 24对父类的测试是否能照搬到子类? 例:假设父类Base中有Inherited()和 Redefined()这两个成员函数,继承父类Base 的子类Derived只对Redefined()做了改动。 由于面向对象的继承使得两个函数相似,故 只需要在对Base:Redefined()的测试要求和 测试用例上添加对Derived:Redefined()新的 测试要求和增补相应的测试用例。 25例如 Base:Redefined()含有如下语句: If(value0)message(“less“); else if(value=0)message(“equal“); else message(“more“); 在Derived:Redefined()中定义为: If(value0)message(“less“); else if(value=0)message(“It is equal“) else message(“more“); if (value=88)message(“luck”); 在原有对父类Base的测试上,对Derived:Redefined()的测 试只需作如下改动:将value=0的测试结果期望改动;增加 value=88的测试。 26基于状态的测试 基于状态的测试是通过检查对象的状态在执行某个方法后是 否会转移到预期状态的一种测试技术。 使用该技术能够检验类中的方法是否能正确地交互。 基于状态测试的主要步骤如下: 1)依据设计文档,或者通过分析对象数据成员的取值情况空间,得到 被测试类的状态转移图。 2)给被测试的类加入用于设置和检查对象状态的新方法,导出对象的 逻辑状态。 3)对于状态转移图中每个状态,确定该状态是哪些方法的合法起始状 态,即在该状态时
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号