Bootstrap

软件工程——期末复习(适用于sdut)

名词解释:

名词解释--人月

答案:人月是软件开发工作量的单位,1人月表示1个程序员1个月的工作时间所开发的代码量。

请解释软件缺陷、错误和失败,并简单举例说明。

答案:缺陷(defect)指系统代码中存在不正确的地方。

错误(error)指系统执行到缺陷代码,就可能是的执行结果不符合预期且无法预测。表现出来不稳定的状态。

失败(failure)指由于错误的发生使得软件的功能失效。

举例:计算式中存在除0--缺陷。计算出现除0时会发生错误。系统无法输出正确结果或异常终止等为失败。

试题解析:课本P322,区分其表现的层次。

问答题:

1.根据描述,建立实体关系图 和 DFD。

某大学图书馆系统的用户分为几种类型的借书人,分别是教职工借书人、研究生借书人和本科生借书人。借书人的基本信息包括姓名、地址和电话号码,其中教职工借书人还要包括办公室地址和办公电话信息,研究生借书人还要包括专业方向和导师信息等。

系统对借出的图书信息进行跟踪,即记录借书人在什么时间借阅了哪本图书,以及在什么时间归还了哪本图书。

借书人借书前可以根据书名进行图书检索,可以检索出图书的条码号、书名、作者、出版社、ISBN、出版日期、是否在馆等信息。

如果打算借阅的图书全部被借出,可以办理预约。每个预约只针对一个借书人和一个书名,需要记录预约日期、优先权和预约完成日期。

答案:实体:借书人(细分为教职工借书人、研究生借书人、本科生借书人)图书、借还书、预约

属性:借书人:姓名、地址和电话号码;教职工借书人:+办公室地址和办公电话;研究生借书人:+专业方向、导师信息。

图书:条码号、书名、作者、出版社、ISBN、出版日期、是否在馆

借还书:借书日期、借书人、借书名称、还书日期

预约:预约日期、借书人、预约图书、优先权、预约完成日期

关系:借书人借还、预约图书

根据描述,建立用例图。

某大学图书馆系统的用户分为几种类型的借书人,分别是教职工借书人、研究生借书人和本科生借书人。借书人的基本信息包括姓名、地址和电话号码,其中教职工借书人还要包括办公室地址和办公电话信息,研究生借书人还要包括专业方向和导师信息等。

系统对借出的图书信息进行跟踪,即记录借书人在什么时间借阅了哪本图书,以及在什么时间归还了哪本图书。

借书人借书前可以根据书名进行图书检索,可以检索出图书的条码号、书名、作者、出版社、ISBN、出版日期、是否在馆等信息。

如果打算借阅的图书全部被借出,可以办理预约。每个预约只针对一个借书人和一个书名,需要记录预约日期、优先权和预约完成日期。

答案:参与者:借书人(派生出教职工借书人、研究生借书人、本科生借书人)

用例:借书、还书、预约图书、检索图书。

3.根据描述,建立概念类图。

某大学图书馆系统的用户分为几种类型的借书人,分别是教职工借书人、研究生借书人和本科生借书人。借书人的基本信息包括姓名、地址和电话号码,其中教职工借书人还要包括办公室地址和办公电话信息,研究生借书人还要包括专业方向和导师信息等。

系统对借出的图书信息进行跟踪,即记录借书人在什么时间借阅了哪本图书,以及在什么时间归还了哪本图书。

借书人借书前可以根据书名进行图书检索,可以检索出图书的条码号、书名、作者、出版社、ISBN、出版日期、是否在馆等信息。

如果打算借阅的图书全部被借出,可以办理预约。每个预约只针对一个借书人和一个书名,需要记录预约日期、优先权和预约完成日期。

答案:概念类:借书人(细分为教职工借书人、研究生借书人、本科生借书人)图书、借还书、预约

属性:借书人:姓名、地址和电话号码;教职工借书人:+办公室地址和办公电话;研究生借书人:+专业方向、导师信息。

图书:条码号、书名、作者、出版社、ISBN、出版日期、是否在馆

借还书:借书日期、借书人、借书名称、还书日期

预约:预约日期、借书人、预约图书、优先权、预约完成日期

关系:借书人借还、预约图书

人机交互设计的目标是什么?如何理解易用性?

答案:易用性。包括易学性、易记性、效率、出错率和主观满意度。

结构化设计中的耦合与内聚都有哪些情况?按由低到高的顺序写出。

