2024-BUAA-OO Unit 3 单元总结

分析本单元的测试过程

黑箱测试与白箱测试
  • 黑箱测试
    • 黑箱测试关注软件的外部,是一种不考虑内部实现的测试方法。测试人员在进行测试时,只关注输入和输出,不关心程序内部的结构和实现细节。
    • 优点:测试人员未必要懂得代码的内部实现,更加关注用户需求和软件功能的完整性。
    • 缺点:有些时候难以覆盖全部情况,难免出现疏漏。
  • 白箱测试
    • 白箱测试,又称结构测试,是一种基于内部实现的测试方法。测试人员需要了解和使用程序的源代码,通过分析代码逻辑进行测试。
    • 优点:可以进行详细的代码检查,发现潜在的逻辑错误和漏洞。可以发现非功能性问题,如性能瓶颈、内存泄漏等。
    • 缺点:需要较高的技术水平和对代码的深入理解,测试用例编写复杂且耗时。难以站在用户的角度发现功能性缺陷。
对单元测试、功能测试、集成测试、压力测试、回归测试的理解
  • 单元测试

    • 单元测试是对软件中最小可测试部分(我们这里通常是一个方法)的验证,确保其按预期功能工作。本单元使用的Junit就是一种常用的单元测试。

    • 目的:验证单个模块或组件的正确性。

    • 测试方法:通常由开发人员编写测试用例,使用断言检查单元方法的输出是否符合预期。

    • 优点:发现和修复单个功能的错误早期,便于快速定位问题。

    • 缺点:不能发现模块之间的集成问题。

  • 功能测试

    • 功能测试主要验证软件系统是否按需求和规格说明书实现功能。通常是黑箱测试的一个部分。

    • 目的:确保软件的整体功能性需求得到满足。

    • 测试方法:通过模拟用户操作,检查系统的功能点,如输入验证等。本单元主要是直接进行输入,检验输出的正确性。

    • 优点:直接从用户角度验证系统功能,确保功能需求实现。不依赖内部代码实现,只关注外部行为。

    • 缺点:和黑箱测试一样难以发现性能瓶颈,同时也可能存在覆盖率不够的情况。

  • 集成测试

    • 集成测试主要验证多个模块或组件组合在一起后的行为和交互(包括系统整体的组合),确保它们组合后功能正确。

    • 目的:确保不同模块之间正确交互,系统整体功能正常。

    • 测试方法:测试不同模块的接口和交互,确保数据流和控制流的正确性。

    • 优点:能够发现模块之间接口和交互的错误,同时验证系统架构的正确性。比单元测试覆盖率高。

    • 缺点:复杂度较高,特别是在大型系统中,需要协调不同模块的开发和测试计划。

  • 压力测试

    • 压力测试是验证系统在高负载、极端条件下的性能和稳定性。
    • 目的:评估系统在超出正常工作负载情况下的表现和处理能力。
    • 测试方法:模拟高并发用户访问、大数据量处理、资源争用等场景,观察系统响应和行为。(大数据量处理如第一单元和第三单元,高并发如第二单元)
    • 优点:能够识别系统在极端条件下的瓶颈和弱点,帮助改进系统的鲁棒性和可靠性。
    • 缺点:需要复杂的测试环境和负载模拟。测试结果需要长时间分析,才能找出性能瓶颈所在。
  • 回归测试

    • 回归测试主要验证修改或更新后的系统仍然保持原有功能正常。
    • 目的:确保新代码的修改或新增功能未引入新的错误。
    • 测试方法:重复执行之前的测试用例,尤其是修改部分和其影响范围内的功能。
    • 优点:确保系统在持续迭代和更新过程中保持稳定。能够比较高效检测因修改引入的潜在错误。
    • 缺点:测试用例和测试脚本维护成本较高。
数据构造有何策略
构造大规模数据

构造大量指令,比如说接近甚至超过强测极限的指令条数,以这种方式来增加测试用例的覆盖性,大数据量情况下,能够比较好地测试出程序的功能实现情况和性能情况。

构造回归数据

根据上次构造数据进行测试。

构造压力数据

对某一类型指令进行大量重复,用以检验程序在某一方面的性能问题。

构造极端数据

构造在规定范围内的极端数据,比如说intMin - intMax,在这种情况下,通过直接相减判断大小的方法就会出现正确性错误。

本单元的架构设计

图模型构建

