版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
软件工程概论
SoftwareEngineering贾恒彬E-mail:jiahengbin@李恒E-mail:liheng@第5章软件实现通常把编码和测试统称为实现。程序的质量主要取决于软件设计的质量,但是,所选用的程序设计语言的特点及编码风格也将对程序的可靠性、可读性、可测试性和可维护性产生深远的影响。测试的目的就是在软件投入生产性运行之前,尽可能多地发现软件中的错误。目前软件测试仍然是保证软件质量的关键步骤,它是对软件规格说明、设计和编码的最后复审。第5章软件实现软件测试在软件生命周期中横跨两个阶段。通常在编写出每个模块之后就对它做必要的测试(称为单元测试),模块的编写者和测试者是同一个人,编码和单元测试属于软件生命周期的同一个阶段。在这个阶段结束之后,对软件系统还应该进行各种综合测试,这是软件生命周期中的另一个独立的阶段,通常由专门的测试人员承担这项工作。第5章软件实现大量统计资料表明,软件测试的工作量往往占软件开发总工作量的40%以上.在极端情况,测试那种关系人的生命安全的软件所花费的成本,可能相当于软件工程其他开发步骤总成本的3倍到5倍。通过测试发现错误之后还必须诊断并改正错误,这就是调试的目的。调试是测试阶段最困难的工作。第5章软件实现5.1编码5.2软件测试基础5.3软件测试5.4软件测试方法5.5调试5.1
编码编码又称程序设计,是软件生命周期中继详细设计之后的阶段,这个阶段的任务是使用选定的程序设计语言,把经过详细设计所得到的以程序设计说明书体现的信息处理过程描述后,转换成能在计算机系统上运行的程序源代码。编码的质量和详细设计的质量、程序设计语言的性能以及编程风格密切相关。根据不同的程序设计语言的不同特点及其适用范围,选择恰当的程序设计语言进行编码,将有利于提高代码的可读性、可测试性、可维护性和可靠性。5.1.1程序设计语言程序设计语言的分类第一代语言——从属于机器的语言第二代语言——汇编语言第三代语言——高级程序设计语言传统的高级程序设计语言
FORTRAN、COBOL、ALGOL、BASIC通用的结构化程序设计语言
PASCAL,C和Ada
专用语言
APL、Lisp、PROLOG、Smalltalk、C++、Java
第四代语言(4GL)5.1.1程序设计语言程序设计语言选择的主要标准(1)系统用户的要求。如果所开发的系统由用户负责维护,用户通常要求用他们熟悉的语言书写程序。(2)可以使用的编译程序。运行目标系统的环境中可以提供的编译程序往往限制了可以选用的语言的范围。(3)可以得到的软件工具。如果某种语言有支持程序开发的软件工具可以利用,则目标系统的实现和验证都变得比较容易。(4)工程规模。如果工程规模很庞大,现有的语言又不完全适用,那么设计并实现一种供这个工程项目专用的程序设计语言,可能是一个正确的选择。
5.1.1程序设计语言程序设计语言选择的主要标准(5)程序员的知识。虽然对于有经验的程序员来说,学习一种新语言并不困难,但是要完全掌握一种新语言却需要实践。如果和其他标准不矛盾,那么应该选择一种已经为程序员所熟悉的语言。(6)软件可移植性要求。如果目标系统将在几台不同的计算机上运行,或者预期的使用寿命很长,那么选择一种标准化程度高、程序可移植性好的语言就是很重要的。(7)软件的应用领域。所谓的通用程序设计语言实际上并不是对所有应用领域都同样适用。因此,选择语言时应该充分考虑目标系统的应用范围。
5.1.2编码风格
编程风格即程序代码书写的风格,良好的编程风格的特点是逻辑简明清晰、易读易懂。程序的阅读者不仅仅有程序的开发者,还有程序的测试人员、维护人员。 具有良好的编程风格的程序有利于程序员在编程的过程中发现错误,有利于测试和维护人员对程序进行测试、调试、维护工作。良好的编程风格对于提高程序的可读性、可测试性、可维护性以及可靠性具有深远的意义。 为了使程序代码具有良好的风格,易读易懂,应该从以下几个方面遵循基本的原则:程序内部的文档数据说明语句构造输入/输出方法等5.1.2编码风格程序内部的文档(恰当的标识符、适当的注解和程序的视觉组织等)恰当的标识符选取含义鲜明的名字,使它能正确地提示程序对象所代表的实体。如果使用缩写,那么缩写规则应该一致,并且应该给每个名字加注解。一般的命名约定有不少人编程时用拼音给函数或变量命名,这样做并不能说明你很爱国,却会让用此程序的人迷糊(很多南方人不懂拼音)。程序中的英文一般不会太复杂,用词要力求准确。
匈牙利命名法是Microsoft公司倡导的
[Maguire1993],虽然很烦琐,但用习惯了也就成了自然。没有人强迫你采用何种命名法,但有一点应该做到:自己的程序命名必须一致。(1)宏定义用大写字母加下划线表示,如MAX_LENGTH;
(2)函数用大写字母开头的单词组合而成,如SetName,GetName;
(3)指针变量加前缀p,如*pNode;
(4)BOOL变量加前缀b,如
bFlag;
(5)int变量加前缀i,如
iWidth;
(6)float变量加前缀f,如
fWidth;
(7)double变量加前缀d,如
dWidth;
(8)字符串变量加前缀str,如
strName;
(9)枚举变量加前缀e,如
eDrawMode;
(10)类的成员变量加前缀m_,如
m_strName,m_iWidth;
5.1.2编码风格适当的注解通常在每个模块开始处有一段序言性的注解,简要描述模块的功能、主要算法、接口特点、重要数据以及开发简史。插在程序中间与一段程序代码有关的注解,主要解释包含这段代码的必要性。对于用高级语言书写的源程序,不需要用注解的形式把每个语句翻译成自然语言,应该利用注解提供一些额外的信息。应该用空格或空行清楚地区分注解和程序。程序的视觉组织程序清单的布局对于程序的可读性也有很大影响,应该利用适当的阶梯形式使程序的层次结构清晰明显。5.1.2编码风格数据说明数据说明的次序应该标准化(例如,按照数据结构或数据类型确定说明的次序)。当多个变量名在一个语句中说明时,应该按字母顺序排列这些变量。如果设计时使用了一个复杂的数据结构,则应该用注解说明用程序设计语言实现这个数据结构的方法和特点。5.1.2编码风格语句构造构造语句时应该遵循的原则是,每个语句都应该简单而直接,不能为了提高效率而使程序变得过分复杂。不要为了节省空间而把多个语句写在同一行;尽量避免复杂的条件测试;尽量减少对“非”条件的测试;避免大量使用循环嵌套和条件嵌套;利用括号使逻辑表达式或算术表达式的运算次序清晰直观。5.1.2编码风格输入/输出对所有输入数据都进行检验;检查输入项重要组合的合法性;保持输入格式简单;使用数据结束标记,不要要求用户指定数据的数目;明确提示交互式输入的请求,详细说明可用的选择或边界数值;当程序设计语言对格式有严格要求时,应保持输入格式一致;设计良好的输出报表;给所有输出数据加标志。5.1.2编码风格效率效率主要指处理机时间和存储器容量两个方面。在讨论提高效率前,应该记住3条原则:效率是性能要求,因此应该在需求分析阶段确定效率方面的要求。效率是靠好设计来提高的。程序的效率和程序的简单程度是一致的。不要牺牲程序的清晰性和可读性来不必要地提高效率。从三个方面进一步讨论效率问题:5.1.2编码风格1.程序运行时间写程序之前先简化算术的和逻辑的表达式;仔细研究嵌套的循环,以确定是否有语句可以从内层往外移;尽量避免使用多维数组;尽量避免使用指针和复杂的表;使用执行时间短的算术运算;不要混合使用不同的数据类型;尽量使用整数运算和布尔表达式。在效率是决定性因素的应用领域,尽量使用有良好优化特性的编译程序,以自动生成高效目标代码。5.1.2编码风格2.存储器效率在大型计算机中必须考虑操作系统页式调度的特点,一般说来,使用能保持功能域的结构化控制结构,是提高效率的好方法。在微处理机中如果要求使用最少的存储单元,则应选用有紧缩存储器特性的编译程序,在非常必要时可以使用汇编语言。提高执行效率的技术通常也能提高存储器效率。提高存储器效率的关键同样是简单。5.1.2编码风格3.输入输出效率如果用户为了给计算机提供输入信息或为了理解计算机输出的信息,所需花费的脑力劳动是经济的,那么人和计算机通信的效率就高。因此,简单清晰同样是提高人机通信效率的关键。硬件之间的通信效率比较复杂,但从写程序的角度看,有些简单原则可以提高输入输出效率:所有输入输出都应该有缓存,以减少用于通信的额外开销。对二级存储器应该选用最简单的访问方法。二级缓存器的输入输出应该以信息组为单位进行。如果“超高效的”输入输出很难被人理解,则不采用这种方法。5.2
软件测试基础
软件测试是为了发现错误而执行程序的过程。或者说,软件测试是根据软件开发各阶段的规格说明和程序的内部结构而精心设计一批测试用例(即输入数据及其预期的输出结果),并利用这些测试用例去运行程序,以发现程序错误的过程。 软件测试在软件生存期中横跨两个阶段: 单元测试:编写完一个模块后所作的测试。通常编写者和测试者是同一个人, 综合测试:对软件系统进行的各种综合测试,通常由专门的测试人员承担。5.2.1软件测试的目的
软件测试的目的是设计测试用例以最小的代价、在最短的时间内系统地发现各种不同类型的错误GrenfordJ.Myers就软件测试目的提出以下观点:测试是程序的执行过程,目的在于发现错误;一个好的测试用例在于能发现至今未发现的错误;一个成功的测试是发现了至今未发现的错误的测试。
注意:测试的可以证明程序中存在错误,但是测试不能证明程序中没有错误。
5.2.2软件测试准则为了能设计出有效的测试方案,主要的测试准则:(1)所有测试都应该能追溯到用户需求。正如上一小节讲过的,软件测试的目标是发现错误。从用户的角度看,最严重的错误是导致程序不能满足用户需求的那些错误。(2)应该远在测试开始之前就制定出测试计划。完成需求模型可着手制定测试计划,在建立了设计模型之后就可以立即开始设计详细的测试方案。(3)Pareto原理:测试发现的错误中的80%很可能是由程序中20%的模块造成的。当然,问题是怎样找出这些可疑的模块并彻底地测试它们。5.2.2软件测试准则(4)应该从“小规模”
“大规模”测试。首先重点测试单个程序模块,然后把测试重点转向在集成的模块簇中寻找错误,最后在整个系统中寻找错误。(5)穷举测试是不可能的。所谓穷举测试就是把程序所有可能的执行路径都检查一遍的测试。此路不通!因此,测试只能证明程序中有错误,不能证明程序中没有错误。但是,精心地设计测试方案,有可能充分覆盖程序逻辑并使程序达到所要求的可靠性。(6)为了达到最佳的测试效果,应该由独立的第三方从事测试工作。5.2.3软件测试方法测试有两种方法,即黑盒测试和白盒测试:如果已经知道了产品应该具有的功能,可以通过测试来检验是否每个功能都能正常使用——黑盒测试;如果知道产品的内部工作过程,可以通过测试来检验产品内部动作是否按照规格说明书的规定正常进行——白盒测试。5.2.3软件测试方法黑盒测试法把程序看作一个黑盒子,完全不考虑程序的内部结构和处理过程。黑盒测试又称为功能测试。白盒测试法与黑盒测试法相反,它的前提是可以把程序看成装在一个透明的白盒子里,测试者完全知道程序的结构和处理算法。这种方法按照程序内部的逻辑测试程序,检测程序中的主要执行通路是否都能按预定要求正确工作。白盒测试又称为结构测试。5.2.4软件测试过程单元测试集成测试确认测试系统测试5.2.4软件测试过程测试与软件开发各阶段的关系5.2.5测试信息流测试过程需要三类输入:软件配置——包括软件需求规格说明、软件设计规格说明、源代码等;测试配置——包括测试计划、测试用例、测试驱动程序等;测试工具——测试工具为测试的实施提供某种服务。例如,测试数据自动生成程序、静态分析程序、动态分析程序、测试结果分析程序以及驱动测试的工作台等。5.2.5测试信息流比较测试的实际结果和预期结果,若两者不一致则很可能是程序中有错误。设法确定错误的准确位置并且改正它,这就是调试的任务。与测试不同,通常由程序的编写者负责调试。如果出现要求修改设计的严重错误,软件的质量和可靠性是值得怀疑的,应该进一步仔细测试;同上述相反,功能完成得很正常,遇到的错误也很容易改正,则仍然应该考虑两种可能:(1)软件的可靠性是可以接受的;(2)所进行的测试尚不足以发现严重的错误。这些错误最终将被用户发现,而且需要在维护阶段改正它们(但是改正同一个错误需要付出的代价比在开发阶段高出许多倍)。5.3
软件测试3.1.1单元测试单元测试:测试模块。单元测试和编码属于软件过程的同一个阶段。在编写出源程序代码并通过了编译程序的语法检查之后,就可以用详细设计作指南,对重要的执行通路进行测试,以便发现模块内部的错误。可用人工测试和计算机测试两种测试方法,完成单元测试工作。单元测试主要使用白盒测试技术,而且对多个模块的测试可以并行地进行。5.3.1单元测试单元测试的内容1.模块接口首先应该对通过模块接口的数据流进行测试,主要检查下述几个方面:参数的数目、次序、属性或单位系统与变元是否一致;是否修改了只作输入用的变元;全局变量的定义和用法在各个模块中是否一致。5.3.1单元测试模块接口测试要点参数数目和由调用模块送来的变元的数目是否相等?参数的属性和变元的属性是否匹配?参数和变元的单位系统是否匹配?传送给被调用模块的变元的数目是否等于那个模块的参数的数目?传送给被调用模块的变元属性和参数的属性是否一致?传送给被调用模块的变元的单位系统和该模块参数的单位系统是否一致?传送给内部函数的变元属性、数目和次序是否正确?是否修改了只做输入用的变元。全程变量的定义和用法在各个模块中是否一致?5.3.1单元测试2.局部数据结构对于模块来说,局部数据结构是常见的错误来源。应该仔细设计测试方案,以便发现局部数据说明、初始化、默认值等方面的错误。局部数据结构测试要点错误的或不相容的说明使用尚未赋值或尚未初始化的变量错误的初始值或不正确的缺省值错误的变量名字(拼写错或截短了)数据类型不相容上溢、下溢或地址异常5.3.1单元测试3.重要的执行通路由于通常不可能进行穷尽测试,因此,在单元测试期间选择最有代表性、最可能发现错误的执行通路进行测试就是十分关键的。应该设计测试方案用来发现由于错误的计算、不正确的比较或不适当的控制流而造成的错误。重要的执行通路测试要点 选择最具有代表性的,最可能发现错误的执行通路进行测试5.3.1单元测试4.出错处理通路出错处理通路测试要点 应重点测试下述可能发生的错误对错误的描述是难于理解的记下的错误与实际遇到的错误不同在对错误进行处理之前,错误条件已经引起系统干预。对错误的处理不正确描述错误的信息不足以帮助确定造成错误的位置。5.3.1单元测试5.边界条件边界测试是单元测试中最后的也可能是最重要的任务。使用刚好小于、刚好等于和刚好大于最大值或最小值的数据结构、控制量和数据值的测试方案,非常可能发现软件中的错误。5.3.1单元测试边界条件测试要点比较数据类型不同的量逻辑运算符不正确或优先次序的错误当由于精度问题两个量不会相等时,程序中却期待着相等条件的出现“差1”错(即,多循环一次或少循环一次)错误的或不存在的循环终止条件当遇到发散的迭代时不能终止循环错误地修改循环变量5.3.1单元测试代码检查单元测试采用静、动结合的方法。在进行动态测试之前,首先采用静态方法对程序的代码进行检查。代码检查主要检查代码和设计的一致性,其内容包括代码的可读性、逻辑表达的正确性、代码结构的合理性、编程的风格、程序的语法、结构等。代码检查有桌面检查、代码审查、走查三种方式。其中,桌面检查是由程序员检查自己的程序;代码审查和走查基本相同,是由若干程序员和测试员组成一个审查小组,通过阅读、讨论和争议,对程序进行静态分析。通过代码检查可以找到程序中30%~70%的逻辑设计和编码缺陷,而且代码检查看到的是问题本身而不是问题的征兆。5.3.1单元测试单元测试的环境=所测模块+驱动模块+桩模块
驱动模块:用来模拟所测模块的上一级模块,相当于是一个接受测试数据,并把数据传送给所测模块,然后打印相关结果的“主程序”。桩模块:又称为“存根程序”,是用来代替被所测模块调用的子模块。它不需要把子模块的所有功能都带进来,但是也不能什么都不做。桩模块不能只简单的给出“曾经进入”的信息,而可能需要使用子模块的接口模拟实际子模块的功能。 5.3.2集成测试
集成测试是在单元测试的基础上,将模块按照总体设计时的要求组装成子系统或整个系统进行测试,因此集成测试又被称为组装测试。
集成测试关注的问题主要有:在把各个模块连接起来的时侯,穿越模块接口的数据是否会丢失一个模块的功能是否会对另一个模块的功能产生不利的影响各个子功能组合起来,能否达到预期要求的父功能全局数据结构是否有问题单个模块的误差累积起来,是否会放大,从而达到不能接受的程度。单个模块的错误是否会导致数据库错误。
5.3.2集成测试集成测试的策略选择什么方式把模块组装起来形成一个可运行的系统,直接影响到模块测试用例的形式、所用测试工具的类型、模块编号的次序和测试的次序、以及生成测试用例的费用和调试的费用。
通常,把模块组装成系统的方式有一次性组装方式和增量式组装方式。
5.3.2集成测试非增量式集成 非增量式集成又称为一次性集成,其策略是首先将各模块作为单个的实体进行测试,然后将所有的已经测试好的模块一次性组合到被测系统中,组成最终的系统进行测试。5.3.2集成测试非增量式集成的特点①测试的额外工作量比较大②模块间的接口错误发现得比较晚③错误的定位和修改比较困难④使用桩模块和驱动模块模拟软件的执行环境进行的测试与将测试模块放入到实际运行环境中进行的测试效果是不同的。因此仍然会有许多模块的接口错误躲过单元测试而进入到系统范围测试.⑤在测试过程中,除编写驱动模块和桩模块比较费时,花在每个模块单元测试上的时间相对增量式集成要少.⑥对于大型程序而言,由于所有的模块的单元测试都可以同时进行,多个测试人员可以并行工作,因此对人力和物力资源的利用率较高。
特点①~④是非增量式集成策略的缺点,⑤~⑥是它的优点。5.3.2集成测试
由于程序中不可避免地存在涉及模块间接口、全局数据结构等方面的问题,因此一次试运行成功的可能性并不很大。5.3.2集成测试增量式集成
增量式集成的策略是按不同的顺序依次向被测系统加入新的模块,进行集成测试,新模块可以用来取代被测系统在之前的测试中所使用的相应的驱动模块或桩模块。 为了保证在组装过程中不引入新错误,需要进行回归测试——重新执行以前做过的全部或部分测试,以确保在增加新的模块的同时没有增加新的错误。
5.3.2集成测试5.3.2集成测试增量式集成的特点①可以减少编写驱动或桩模块的工作量;②模块接口错误可以较早被发现;③较容易对错误进行定位和修改;④多次的回归测试,以及被测系统中模块在不同环境下的多次运行,为充分暴露模块接口错误提供了更多的机会,因此测试更彻底;⑤由于用实际模块替代了驱动模块或桩模块,在测试过程中所测模块的上(下)级模块将会多次重复执行;因此花费在所测模块上的测试时间相对非增量式集成较多;⑥测试工作的并行程度相对非增量式集成要低一些。
特点①~④是增量式集成的优点,⑤~⑥是缺点5.3.2集成测试
非增量式集成增量式集成编写驱动模块/桩模块工作量大小接口错误发现的时间晚早错误定位与修改的难度大小测试的彻底程度低高单个模块测试所需时间少多模块单元测试的并行程度高低非增量式集成与增量式集成测试策略对比表
增量式集成测试策略要比非增量式集成测试策略更好。因此,建议使用增量式集成测试策略5.3.2集成测试增量式集成测试的三种不同策略自底向上集成具体策略:整个测试过程的起点是系统模块层次结构中的最底层模块;然后用待加入的新模块替换被测系统先前所使用的驱动模块,新模块的直接上级模块用驱动模块替换;这个替换的过程一直持续到顶层模块加入被测系统中。主要优点:不需要编写桩模块,设计测试用例比较容易。主要缺点:对主要的控制直到最后才接触到。5.3.2集成测试自顶向下集成具体策略:整个测试过程的起点是顶层模块(主控模块),然后用待加入的新模块替换被测系统先前所使用的桩模块,新模块的所有直接下级模块全部用桩模块替换;这个替换的过程一直持续到所有的模块都加入到被测系统中为止。主要优点:不需要编写驱动模块,能够较早的发现主要控制方面的问题。主要缺点:需要编写桩模块,而要使桩模块能够模拟实际子模块的功能是十分困难的,特别是一些涉及到输入/输出的模块。5.3.2集成测试混合式集成具体策略:将系统划分成三层,上层采用自顶向下的策略,下层采用自底向上的策略,最后在中间层会合。混合式集成策略结合了自顶向下集成和自底向上集成策略的优点,当被测软件关键模块(注:关键模块应及早测试)比较多时,它是最好的折衷方法。
5.3.2集成测试在集成测试的范畴中,所谓回归测试是指重新执行已经做过的测试的某个子集,以保证一些程序的变化没有带来非预期的副作用。回归测试集包括3类不同的测试用例:检测软件全部功能的代表性测试用例子;专门针对可能受修改影响的软件功能的附加测试;针对被修改过的软件成分的测试。回归测试5.3.3确认测试
确认测试又称有效性测试。它的任务是验证软件的有效性,即验证软件的功能和性能及其他特性是否与用户的要求一致。 在确认测试阶段需要做的工作:首先要进行有效性测试以及软件配置复审,然后进行验收测试和安装测试,在通过了专家鉴定之后,才能成为可交付的软件。5.3.3确认测试有效性测试 有效性测试是在模拟的环境(可能就是开发的环境)下,运用黑盒测试的方法,验证被测软件是否满足需求规格说明书列出的需求。测试结果可以分为两类。测试结果与预期结果相符。说明软件的这部分功能或性能特征与需求规格说明书相符合,可以被接受。测试结果与预期结果不符。说明软件的这部分功能或性能特征与需求规格说明书不相符,需要为软件的这一部分提交问题报告5.3.3确认测试软件配置复查软件配置复查的目的是保证软件配置的所有成分都齐全,各方面的质量都符合要求,具有维护阶段所必需的细节,而且已经编排好分类的目录。
除了按合同规定的内容和要求,由人工审查软件配置之外,在确认测试的过程中,应当严格遵守用户手册和操作手册中规定的使用步骤,以便检查这些文档资料的完整性和正确性。必须仔细记录发现的遗漏和错误,并且适当地补充和改正。
5.3.3确认测试验收测试
验收测试是以用户为主的测试。软件开发人员和QA(质量保证)人员也应参加。由用户参加设计测试用例,使用用户界面输入测试数据,并分析测试的输出结果。一般使用生产中的实际数据进行测试。α测试——是由一个用户在开发环境下进行的测试,也可以是开发机构内部的用户在模拟实际操作环境下进行的测试。开发者在整个测试过程中随时记录使用中的情况和错误,因此α测试是在受控的环境下进行的测试。β测试——是由软件的多个用户在一个或多个用户的实际使用环境下进行的测试。测试时,开发者通常不在测试的现场,因此β测试是在开发者无法控制的环境下进行的软件现场应用。5.3.4系统测试所谓系统测试,是将通过确认测试的软件,作为整个基于计算机系统的一个元素,与计算机硬件、外设、某些支持软件、数据和人员等其他系统元素结合在一起,在实际运行或模拟环境下,对计算机系统进行一系列的综合性的测试。系统测试的目的在于通过与系统的需求定义作比较,发现软件与系统定义不符合或与之矛盾的地方。系统测试的测试用例应根据需求分析规格说明来设计,并在实际使用环境下来运行。
5.3.4系统测试几种常见的系统测试功能测试(FunctionTesting) 功能测试的目的是找出软件系统的功能与规格说明书中对于产品功能定义之间的差异。容量测试(VolumeTesting) 容量测试的目的是使系统承受超额的数据容量来发现它是否能够正确处理。压力测试(StressTesting) 压力测试的目的是测试在一个短时间里,资源超负荷或数据量、活动达到峰值情况下时系统的表现,即测试系统承受速度方面的超额负载。比如:基于Web的应用中用户的并发访问量的测试。5.3.4系统测试可用性测试(UsabilityTesting) 可用性测试是基于程序系统中充分考虑到以人为本的因素而出现的。其目的是检测用户在理解和使用系统方面到底有多好。安全性测试(SecurityTesting) 安全性测试的目的是通过测试破坏系统的安全检查机制,从而暴露系统在安全方面的不足与缺陷。性能测试(PerformanceTesting) 性能测试的目标是度量系统相对于预定义的目标的差异。性能要求包括响应时间、吞吐率等。性能功能测试常和压力测试一起进行。5.3.4系统测试恢复性测试(RecoveryTesting) 恢复性测试的目的是验证系统(如操作系统、数据库管理系统等)从软件或硬件失败中恢复的能力。其中包含系统能否正确地完成恢复功能,以及系统能否在要求的MTTR时间内恢复两方面的测试。兼容性测试(CompatibilityTesting) 兼容性测试的目的是测试应用对其他应用或系统的兼容性。可安装性测试(Install-abilityTesting) 可安装性测试的目的是验证成功安装系统的能力。5.3.4系统测试文档测试(DocumentationTesting) 文档测试的目的是验证用户文档是正确的并且保证操作手册的过程能正确工作。配置测试(ConfigurationTesting)
配置测试的目的是验证系统在不同的系统配置下能否正确工作。配置包括:硬件、软件、网络等。5.3
软件测试方法5.3.1软件测试方法概述静态测试 通常不要求在计算机上实际执行所测程序,主要以一些人工的模拟技术对软件进行分析和测试。代码审查:由有经验的程序设计人员根据软件的详细设计说明书,阅读程序来发现软件错误和缺陷。静态分析:主要是对程序进行以图形的方式表现程序的内部结构。主要有控制流分析、数据流分析、接口分析和表达式分析等5.4.1软件测试方法概述动态测试 通过输入一组预先按照一定的测试准则构造的实例数据来动态运行程序,而达到发现程序错误的过程。白盒测试 根据软件产品的内部工作过程,在计算机上进行测试,以证实每种内部操作是否符合设计规格要求,所有内部成分是否已经过检查黑盒测试 根据软件产品的功能设计规格,在计算机上进行测试,以证实每个实现了的功能是否符合要求。 测试人员完全不考虑程序内部的逻辑结构和内部特性,只依据程序的需求分析规格说明,检查程序的功能是否符合它的功能说明。5.4.1软件测试方法概述“穷尽”测试是不可能的!
不论是黑盒测试,还是白盒测试,都不可能把所有可能的输入数据都拿来进行所谓的穷举测试。因为可能的测试输入数据数目往往达到天文数字。5.4.2软件测试方法表1测试项目比较黑盒测试法
白盒测试法边界值分析等价类划分因果分析猜测错误逻辑覆盖
控制结构测试
语句覆盖
基本路径测试判定覆盖条件测试条件覆盖循环测试判定/条件覆盖条件组合覆盖路径覆盖
白盒测试(结构性测试)的基础是模块说明书或软件的详细设计说明白盒测试按照程序内部的逻辑结构测试程序,检查程序中的每条通路是否能按照预定的要求正确工作黑盒测试(功能性测试)的基础是软件的规格说明把程序看成一个黑盒子,完全不考虑程序的内部机构和处理过程黑盒测试只检查程序的功能是否能按照规格说明书的规定正常使用,程序是否能适当的接收输入数据产生正确的输出信息,并保持外部信息的完整性5.4.2软件测试方法黑盒(功能性)测试用例设计方法方法
实例讲解等价类划分边界值分析因果分析错误推测(黑盒)等价类划分基本思想
根据程序的输入数据性质的不同,将其划分为几个不同的集合类,然后从每个集合类中挑选有代表性的数据作为测试用例。每个集合类中的数据对于发现程序中的错误具有等效的作用。这样的集合类就被称为等价类。
无效等价类指的是不合理、无意义的或与规格说明中的规定不符的输入数据的集合,利用无效等价类可以测试程序对意外的、不合理的输入数据的处理能力即程序的健壮性
有效等价类指的是对于程序的规格说明来说有意义的、合法的输入数据的集合。利用有效等价类可以检测程序是否正确实现了要求的功能和处理(黑盒)等价类划分等价类的划分方法在输入条件规定了取值范围或值的个数的情况下,可以确立一个有效等价类和两个无效等价类。在输入条件规定了输入值的集合或者规定了“必须如何”的条件的情况下,可以确立一个有效等价类和一个无效等价类在输入条件是一个布尔量的情况下,可确定一个有效等价类和一个无效等价类在规定了输入数据的一组值(假定n个),并且程序要对每一个输入值分别处理的情况下,可确立n个有效等价类和一个无效等价类在规定了输入数据必须遵守的规则的情况下,可确立一个有效等价类(符合规则)和若干个无效等价类(从不同角度违反规则)在确知已划分的等价类中各元素在程序处理中的方式不同的情况下,则应再将该等价类进一步地划分为更小的等价类(黑盒)等价类划分等价划分法的实施基本步骤(1)划分等价类并列出等价类表(2)构造测试用例 根据已列出的等价类表,按以下步骤确定测试用例:设计一个新的测试用例,使其尽可能多地覆盖尚未覆盖的有效等价类。重复这一步,最后使得所有有效等价类均被测试用例所覆盖;设计一个新的测试用例,使其只覆盖一个无效等价类。重复这一步使所有无效等价类均被覆盖。
应按照输入条件(如输入值的范围,值的个数,值的集合,输入条件必须如何)划分为有效等价类和无效等价类。例如:每个学生可选修1-3门课程可以划分一个有效等价类:选修1-3门课程。可以划分两个无效等价类:未选修课,选修课超过3门。输入等价类有效等价类无效等价类
报表日期的类型及长度6个数字字符(1)有非数字字符(4)少于6个数字字符(5)多于6个数字字符(6)年份范围在2001~2005之间(2)小于2001(7)大于2005(8)月份范围在1~12之间(3)“报表日期”输入条件的等价类表小于1(9)大于12(10)第一步:等价类划分(黑盒)等价类划分第二步:为有效等价类设计测试用例
对表中编号为1,2,3的3个有效等价类用一个测试用例覆盖:200105等价类(1)(2)(3)输入有效测试数据期望结果覆盖范围第三步:为每一个无效等价类至少设计一个测试用例
测试数据期望结果覆盖范围001MAY等价类(4)输入无效20015等价类(5)输入无效2001005等价类(6)输入无效200005等价类(7)输入无效200805等价类(8)输入无效200100等价类(9)输入无效200113等价类(10)输入无效不能出现相同的测试用例本例的10个等价类至少需要8个测试用例(黑盒)等价类划分实例讲解-1问题陈述(三角形问题)三角形问题接受三个整数a,b,c作为输入,用作三角形的边。程序的输出是由这三条边确定的三角形的类型:等边三角形、等腰三角形、不等边三角形或非三角形。整数a,b,c必须满足以下条件:
c1. 1<=a<=200
c2. 1<=b<=200
c3. 1<=c<=200
c4. a<b+c
c5. b<a+c
c6. c<a+b(黑盒)等价类划分等价类划分: R1={<a,b,c>:有三条边a,b,c的等边三角形} R2={<a,b,c>:有三条边a,b,c的等腰三角形} R3={<a,b,c>:有三条边a,b,c的不等边三角形} R4={<a,b,c>:三条边a,b,c不构成三角形}a,b,c可能的取值: D1={<a,b,c>:a=b=c} D2={<a,b,c>:a=b,a<>c} D3={<a,b,c>:a=c,a<>b} D4={<a,b,c>:b=c,a<>b} D5={<a,b,c>:a<>c,a<>b,b<>c} D6={<a,b,c>:a>=c+b} D7={<a,b,c>:b>=a+c} D8={<a,b,c>:c>=a+b}(黑盒)等价类划分实例讲解-2问题陈述(标识符定义问题)某PASCAL语言版本中规定:”标识符由字母开头,后跟字母或数字的任意组合构成,有效字符数为8个,最大字符数为80个.并且标识符必须先说明,再使用.在同一说明语句中,标识符至少必须有一个.
等价类划分:输入条件有效等价类无效等价类标识符个数1个(1),多个(2)0个(3)标识符字符个数1~8个(4)0个(5),>8个(6),>80个标识符组成字母(8),数字(9)非字母数字字符(10),保留字(11)第一个字符字母(12)非字符(13)标识符使用先说明后使用(14)未说明已使用(15)(黑盒)等价类划分编号用例类的覆盖情况1VARx,T1234567:REAL;BEGINx:=3.14;T1234567:=2.73;….(1),(2),(4),(8),(9),(12),(14)2VAR:REAL;(3)3VARx,:REAL;(5)4VART12345678:REAL(6)5VART12345…….:REAL;(7)6VART$:CHAR;(10)7VARGOTO:INTEGER;(11)8VAR2T:REAL;(13)9VARPAR:REAL;BEGIN……PAP:=SIN(3.14*0.8)/6;(15)(黑盒)边界值分析法基本思想
选取输入/输出范围的边界值、略大于边界值和略小于边界值的数据来测试程序是否存在错误。
边界是指,相当于输入等价类和输出等价类而言,稍高于其边界值及稍低于其边界值的一些特定情况。因此,
边界值分析法可作为等价类划分法的一种有益补充。
(黑盒)边界值分析法边界值法中测试用例的选择原则(1)如果输入条件规定了值的范围,则应该取刚达到这个范围的边界值,以及刚刚超过这个范围边界的值作为测试输入数据;(2)如果输入条件规定了值的个数,则用最大个数、最小个数、比最大个数多1个、比最小个数少1的数作为测试数据;(3)根据规格说明的每一个输出条件,使用规则(1);(4)根据规格说明的每一个输出条件,使用规则(2);(5)如果程序的规格说明给出的输入域或输出域是有序集合(如有序表、顺序文件等),则应选取集合的第一个和最后一个元素作为测试用例;(6)如果程序用了一个内部结构,应该选取这个内部数据结构的边界值作为测试用例;(7)分析规格说明,找出其他可能的边界条件。(黑盒)边界值分析法
A按照输入值范围的边界。例如:输入值的范围是-1.0至1.0,则可选择用例:
–1.0、1.0、-1.001、1.001。
B按照输入/输出值个数的边界。
例如:输入文件可有1-255个记录,则设计用例: 文件的记录数为0个、1个、255个、256个。
C输出值域的边界。
例如:检索文献摘要,最多4篇。设计用例: 可检索0篇、1篇、4篇,和5篇(错误)。
D输入/输出有序集(如顺序文件、线性表)的边界。
应选择第一个元素和最后一个元素。输入条件报表日期的类型及长度1个数字字符5个数字字符7个数字字符有1个非数字字符全部是非数字字符6个数字字符显示出错显示出错显示出错显示出错显示出错输入有效日期范围月份范围测试用例说明测试数据期望结果选取理由52001520010052001.5MAY---200105月份为1月月份为12月月份<1月份>12200101200112200100200113200101200512200100200513输入有效输入有效显示出错显示出错输入有效输入有效显示出错显示出错在有效范围边界上选取数据仅有1个合法字符比有效长度少1比有效长度多1只有1个非法字符6个非法字符类型及长度均有效最小日期最大日期刚好小于最小日期刚好大于最大日期最小月份最大月份刚好小于最小月份刚好大于最大月份“报表日期”边界值分析法测试用例(黑盒)因果图法
前面介绍的等价类划分方法和边界值分析方法,都是着重考虑输入条件,但未考虑输入条件之间的联系。当需要测试的程序的输入数据之间存在相互的制约关系或存在输入情况的不同组合,相应产生多个动作的形式时,就需要用到因果图法。
因果图方法最终生成的就是判定表。它适合于检查程序输入条件的各种组合情况。
(黑盒)因果图法因果图中的因果关系 通常,在因果图中,用Ci表示原因,Ei表示结果。各结点表示状态,可取值“0”或“1”。“0”表示某状态不出现,“1”表示某状态出现。恒等非或(∨)与(∧)(黑盒)因果图法因果图中的约束关系E:a,b两个原因不会同时成立,两个中最多有一个可能成立。
I:a,b,c三个原因中至少有一个必须成立。
O:a和b当中必须有一个,且仅有一个成立。
R:当a出现时,b必须也出现。不可能a出现,b不出现。
M:当a是1时,b必须是0。而当a为0时,b的值不定。(黑盒)因果图法基本步骤
(1)分析软件规格说明描述中,哪些是原因(即输入条件或输入条件的等价类),哪些是结果(即输出条件),并给每个原因和结果赋予一个标识符。 (2)分析软件规格说明描述中的语义,找出原因与结果之间,原因与原因之间对应的是什么关系?根据这些关系,画出因果图。 (3)由于语法或环境限制,有些原因与原因之间,原因与结果之间的组合情况不可能出现。为表明这些特殊情况,在因果图上用一些记号标明约束或限制条件 (4)把因果图转换成判定表。 (5)把判定表的每一列拿出来作为依据,设计测试用例。(黑盒)因果图法实例讲解-1
问题描述: 某个软件的规格说明中包含了下面的要求:
第一列字符必须是A或B,第二列字符必须是一个数字,在此情况下进行文字的修改。但如果第一列字符不正确,则给出信息L;如果第二列字符非数字,则给出信息M。
(黑盒)因果图法编号
原因(条件)
编号
结果(动作)
1第一列字符是
A21修改文件
2第一列字符是
B22给出信息
L3第二列字符是一数字
23给出信息
M11中间原因
(1)列出原因和结果(2)画出因果图.所有原因结点列在左边,所有结果结点列在右边.建立四个中间结点,表示处理的中间状态(黑盒)因果图法(3)加上约束条件E。
(4)由因果图得到判定表12345678条件(原因)11111000021100110031010101011111100动作(结果)220000112110100023010101测试用例
A3AMB5BNC2DYA8A7B4B!X6P(黑盒)因果图法实例讲解-2
一个处理单价为5角钱的饮料的自动售货机软件测试用例的设计
问题描述:
若投入5角钱或1元硬币,按下[澄汁]或[啤酒]的按钮,则相应的饮料就送出来.若售货机没有零钱找,则一个显示[零钱找完]的红灯亮,这时在投入1元硬币并按下按钮后,饮料不送出来而且1元硬币也退出来;若有零钱找,则显示[零钱找完]的红灯灭,在送出饮料的同时退还5角硬币(黑盒)因果图法
原因1.售货机有零钱找
2.投入1元硬币
3.投入5角硬币
4.按下澄汁按钮
5.按下啤酒按钮
结果21.售货机[零钱找完]的红灯亮
22.退还1元硬币
23.退还5角硬币
24.送出澄汁饮料
25.送出啤酒饮料(1)列出原因和结果(2)画出因果图.所有原因结点列在左边,所有结果结点列在右边.建立四个中间结点,表示处理的中间状态.(黑盒)因果图法中间结点:11.投入1元硬币并按下饮料按钮
12.按下[澄汁]或[啤酒]的按钮
13.应当找5角硬币并且售货机有零钱找
14.钱已付清因为2/3,4/5不能同时发生,分别加上约束条件E(黑盒)因果图法(4)由因果图得到判定表(3)由于2与3,4与5不能同时发生,分别加上约束条件E。
(黑盒)错误推测法
等价类划分和边界值分析法都只是孤立的考虑各种测试用例的效果,因果图是比较机械的设计测试用例。他们都缺乏综合考虑的效应。基本思想通过经验或直觉推测程序中可能存在的各种错误,从而有针对性设计测试用例。白盒(结构性)测试用例的设计方法---覆盖测试表结构性测试覆盖标准标准
覆盖说明语句覆盖使被测程序中的每个语句至少执行一次判定覆盖语句覆盖+每个判定的每种可能的结果至少执行一次条件覆盖语句覆盖+判定表达式中的每个条件都取到各种可能的结果判定/条件覆盖判定覆盖+条件覆盖条件组合覆盖每个判定表达式中条件的各种可能组合都至少出现一次路径覆盖程序的每一条可能路径都至少执行一次(如果程序图中有环,则要求每个环至少要经过一次)
白盒法需要了解程序的功能与结构,测试用例必须根据程序内部的逻辑来设计。如果想用白盒法发现程序中的所有错误,则至少必须使程序中每种可能的路径都执行一次。白盒法又称为逻辑覆盖法,目前常用的覆盖标准有:白盒(结构性)方法实例图1被测模块的流程图被测模块的源程序BEGIN
……
IF(A>1)AND(B=0)
THENX:=X/A
IF(A=2ORX>1)
THENX:=X+1
END入口A>1ANDB=0X=X/AA=2ORX>1X=X+1返回TTabcde1234567s白盒(结构性)方法-语句覆盖入口A>1ANDB=0X=X/AA=2ORX>1X=X+1返回TTabcde1234567图2被测模块的流程图测试分析:1.该测试用例可以使每条语句都执行一次2.如果将程序中的第2个判定的OR改为AND,将不能发现错误3.将第2个判定的“X>1”误写为”X<1”,将不能发现错误测试用例程序执行路径A=2,B=0,X=4sacbed特点:
语句覆盖只关心判定表达式的值,而没有分别测试判定表达式中每个条件取不同的值时的情况白盒(结构性)方法-判定覆盖图3被测模块的流程图测试分析:1.该测试用例可以使每个判定分支都执行一次2.将第2个判定的“X>1”误写为”X<1”,仍然不能发现错误测试用例程序执行路径A=3,B=0,X=3sacbdA=2,B=1,X=1sabed入口A>1ANDB=0X=X/AA=2ORX>1X=X+1返回TTabcde1234567s白盒(结构性)方法-条件覆盖入口A>1ANDB=0X=X/AA=2ORX>1X=X+1返回TTabcde1234567s图4被测模块的流程图测试用例程序执行路径A=2,B=0,X=3sabdA=1,B=1,X=1scbed测试分析:1.该测试用例可以使每个判定内部的条件都能够取一次“真”和“假”
即:下面的每个取值都出现一次
A>1B=0A=2X>1
A<=1B<>0A<>2X<=12.仍然无法发现第2个判定表达式中的错误3.条件覆盖看起来似乎覆盖了判定覆盖,实际却不一定。对于第1个判定式:若使用测试用例:A=2,B=1和A=0,B=0,则判定永远为假,后面的“X=X/A”语句永远也检测不到。白盒(结构性)方法-判定/条件覆盖入口A>1ANDB=0X=X/AA=2ORX>1X=X+1返回TTabcde1234567s图5被测模块的流程图测试用例(与条件覆盖同)程序执行路径A=2,B=0,X=3sabdA=1,B=1,X=1scbed测试分析:1.该测试用例可以使判定中的条件都能够取一次“真”和“假”,且每个判定本身的所有结果至少出现一次2.这组测试用例与上面的条件覆盖的测试用例相同,这说明,有时判定/条件覆盖并不比条件覆盖更强。白盒(结构性)方法-条件组合覆盖(1)入口A>1ANDB=0X=X/AA=2OR
X>1X=X+1返回TTabcde1234567s图6被测模块的流程图测试分析:1.该测试用例可使判定表达式中条件的各种可能组合都至少出现一次2.满足条件组合测试覆盖标准的测试数据,也一定满足判定覆盖、条件覆盖、判定/条件覆盖。3.满足条件组合测试覆盖标准的测试数据并不一定能使程序中的每条路径都执行到。例如:本测试方案中路径sacbd就没有测试到测试用例程序执行路径A=2,B=0,X=4sacbedA=2,B=1,X=1sabedA=1,B=0,X=2sabedA=1,B=1,X=1sabd白盒(结构性)方法-条件组合覆盖(2)A>1B=0A=2,B=0,X=4A>1B<>0A=2,B=1,X=1A<=1B=0A=1,B=0,X=2A<=1B<>0A=1,B=1,X=1A=2X>1A=2,B=0,X=4A=2X<=1A=2,B=1,X=1A<>2X>1A=1,B=0,X=2A<>2X<=1A=1,B=1,X=1入口A>1X=X/AA=2X=X+1返回TTabcdesB=0X>1TT图7图6的计算机执行的实际流程图白盒(结构性)方法-路径覆盖入口A>1ANDB=0X=X/AA=2OR
X>1X=X+1返回TTabcde1234567s图8被测模块的流程图测试分析:1.该测试用例可使使程序的每一条可能路径都至少执行一次2.路径覆盖是相当强的逻辑覆盖标准,但他没有检验表达式中条件的各种可能组合情况;结合路经测试和条件组合测试,可以设计出检错能力更强的测试数据测试用例程序执行路径A=2,B=0,X=4sacbedA=1,B=1,X=1sabdA=1,B=1,X=2sabedA=3,B=0,X=3sacbd白盒(结构性)测试用例的设计方法---基本路径测试表控制结构测试基本路径测试测试用例能保证每条语句至少执行一次,每个条件在执行时分别取真假两种值条件测试测试用例能检查程序模块中包含的逻辑条件循环测试测试循环结构的有效性
现在的很多结构性测试技术,是根据程序的控制结构设计测试数据的技术,下面列出了几种常用的控制结构测试技术。本节重点介绍基本路径测试(白盒)基本路径法
基本路径测试,首先计算程序的环形复杂度,并用该复杂度为指南定义执行路径的基本集合,从该基本集合导出的测试用例可以保证程序中的每条语句至少执行一次,而且每个条件在执行时都将分别取真、假两种值。(白盒)基本路径法第一步,根据过程设计结果画出相应的流图。第二步,计算流图的环形复杂度。第三步,确立线性独立路径的基本集合所谓独立路径是指至少引入程序的一个新处理语句集合或一个新条件的路径,也就是说,独立路径至少包含一条在定义该路径之前不曾用过的边。使用基本路径测试法设计测试用例时,程序的环形复杂度决定了程序中独立路径的数量,而且这个数是确保程序中所有语句至少被执行一次所需的测试数量的上界。第四步,设计可强制执行基本集合中每条路径的测试用例。(白盒)基本路径法106分析例子流图环形复杂度6基本集合(白盒)条件测试基本路径测试简单高效,但是只有这样的技术还不够,为了进一步提高白盒测试的质量,还需要使用其他控制结构技术。条件测试技术设计出的测试用例,能够检查程序模块中包含的逻辑条件。条件测试基础简单条件格式:一个布尔变量或一个关系表达式,在布尔变量或关系表达式之前还可能有一个NOT算符。关系表达式的形式如下:
E1<关系算符>E2
关系算符:>,<,≥≤≠=复合条件:复合条件由两个或多个简单条件、布尔算符和括弧组成。布尔算符有OR,AND和NOT。不包含关系表达式的条件称为布尔表达式。条件成分类型:包括布尔算符、布尔变量、布尔括弧、关系算符及算术表达式。(白盒)条件测试条件测试的目的不仅是检测程序条件中的错误,而且是检测程序中的其他错误。如果程序P的测试集能有效地检测P中条件的错误,则它很可能也可以有效地检测P中的其他错误
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 会议服务合同协议书的履行期限
- 苯板采购合同的履行威胁
- 螺旋式机器购买协议
- 房屋买卖合同的违约金计算及支付方式
- 电脑交易协议示范
- 招标方案设计背景介绍
- 目标责任书撰写技巧
- 装卸信誉保证
- 网络打印机采购协议
- 致爱妻忠诚的保证书
- 军事理论课(2024)学习通超星期末考试答案章节答案2024年
- 魅力歌剧-《饮酒歌》课件 2024-2025学年人音版初中音乐九年级上册
- 2024年心血管运动医学指南要点解读课件
- 安防监控系统技术标投标书例范本
- 牛肉丸销售合同模板
- 2024年资格考试-高校教师岗前培训考试近5年真题集锦(频考类试题)带答案
- 上海市普陀区曹杨二中2025届生物高二上期末综合测试试题含解析
- 1.1 公有制为主体多种所有制经济共同发展 课件-2024-2025学年高中政治统编版必修二经济与社会
- 第三单元(单元测试)-2024-2025学年四年级上册数学人教版
- 中高层管理人员薪酬激励制度
- 2024年秋季新人教版七年级上册英语全册教案设计
评论
0/150
提交评论