答案:耦合(低到高):数据、印记、控制、重复、公共、内容;

内聚(低到高):偶然、逻辑、时间、过程、通信、功能、信息。

在软件工程实践中,有人认为“软件工程存在最好的解决方案,也应该追求最好的方案”,请辨析该说法是否正确,并给出相应的解释说明。

  “软件工程存在最好的解决方案,也应该追求最好的方案”这一说法并不完全正确。虽然在理论上,有些问题可以有最优解,但在实际的软件工程中,所谓的“最好”解决方案通常是相对的,它依赖于具体的项目需求、资源、时间限制、团队技术能力等多重因素。追求“最好的方案”可能导致过度设计、复杂度增加和开发成本上升,甚至影响项目的进度和交付。因此,软件开发更应关注找到一个“足够好”的解决方案,即在现有条件下满足需求的最优解,而非追求理想化的完美方案。最终,合理的妥协和适时的技术迭代往往比单纯追求最优解更加符合实际项目的需求,避免过度设计和不必要的复杂度。

有人认为在软件测试中,应当找出软件中所有的缺陷和不足,从而确保软件产品的质量,请辨析该描述是否正确,并给出相应的解释说明。

在软件测试中,虽然发现和修复缺陷是确保软件质量的重要环节,但“找出所有缺陷”并不是现实和可行的目标。软件测试的目的是通过合理的测试策略、方法和工具,尽可能发现影响系统功能、性能和安全等方面的关键缺陷。然而,软件系统通常复杂且庞大,几乎不可能通过常规测试发现所有的缺陷,尤其是在时间和资源有限的情况下。更重要的是,测试应该优先关注高风险和关键功能,而不是追求完全的缺陷覆盖。过于追求“找出所有缺陷”可能导致测试资源的浪费,无法有效平衡成本和效益。因此,软件测试应着眼于发现严重缺陷、提高系统的可靠性和可维护性,并通过合理的风险评估确保软件的整体质量,而不是试图发现每一个小缺陷。

根据抽象程度的不同,软件设计可以为分高层设计、中层设计和低层设计,各自的关注点在哪?并简要说明为什么需要分层进行软件设计。(课本139页原话)

软件体系结构={部件(component),连接件(connector),配置(configuraion)}(Shaw,1995),如何理解这一定义?并简要说明应当如何进行软件体系结构的设计。p148

定义:软件体系结构={部件(component),连接件(connector),配置 (configuraion)}

部件:软件体系结构的组成基本组成单位之一,承载系统的主要功能,包括处理与数据;

连接件:软件体系结构的另一个组成基本单位之一,定义部件之间的交互,是连接的抽象表示;

配置:对“形式”的发展,定义了“部件”以及“连接件”之间的关联方式,将他 们组成系统的总体结构;

定义的理解:一个软件系统的体系结构规定了系统的计算部件和部件之间的交互。

体系结构设计过程p160

1、分析关键需求和项目约束;2、选择体系结构风格;3、进行软件体系结构逻辑(抽象)设计;4、依赖逻辑设计进行软件体系结构物理(实现)设计;5、完善软件体系结构设计; 6、定义构件接口;7、迭代过程3-6

试说明什么是分解(decomposition)和抽象(abstraction),并简要说明为什么分解与抽象是软件设计的核心思想。(课件上的标准答案)

分解是将系统分割为几个相对简单的子系统,以及各子系统之间的关系。

抽象则是通过接口将系统与具体的实现分离,是整个系统的关键所在、本质所在。

因为现代软件设计的核心问题在于控制由于软件复杂性引起的“系统复杂度”,为此“分而治之”是软件设计解决复杂度难题的主要思路,抽象和分解正是“分治”“解耦'的体现,在软件工程实践中也得到了大量应用,故此是软件设计的核心思想。

试举例说明什么是“桩”(stub)和“驱动”(driver),并说明其在软件工程中的应用。

答:

def test(a,b)#被测模块

c=a+b

stub(c)

def stub(c)#桩函数

print(c)

if __name==“__mian__”:#驱动程序

test(1,2)

在软件工程中,桩(Stub)和驱动(Driver)是用于软件测试和开发过程中模拟未完成模块或系统的一种方法。这些技术特别在进行单元测试、集成测试或开发中的模块化设计时非常有用。它们允许开发人员在系统的某些部分还未实现或尚未集成时,继续进行其他部分的开发或测试。

1. 桩(Stub)

