文章目录
一、本单元测试过程
1. 黑箱测试和白箱测试
黑箱测试
- 定义: 这种测试方法关注软件系统的外部行为和功能,而不考虑内部实现细节。测试人员基于需求和功能说明来设计测试用例,主要检查软件的输入输出。
- 优点:
- 无需了解代码内部实现,测试人员可以是非技术人员。
- 更加关注用户需求和功能完整性。
- 缺点:
- 难以覆盖所有可能的输入输出组合。
- 可能无法发现一些隐藏的逻辑错误和异常情况。
白箱测试
- 定义: 这种测试方法关注软件系统的内部结构和逻辑。测试人员需要了解代码的内部工作原理,测试目标包括代码覆盖率、分支覆盖率等。
- 优点:
- 可以通过测试代码的每个路径,有效地发现和修复逻辑错误。
- 可验证代码实现是否符合设计预期。
- 缺点:
- 对测试人员的技术要求较高。
- 测试覆盖范围可能有限,难以评估非技术方面的问题。
2. 单元测试、功能测试、集成测试、压力测试、回归测试的理解
单元测试
- 定义: 主要测试代码中的最小可测试组件(例如,方法或类)的功能是否正确。通常由开发人员编写和执行,使用如JUnit的测试框架。
- 目的: 确保每个组件单独工作正常。
- 特点:
- 测试范围最小,针对具体的代码逻辑。
- 快速发现和定位问题。
功能测试
- 定义: 测试系统根据需求规格说明书进行的功能,通常是黑箱测试的一部分。它们验证软件是否按照预期功能工作。
- 目的: 确保系统实现了所有预期的功能。
- 特点:
- 直接基于需求和设计文档编写测试用例。
- 不关注内在实现,重点在于功能正确性。
集成测试
- 定义: 测试多个模块或组件之间的接口和交互,确保它们组合后功能正确。包括部分集成(子系统内)和系统集成(整个系统)。
- 目的: 发现组件之间交互的问题,如数据传递和控制流问题。
- 特点:
- 测试范围比单元测试大,跨越多个模块。
- 可能涉及模拟接口和依赖项。
压力测试
- 定义: 测试系统在极端条件下(高负载、大量数据等)的表现,观察其稳定性和性能。
- 目的: 确保系统在超负载时的健壮性和可用性。
- 特点:
- 模拟高用户量或资源消耗场景。
- 测试系统在异常情况下的响应和恢复能力。
回归测试
- 定义: 在软件修复或升级之后,重新运行先前通过的测试用例,确保改动未引入新的错误。
- 目的: 确保新代码的引入没有破坏现有功能。
- 特点:
- 通常在修改代码之后自动化执行。
- 重点在于验证旧功能在新版本中的正确性。
3. 数据构造策略
构造大规模数据
- 构造体量极大的数据,依靠大体量下的大随机测试bug。
构造边际数据
- 构造会频繁触发边际条件的数据,测试极端情况下是否会发生异常。
构造压力数据
- 针对某一特殊情况使用大量重复命令堆叠出数据,测试极端情况下是否会发生超时等情况。
二、架构设计
1. 图模型构建
在Person中用HashMap存储邻居,key是邻居的id,value是邻居的引用。Network中同理,采用该容器可以有效地提升访问效率。
图本身的结构则完全依靠Person的邻居存储。得益于HashMap的复杂度,该方式每次访问一个邻居都是常数级别的,在时间复杂度上没有问题。
对于每次作业提出的新指令,都专门进行实现,大概流程是:添加新的容器,设计并添加新的类,在Network中支持新的方法。本次作业大部分指令朴素实现即可, O ( n ) O(n) O(n)的时间复杂度不会导致强测GG。
2. 图维护策略
暴力美学——对每个针对图的修改,都直接执行,无需任何优化。强测的结果证明这种方式并不会影响评测。
三、性能问题及修复与规格和实现分离
1. 性能问题及修复
本次作业中未出现性能问题。观察可以发现,本次作业中 O ( n ) O(n) O(n)的复杂度即可通过强测,而只要妥善设计,朴素方法都能通过强测,又没有性能分,无需费心考虑额外的优化。事实上,只需要把每个指令的朴素思路写出来,基本都不会超时。此处的基本仅用来表示严谨。
2. 规格和实现分离
规格
规格是关于软件系统、模块或功能的详细描述,它定义了系统应具有的行为、性能和其他属性。规格通常以文档、需求说明书、以及合同等形式存在。其目的是提供清晰、可验证的标准,以确保所有利益相关方(如开发人员、测试人员和客户)对系统要求的认知一致。作为开发和测试的基础,确保系统实现满足预期的业务需求和规范。
实现
实现是根据规格来编写代码,使系统具备规格中所描述的功能和特性。实现涉及具体的编程、算法设计、数据结构选择和系统集成等。目的:将规格需求转化为具体的、可执行的软件产品。通过编码实现系统的业务逻辑、用户界面和后端处理。
规格与实现分离的重要性
- 清晰的需求界定: 分离规格与实现可以使需求和设计变得更加明确,并且便于利益相关者在实现前对需求进行审查和验证。
- 提升开发灵活性: 开发人员可以根据经过确认的规格自由选择合适的设计模式和技术栈,而不必担心需求临时变更带来的影响。
- 改善测试和维护: 测试和维护团队可以依据规格来验证和维护系统,而不必研究具体的实现代码,这有助于减少错误和提高工作效率。
- 减少知识传递障碍: 不同团队(如需求分析团队、开发团队和测试团队)的工作可以基于规格这一共同语言进行,从而简化沟通和协作过程。
四、更好的设计和实现JUnit测试与Junit测试代码与规格一致性的效果
1. 利用规格信息更好的设计实现Junit测试
测试用例设计
规格能够指导测试用例的设计。从规格中提取功能需求,设计测试用例确保每个功能点都被覆盖。例如,根据用例图、用例描述和用户故事生成测试用例。同时,根据规格中的输入范围和条件可以设计边界值测试,以确保系统在极端和临界条件下的表现。
预期结果
规格还能指导每个测试用例的预期结果。这不仅包括正常情况,还包括异常情况和错误消息。不过对于本单元,似乎并未考察Junit验证方法返回的异常。
Junit检验代码实现与规格一致性的效果
我在本单元中,采用类似数据生成器的思路,让Junit在运行时临时生成多组符合规格的数据来测试代码。在实践中,该方法能够较为全面的覆盖多种数据情况,测试出来各种各样的bug。
五、本单元学习体会
在本单元中,我学习了以JML为例的规格化编程,这和之前两个Unit有着很大的区别。不过,本单元对图论的要求浅尝辄止,令人可惜。总而言之,在本单元中我学习到了规格化编程的思想, 并略微温习了一些图论的知识。
本单元整体难度不大——在读懂题目后。本单元中,大部分指令并未发挥JML的威力,(个人认为,个人认为)很多指令用JML描述反而是画蛇添足,只有寥寥几个指令才有了点规格化设计的味道。