JML中的要求几乎一致,在Person中用HashMap存储邻居,key是邻居的id,value是邻居的Person引用。Network中同理,对于Tag中的存储,也是类似的,采用该容器可以有效地提升查找效率。对于联通性的存储,采用了基于路径压缩和按秩合并的并查集,在边修改和增加时候维护并查集。

事实上,这就是基于点集和相邻边维护的一个朴素图模型,采用边集维护的话,在逻辑上可能有一定难度

维护策略

对比较大量的属性进行了动态维护,下面举几个例子。

ValueSum:增加边时候增加即可。

AgeVar:存储年龄平方和,计算方差并维护。

TagValueSum:在Tag中增加人,删除人,增加边时候进行修改。

BestAquantance:朴素维护一个最大值即可。

CoupleSum:在每次边修改时,检查是否有BestAquantance的修改,如果有,就对六个点(边的端点和新旧Couple)进行检查并修改当前的CoupleSum

性能问题、规格与实现分离的理解

作业中出现的性能问题及其修复情况

本单元作业中没有出现性能问题,这主要归功于数据结构的选择和比较大量的动态维护,(但是出现了严重的正确性问题,还是测试太少了),观察强测情况,可以发现在本单元的性能要求中,O(n)的时间复杂度是可以接受的,那么我们只要注意不要出现O(n^2)级别的方法即可,主要需要注意ValueSumTagValueSumCoupleSum这些直接按照JML写会超时的方法即可。

对规格与实现分离的理解

规格与实现分离是软件工程中的一种设计原则,旨在将系统的功能需求(规格)与其具体实现细节(实现)区分开来。这种分离带来了更好的模块化、灵活性和可维护性。

  • 规格

    规格是对软件系统或组件所需功能和行为的描述,不涉及具体实现细节。规格通常包括以下内容:

    • 功能需求:系统应具备的功能和特性,如输入输出行为、业务逻辑、用户交互等。在本单元中可以理解为各条指令。
    • 非功能需求:性能要求、安全性、可用性、兼容性等。这一单元就是性能需求。
    • 接口定义:组件之间的交互方式和数据格式,包括API、协议等。本单元可以认为是com中的各个接口限制。

    规格通常独立于实现描述了“是什么”而非“如何做”,关注系统的功能和行为。是以用户导向驱动的,面向最终用户和系统的交互者。

  • 实现

    实现是根据规格对系统功能的具体实现细节,包括编码、算法、数据结构等。

    实现通常是细节导向的,就是说实现要关注系统内部如何运作,关注代码、算法和数据处理。

  • 规格与实现分离

  1. 提高模块化和可维护性:

    • 通过清晰定义规格和接口,各个模块可以独立开发和测试。
    • 修改实现时,只要不改变规格和接口,其他模块不受影响,提高了系统的可维护性和灵活性。
  2. 增强系统的可测试性:

    • 测试可以基于规格进行设计和执行,确保功能需求的正确实现。

    • 实现可以进行单元测试,确保代码逻辑的正确性。

  3. 实现方式:

    • 通过明确的接口,将模块之间的交互方式标准化。例如,接口和抽象类。
    • 基于规格的自动化测试用例,验证系统功能和行为是否符合需求。

Junit测试方法的理解

如何利用规格信息来更好的设计实现Junit测试
  • 理解和整理规格信息

    • 明确系统或组件应具备的功能和特性。
    • 明确性能要求、安全性、可用性等。
    • 明确方法的输入参数、返回值、异常情况等。
  • 设计合适的测试数据

    • 能够比较全面地进行功能测试,确保每个功能点都被覆盖。
    • 根据规格中的输入范围和条件可以设计边界值测试,以确保系统在极端和临界条件下的表现。
Junit测试检验代码实现与规格的一致性的效果

Junit测试中,采用类似Python数据生成器的思路,让Junit在运行时生成多组符合规格的数据来测试代码。能够起到和整体功能测试类似的效果。

本单元学习体会

在本单元中,我学习了以JML为例的规格化编程,这和之前两个Unit有着很大的区别。本单元对于架构设计没有要求,对于算法部分要求也比较简单,在本单元中我重点体会到了规格化编程的思想。

本单元整体难度不大,然而我却在作业中出现了比较严重的正确性错误,在强测中损失了部分分数,主要还是在第一单元和第二单元结束后松懈了,本单元没能够进行比较充分的测试导致的。正印证了那句“业精于勤”。

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值