桩是用于替代系统中尚未实现的组件或模块的代码,通常它模拟的是被调用的函数、方法或模块的行为。桩通常不执行完整的功能,而是返回预设的结果或简单地模拟接口的行为。桩的主要目的是支持其他部分的开发或测试,确保系统能够部分运行。

桩的特点:

主要用于模拟被调用的低层模块或子系统。

返回预设的值,而不是实现真实的功能。

常用于单元测试中,替代那些尚未开发完成或不方便测试的模块。

例子:

假设我们正在开发一个电子商务系统,其中有一个支付模块,而支付服务提供商的接口还没有完成。在这种情况下,我们可以使用桩来模拟支付模块的功能。

例如,支付模块中的processPayment方法可能会涉及到与外部支付网关的交互。由于外部支付服务未实现,可以编写一个桩程序来模拟支付网关的响应:

def processPayment(amount):

    # 假设总是成功处理支付

    return "Payment processed successfully"

通过这种方式,其他模块(如订单处理、库存管理等)可以继续进行开发和测试,而不需要等待支付服务的完成。

2. 驱动(Driver)

驱动是用来替代尚未实现的高层模块或系统组件,通常它负责调用被测试模块(被驱动模块)。驱动程序的作用是为待测试的模块提供输入和环境,并捕获它的输出。驱动常用于集成测试,特别是在模块还没有完成时,通过驱动提供测试的入口。

驱动的特点:

主要用于模拟调用模块的高层逻辑。

提供输入数据并驱动待测试模块的执行。

用于集成测试和系统测试中,特别是当下层模块尚未实现时。

例子:

假设在开发一个数据处理系统时,数据的输入需要通过一个文件上传模块,而该模块尚未开发完成。在这种情况下,我们可以编写一个驱动来模拟文件上传模块的行为。

假设待测试的模块是一个processFile方法,该方法读取文件内容并进行数据处理。由于文件上传模块未完成,我们可以编写一个驱动来模拟文件上传模块,提供一个测试用的文件路径,并模拟上传过程。

def test_processFile():

    # 模拟一个文件路径

    file_path = "test_data.csv"

    # 假设文件上传模块未完成,我们模拟文件路径输入

    file_content = uploadFile(file_path)  # 驱动模块

    # 调用待测试的模块

    result = processFile(file_content)  # 被驱动模块

    print(result)

这里的uploadFile函数是驱动程序,它模拟了文件上传的过程,并提供文件路径,processFile则是被测试的模块。

3. 桩与驱动的应用场景

单元测试:当测试一个模块时,如果它依赖于其他尚未完成的模块,可以使用桩来替代这些模块,确保测试集中在待测试模块的逻辑上。

例如,在测试一个订单模块时,可以使用桩来模拟支付模块的返回结果。

集成测试:当多个模块需要协作工作,但其中某些模块尚未完成时,可以使用驱动来替代那些尚未完成的模块,驱动已完成的模块进行测试。

例如,在测试数据处理系统时,驱动模块模拟了输入数据的来源(如上传的文件),以测试数据处理模块的功能。

开发阶段的协作:当系统的开发团队分为多个小组时,有些小组负责某些模块的开发,但其他小组的模块可能还未完成。此时,桩和驱动可以作为临时工具,帮助各个小组在开发过程中进行协作与集成。

4. 总结

桩(Stub):用于模拟系统中尚未实现的低层模块,通常替代被调用模块的功能,并返回预设的结果。

驱动(Driver):用于模拟尚未完成的高层模块,通常用于提供输入并驱动待测试模块的执行。

应用场景:桩和驱动常用于单元测试、集成测试以及模块开发过程中,以支持其他模块的开发、测试和协作。

通过使用桩和驱动,开发人员能够在系统的一部分还未完成时继续进行其他部分的测试和开发,有效提高开发效率和系统的稳定性。

已知定义有整型变量X,Y,有如下代码:

X=X+Y;Y=X-Y;X=X-Y;

试分析此段代码的作用,尝试从软件工程的角度说明这段代码存在的问题。

答:作用:交换X和Y的值

问题:

可读性差:虽然它实现了交换,但使用了三步计算来达到这个目的,而不如直接使用临时变量来交换,这样代码更加直观和清晰。

潜在的溢出风险:使用了加法和减法操作,可能会导致整数溢出,尤其是当 X 和 Y 的值非常大时。假设 X 和 Y 的值已经接近整型的最大值(比如 INT_MAX),那么 X + Y 可能会导致溢出,从而导致程序行为不符合预期。

增加了不必要的风险性。

