1第十讲软件开发流程及调试与测试参考书:《实用C++程序调试指南》AnnR.FordTobyJ.Teorey著於春景译《软件测试技术概论》古乐史九林编著2典型软件开发流程•软件工程概要•问题的提出•需求分析•概要设计•详细设计•编码实现•系统测试•经验总结3软件工程概要•需求分析:确定软件需要解决什么问题-决定因素:人-软件开发人员需要与用户深入交流,明确问题的输入、输出以及其他附加信息-不要轻视任何问题!•方案设计:设计程序框架-概要设计:设计总体方案,形成高层模块划分-详细设计:细化模块,获得各模块的输入、输出与算法•编码实现:实际编程•系统测试:测试程序的正确性与稳定性•经验总结4软件开发流程图修改需求分析方案设计编码实现系统测试反馈修改修改反馈反馈5本讲主要内容•调试-调试概述-常见的语法和语义错误-跟踪技术-使用调试器•测试-测试概述-白盒测试-黑盒测试-单元测试-集成测试6调试概述•程序调试是对错误进行定位并排除错误•调式方法-手动跟踪-程序跟踪-使用调试器7语法错误的排除•语法错误由编译器指出,根据编译器提供的信息修改程序。•编译器带来的难题-编译器有时“偏离方向”,不指出真正的错误,而是指出之后的某处。-遇到一个语法错之后,编译器往往产生很多错误信息。•策略-如果在编译器指出的行未发现错误,向前寻找-如果出现大量错误信息,改正第一个以后重新编译8常见语法错误•漏写分号•变量名未声明•括号不匹配•字符串没有结束符•赋值语句左侧不是左值•带返回值的函数缺少return语句9语法警告•虽然语法规则没有被破坏,但是可能会有隐含错误。针对常见的编程错误,编译器中专门嵌入了错误检查功能。•要认真对待警告。•常见警告:-将“=”用作“==”-变量未初始化10常见语义错误•死循环•混淆了运算符的优先级•else搭配不当•off-by-one(偏一)错误•将代码不适当地放在循环体中•应该使用复合语句时未使用复合语句•数组下标上下限错误11软件测试概述•软件测试的目的在于发现错误;一个好的测试用例在于发现从前未发现的错误;一个成功的测试是发现了从前未发现的错误的测试。(MeryG.TheArtofSoftwareTesting)•IEEE的定义-软件测试定义为:“使用人工和自动手段来运行或测试某个系统的过程,其目的在于检验它是否满足规定的需求或是弄清预期结果与实际结果之间的差别”12测试在软件开发中的角色•测试是执行或者模拟一个系统或者程序的操作•测试是为了建立一个信心,即软件是按照他所要求的方式进行的,而不会执行它不被希望的操作•测试是带着发现问题和错误的意图来分析程序的•测试是度量程序的功能和质量的•测试是评价程序和项目工作产品的属性和行为能力的,并且评估其是否获得了期望和可接受的成果——NormBrown.LittleBookofTestingVolI.13调试与测试的不同•调试是随机的,不可重复的过程,它用于隔离和确认问题发生的原因,然后修改软件来纠正问题。•测试是有计划的,可重复的过程,目的是为了发现预先定义的规格和标准不符合的问题。14白盒测试•白盒测试是一种测试用例设计方法•使用白盒测试方法产生的测试用例能够:-保证一个模块中的所有独立路径至少被使用一次-对所有逻辑值均需测试“真”和“假”;-在上下边界可操作范围内运行所有循环;-检查内部数据结构以确保其有效性。15常用的白盒测试技术•静态分析技术-静态分析不执行程序,它可以由人工进行,充分发挥人的逻辑思维优势,也可以借助软件工具自动进行。-代码检查主要检查代码和设计的一致性,代码对标准的遵循、可读性,代码的逻辑表达的正确性,代码结构的合理性等方面;在检查前,应准备好需求描述文档、程序设计文档、程序的源代码清单、代码编码标准和代码缺陷检查表等。-静态结构分析主要是以图形的方式表现程序的内部结构,例如函数调用关系图、函数内部控制流图。-代码质量度量ISO/IEC9126国际标准所定义的软件质量包括六个方面:功能性、可靠性、易用性、效率、可维护性和可移植性。软件的质量是软件属性的各种标准度量的组合。16常用的白盒测试技术•动态分析技术-程序在受控的环境下使用特定的数据运行-路径测试使程序能够执行尽可能多的逻辑路径-分支测试需要程序中的每个分支至少被经过一次-覆盖率分析主要对代码的执行路径覆盖范围进行评估,可以指导测试用例的设计。主要有:语句覆盖、判定覆盖、条件覆盖、判定条件覆盖、路径覆盖。17黑盒测试•在测试中主要关注于被测试软件的功能实现,而不是内部逻辑。•黑盒测试试图发现以下类型的错误:-功能错误或遗漏-界面错误-数据结构或外部数据库访问错误-性能错误-初始化和终止错误18单元测试•对软件的基本组成单元进行测试•在纯C语言代码中,一般认为一个函数就是一个单元•目的:-验证代码是与设计相符合的-跟踪需求和设计的实现-发现需求和设计中存在的错误-发现在编码过程中引入的错误19为什么要进行单元测试•问题一、单元测试花费了太多时间-未经单元测试的程序,集成起来能够正常工作的可能性是很小的•问题二、单元测试仅仅是证明这些代码做了什么-首先要有详细的规格说明,再编码。测试能够以规格说明为基础。代码能够针对它的规格说明,而不是自身进行测试。高质量的测试需要高质量的规格说明。20为什么要进行单元测试•问题三、我是个很棒的程序员,我是否可以不进行单元测试-编码不是可以一次通过的过程,每个人都会犯错误•问题四、不管怎样,集成测试将会抓住所有的Bug-在集成阶段,对单元功能全面测试的复杂程度远远超过独立进行的单元测试过程21单元测试环境•驱动模块-是一个接收测试数据,并把数据传送给(要测试)的模块,然后打印相关结果的“主程序”•桩模块-替代那些隶属于本模块(被调用)的模块•模拟生成测试数据或状态22单元测试策略——自顶向下•方法-先对最顶层的单元进行测试,把调用的单元做成桩模块。使用上层已测试过的单元作为驱动程序。•优点-可以和详细设计及编码并行•缺点-随着单元一个一个被测试,测试过程将变得越来越复杂。-任何一个单元的修改将影响到其下层调用的所有单元都被重新测试。23单元测试策略——自底向上•方法-用下层已测试过的单元,做成桩模块•优点-不需要桩模块,用例可以直接从功能设计中获取24单元测试策略——孤立测试•方法-不考虑每个模块与其他模块之间的关系,为每个模块设计桩模块和驱动模块。每个模块进行独立的单元测试。•优点-简单、易操作,可以达到高的结构覆盖率。各模块可以并行测试-是最好的单元测试策略25集成测试•也叫组装测试、联合测试。在单元测试的基础之上,将所有模块按照概要设计要求组装测试。此前单元测试已经完成。•关注重点:-把各个模块连接起来时,穿越模块接口的数据是否会丢失。-各个子功能组合起来,是否达到预期要求的父功能。-一个模块的功能是否会对另一模块的功能产生不利影响。-全局数据结构是否有问题,会不会被异常修改。-单个模块的误差积累起来,是否会放大,从而达到不可接受的程度。•集成测试和开发的关系-集成测试与架构设计之间有相互的依赖性。如果架构设计不明确,集成测试将无法很好地完成。同样集成测试可以用来发现架构设计中的错误。26集成测试的策略•集成测试的策略比较多,这里简单介绍几种-大爆炸集成:将所有组件一次性集成-自顶向下集成-自底向上集成-三明治集成