从软件工程的角度看代码时,可能会出现以下几种常见的问题:

1. 可读性差

问题:代码不易理解,难以被其他开发人员快速阅读和修改。

原因:使用复杂的逻辑、缺乏清晰的命名、不符合常规编程习惯等。

影响:降低代码的维护性、增加出错的机会。团队成员或未来的开发人员可能需要更多时间来理解代码。

解决方案:

使用清晰、直观的变量名和函数名。

避免过于复杂的表达式或嵌套结构。

添加适当的注释,说明代码的意图和实现方式。

2. 效率低下

问题:代码执行效率低,可能浪费系统资源或导致性能瓶颈。

原因:使用了不必要的复杂计算、冗余的操作、低效的数据结构等。

影响:程序运行时间长,响应慢,影响用户体验,或导致系统负载过高。

解决方案:

优化算法和数据结构,选择合适的实现方式。

避免重复计算,使用缓存或缓存机制来存储中间结果。

进行性能分析,识别瓶颈并加以优化。

3. 代码重复

问题:代码中存在大量重复的逻辑或实现,增加了维护成本。

原因:没有合理的模块化设计,导致相同的逻辑多次实现。

影响:如果某个逻辑需要修改,必须在多个地方修改,增加了出错的概率和维护的复杂性。

解决方案:

采用函数和方法抽象,避免重复代码。

使用设计模式,如工厂模式、策略模式等,来提高代码的复用性。

4. 耦合度高

问题:模块之间的依赖关系过于紧密,导致代码难以修改和扩展。

原因:模块间相互依赖,缺乏良好的封装性和模块化设计。

影响:修改一个模块时可能需要修改多个相关模块,增加了出错的可能性,影响代码的可维护性和可扩展性。

解决方案:

遵循“高内聚,低耦合”的设计原则。

使用接口、抽象类或设计模式来降低模块之间的依赖性。

确保模块之间通过清晰的接口通信,而不是直接访问实现细节。

5. 错误处理不当

问题:代码中缺乏有效的错误处理,可能导致程序崩溃、数据丢失或无法正确恢复。

原因:没有充分考虑异常情况,错误和异常未被捕获或处理。

影响:程序可能在运行时出现不可预料的错误,导致系统不稳定或数据损坏。

解决方案:

采用一致的异常处理机制,确保所有可能的错误都被适当地捕获和处理。

在关键地方使用日志记录,便于排查问题。

提供友好的错误信息或恢复机制,确保用户体验。

6. 缺乏测试

问题:代码缺乏单元测试、集成测试或系统测试,可能导致未发现的BUG。

原因:没有在开发过程中进行充分的测试,或者测试覆盖不全。

影响:代码中的错误可能在正式发布后才被发现,增加了后期修复的成本和风险。

解决方案:

在开发过程中使用单元测试框架,如JUnit、pytest等,进行功能验证。

编写全面的测试用例,覆盖各种正常和异常情况。

进行集成测试和系统测试,确保模块之间的协同工作。

7. 不遵循编码规范

问题:代码风格不统一,未遵循团队或行业的编码规范。

原因:开发人员习惯差异,缺乏统一的规范。

影响:不同风格的代码可能造成阅读困难,增加代码审查和维护的成本。

解决方案:

遵循团队或行业标准的编码规范,确保代码风格一致。

使用代码检查工具(如 ESLint、Pylint)自动检测代码风格问题。

定期进行代码审查,确保代码质量。

8. 资源管理不当

问题:代码中对资源(如内存、文件句柄、数据库连接等)的管理不当,可能导致资源泄露。

原因:未能正确释放资源,或者忘记关闭文件、数据库连接等。

影响:系统的资源使用会不断增加,可能导致性能下降,甚至程序崩溃。

解决方案:

在代码中使用适当的资源管理机制,如RAII(资源获取即初始化)或自动内存管理(如垃圾回收)。

对所有资源进行正确的释放,确保资源在不再需要时被及时回收。

使用智能指针或自动管理工具,避免手动管理内存。

9. 安全性问题

问题:代码中存在安全漏洞,可能被恶意攻击利用。

原因:没有采取适当的安全措施,如输入验证、加密、访问控制等。

影响:可能导致数据泄露、系统被入侵或遭受拒绝服务攻击。

解决方案:

采用输入验证、防止SQL注入、跨站脚本(XSS)等常见攻击。

确保密码存储使用加密算法,并采取其他安全措施(如HTTPS、身份验证)。

定期进行安全审计和代码审查,确保系统的安全性。

10. 设计不良

问题:代码的设计不符合SOLID原则等常见的设计原则,导致系统难以扩展和维护。

原因:代码设计过于复杂、缺乏模块化、没有充分考虑可扩展性等。

影响:系统难以应对需求的变化或扩展,维护成本高。

解决方案:

遵循良好的设计原则,如SOLID、DRY(Don't Repeat Yourself)等。

在系统设计时,考虑到未来可能的扩展和变化,避免过度耦合。

11. 缺乏文档

问题:缺乏有效的文档,导致其他开发人员或后续人员难以理解和维护代码。

原因:开发人员在编码过程中忽视了文档的编写。

影响:如果没有文档,其他开发人员在理解和修改代码时可能会产生困难,增加了维护成本。

解决方案:

在开发过程中保持适当的文档,尤其是在复杂的功能模块和算法部分。

编写API文档、架构文档和使用说明,确保团队成员可以快速上手。

试举例说明可靠性(Reliability)和可用性(Availability)的区别。

可靠性:是保证软件的正常,不管输入的数据是合法数据还是非法数据,程序内部都不会毁坏。还是可以完整的运行。

可用性:主要关注在于软件是否可以在正常的条件运行。

区别:两者可靠性关注的点要多一些。可靠性不仅可用,而且还多了一个错误输入时的 处理。

举例:A机器一年坏一次,一次坏一个月;B机器一年坏十次,一次坏10秒。在可靠性上,A机器的可靠性更高。在可用性上,A机器一年可用11个月:B机器一年可用12个月,B机器可用性更高。

可靠性(Reliability)和可用性(Availability)是衡量系统质量的两个重要指标,它们虽然密切相关,但有本质的区别。可靠性指的是系统在特定时间内能够正常运行的能力,换句话说,就是系统在没有发生故障的情况下能够持续工作的时间长度。例如,如果一个电梯在一年内没有出现任何故障,我们可以说它具有很高的可靠性。而可用性则是指系统在任何时候都能为用户提供服务的能力,它不仅考虑到系统正常运行的时间,还包括因故障恢复的时间。举个例子,如果这个电梯虽然一年内总是能正常运行,但一旦发生故障,修复时间较长,导致乘客无法使用,那它的可用性就会受到影响。总的来说,可靠性强调“系统无故障运行”的能力,而可用性则更强调“系统能够随时提供服务”的能力,二者通常相辅相成,但也可以在某些情况下有所差异。

已知输出身高体重函数体定义为:

void print(int params[]){

System.out.println("身高"+params[0]);

System.out.println("体重"+params[1]);

}

试指出其所属耦合类型,并尝试修改代码以降低其耦合程度

答:印记耦合:当被调用的模块可以使用的数据多于真实所需数据时,导致数据访问可能失控,给计算机犯罪提供机会.

解耦:只提供所需要的数据

void print(double height,double weight){

System.out.println("身高"+height);

System.out.printIn("体重"+weight);

}

如何理解“为变更而设计”?

实践表明变更是软件开发面临的最大挑战,也是软件维护成本远高于软件开发成本的主要原因,这就需要在开发阶段就为将来可能的变更进行预设计以减少维护成本,比如根据信息隐藏等思想,封装潜在变更方法以应对变更等。

根据系统功能简介,抽象概念类并确定必要的关系

(1)酒店管理系统用于满足酒店工作人员和管理人员的需求。

(2)酒店管理人员和工作人员可以为酒店房间加入入住和退房记录,并生成相应的报表用于查阅,确认和保存,

   酒店工作人员可以浏览、查询、统计、添加酒店房间的入住离开信息。

管理员可以查询房间信息、查询员工信息、更改房间信息、更改员工信息等。

  (3) 客户在酒店前台申请入住酒店,酒店工作人员需要对客户的姓名、性别、身份证号、房间号、入住时间、联系方式等信息进行记录,客户退房时进行退房记录。

(4)管理员和员工可以通过姓名、入住日期、身份证号、房间号、联系方式等信息查询客户入住和离开情况。

答案:类:员工(姓名、性别、级别、用户名、密码) -- (派生)--酒店管理人员、工作人员    

客户(姓名、性别、身份证号、联系方式)   

客房(房间号、房间类型、房间状态)     

房型(房型、单价)  

入住/离开信息(姓名、身份证号、房间号、入住时间、房间单价、退房时间、房费总额)(关联类)

关系:客户--(入住、离开)--客房    

员工 -- (查询)-- 入住/离开信息

酒店管理人员--(查询/修改)--房间信息

酒店管理人员--(查询/修改)--员工信息

软件测试为什么需要选择不同的方法进行测试设计?

答案:首先,测试对象不同,决定测试使用的方法不同;

其次,测试设计的目的,是为了以最少的测试用例,检测和发现尽可能多的缺陷和错误,使得测试更加经济有效。

用自己的话描述验证与确认的区别,并分别列举2项验证和确认的SQA活动。

答案:验证:我们在正确的构建产品吗?

验证活动:单元测试、集成测试

确认:我们在构建正确的产品吗?

确认活动:文档评审、验收测试

问答题

为何说软件体系结构设计不应依赖于编程机制

软件体系结构设计不应依赖于编程机制,是因为体系结构关注的是系统的高层次设计与组件之间的交互关系,而编程机制主要是具体的实现细节。体系结构设计应该专注于系统的功能需求、模块划分、性能需求和可扩展性等宏观层面的考虑,而不应过早地与特定的编程语言或技术实现绑定。依赖于编程机制可能导致设计的局限性,影响系统的灵活性和可维护性,且随着技术的发展,编程机制的变化可能会导致体系结构需要频繁调整。因此,良好的软件体系结构应该具有抽象性和独立性,能够适应不同的实现技术和平台。

判断下面的代码为高耦合还是低耦合?如果是高耦合,如何降耦?
Public class Sales{
    SalesMapper salesMapper;
    public void endSales(){
        salesMapper.save();
    }
}

public class SalesMapper {
    public void save(){//方法实现}
}

答案:高耦合

设计接口 SalesMapperService

让SalesMapper类实现接口;

让Sales类依赖接口。

该设计改进应用了针对接口编程原则和DIP(依赖倒置)原则。

试题解析:详细解析见课本P255

软件测试要执行那些活动,请加以描述。

答案:测试计划、测试设计、测试执行和测试评价。

测试计划:在开始具体的软件测试活动之前,必须明确软件测试的工作范围、资源与成本、基本策略、进度安排等。

测试设计:是软件测试的关键阶段,目标是进一步明确需要被测试的对象,为被测对象设计测试用例集合。

测试执行:严格按照测试用例执行测试,并记录测试结果。

测试评价:测试执行结束后,必须评价测试结果,以确定测试是否成功。

试题解析:课本P331-332,注意顺序和目的。

请解释Verification &Validation的区别。

答案:Verification为验证,目的是检查开发者是否正确地使用技术建立系统,确保系统能够在预期的环境中按照技术要求正确的运行。其侧重验证活动。

Validation为确认,目的是检查开发者是否建立了正确的系统,确保最终产品符合规格。其侧重确认目标。

试题解析:课本P320,但务必理解其不同之处。

SWEBOK(软件工程知识体系)定义的软件工程包括的知识领域有哪些

SWEBOK第二版定义软件工程有10个知识领域,分别是:软件需求、软件设计、软件构造、软件测试、软件维护、软件配置管理、软件工程管理、软件工程过程、软件工程工具和方法、软件质量;

SWEBOK第三版定义了另外5个知识领域,分别是:软件工程职业实践、工程经济学基础、计算基础、数学基础、工程基础。

试题解析:课本P381

论述题

最好的方案能够得到的好处肯定不会低于足够好的方案,那人们为什么不追求最好的方案?试着举例说明你的观点。

答案:追求最好的方案意味着高代价(时间、成本),成功的软件工程项目是要在有限的时间和成本内,得到高质量的目标软件,因此软件工程追求的是成本效益比有效,而不是最好。

比如:对软件测试来说,追求“最好”即达到零缺陷,但为了证明零缺陷,需要进行穷举测试,这往往要付出几千年甚至更久的代价,超出了工程项目的时间和成本限制,通常无法实现。

因此,人们在软件测试时,通常选择在有限时间内完成尽可能高的覆盖率(足够好)即可。

软件测试为软件质量的评估提供了最后堡垒,因此要将软件测试看作捕捉和发现各种错误的安全网。对此说法,你认为是否正确?为什么?

答案:软件测试是质量保障的重要方法之一,但软件质量不仅是在测试这一个阶段形成的,在软件工程的整个过程中,质量已经被包含在软件之中了。因此应该在整个软件过程中注重质量和错误检测,而不是由软件测试一个阶段来捕获和发现全部的错误。

;