契约——BUAA_OO_Unit3

契约——BUAA_OO_Unit3

1. 前言

第三单元的时间是一个学期的第九周到第十二周,恰好也是一个学期最忙的时候,操作系统的难度有了较大的提升,冯如杯的答辩准备,准备航概考试的刷题,各种学校的学院的活动纷至沓来,让生活和人都处在一个些许混乱的状态。

这段时间,写写代码倒成了一种忙里偷闲了。

相比前两个单元的自我感觉良好的“洋洋洒洒”,第三单元的总结就按照课程的博客作业要求写吧。

  • 分析本单元的测试过程
    • 谈谈你对黑箱测试、白箱测试的理解
    • 对单元测试、功能测试、集成测试、压力测试、回归测试的理解
    • 数据构造有何策略
  • 梳理本单元的架构设计,分析自己的图模型构建和维护策略
  • 分析作业中出现的性能问题及其修复情况,谈谈自己对规格与实现分离的理解
  • 本单元中同学们实现了Junit测试方法,总结分析如何利用规格信息来更好的设计实现Junit测试,以及Junit测试/检验/代码实现/与/规格/的一致性/的效果(这个要求的断句确实有点难)
  • 本单元学习体会

2. 测试

2.1 黑箱测试

黑箱测试是将程序作为一个封装好“输入输出机器”。测试者不了解程序的内部情况,不了解具体的实现代码。只知道程序的输入输出方式和程序的预期功能。测试者通过给定特定的输入,观察是否有期望的输出,以判断功能实现是否存在问题。从程序设计课程以来各课程学习中的各式测评机就是典型的黑箱测试。

黑箱测试也是从用户角度针对软件进行测试,因为用户也是不关注程序的内部情况。同时黑箱测试可以让功能实现和程序测试在很大程度上分离,避免惯性思维导致测试不够全面。

2.2 白箱测试

与黑箱测试相反。测试者了解测试程序的数据结构、算法等具体实现信息,从程序实现的角度对程序进行的测试。测试者通过给定特定的输入,观察程序各语句的执行结果、各分支跳转等是否符合预期。通过黑箱测试找到了引发问题的输入之后寻找程序错误的过程就是典型的白箱测试。

白箱测试主要由开发者执行。因为要基于开发者对于自己程序的理解,输入的数据通常有特定目的。

白箱测试的重要指标是测试的覆盖率,如覆盖多少代码行、函数、分支等。但是,全部覆盖也不能完全证明其可靠,仍有可能是因为测试的输入并不会引发问题。

2.3 单元测试

单元测试是一种自下而上的测试方法。针对程序设计当中的最小单位,如函数、方法等进行测试,以确定程序中的各最小单元是符合预期的。这种测试主要通过白箱测试完成。

通过完备的单元测试后,若在更大颗粒度的测试当中发现了问题,至少可以认定更小的程序设计单位没有问题,问题应当出现在这些更小的程序设计单位的交互中,有助于降低后续发现和修正问题的成本。

2.4 功能测试

功能测试是验证程序实现能否满足需求规格说明书中所定义的各项功能要求。测试的重点包括规定的输入边界情况等。这种测试主要通过黑箱测试完成,人工设计相关的输入的测试效率会比完全随机生成输入要高。

2.5 集成测试

集成测试通常在单元测试之后进行。在认定更小的程序单位没有问题后,重点测试其间合作交互是否正常,以发现模块间接口和信息交换的缺陷。对于main的测试就可认为是一种颗粒度很大的集成测试。

2.6 压力测试

压力测试的主要目的是验证程序实现能否满足需求规格说明书中所定义的各项性能要求。测试的重点是在当前程序实现的情况下时间复杂度和空间复杂度的极大情况。对于可能存在并发的场景,并发数也是压力测试的重要指标。

2.7 回归测试

回归测试主要测试软件原先已经实现的功能在软件被进一步修改之后是否保持正确,没有因为新增功能或者后续修改产生意外的副作用。

2.8 数据构造

测试数据的构造主要采取广泛的随机构造以覆盖绝大多数可能的情况。对于边界数据和压力数据,采用人工构造的效率会更高一些。

3. 架构

3.1 架构设计

本单元架构设计的重要性并不如前两个单元突出。架构设计也较为简单。

对于异常,每个异常根据其接口的要求实现即可。

主体部分的核心是MyNetwork,其中有Graph用于通过并查集维护图模型、Triple用于维护三角形关系,TagRepo用于保存各Tag的引用以实现对于Tag中的valueSum的维护。MyNetwork中还有personsmessages用于保存各person和message。

在这里插入图片描述

3.2 图模型构建与维护

图模型采用并查集实现,实现了按秩合并、完全路径压缩。考虑到person的id范围为整型,故不能采用数组而采用HashMap。

并查集本身没有考虑关系删除的情况,故删除关系时需要重新构建并查集。Graph中将所有person之间的关系都用HashMap保存了。若遇到了删除关系的情况,先在HashMap中进行记录,并将当前的并查集记为失效的。直到下次需要查询由并查集得到的数据时才重建。避免重建并查集这个很重的操作被反复执行。

得益于Graph中将所有person之间的关系都用HashMap保存了。求解最短路径时可以方便地采用Dijkstra,计算的结果也要进行缓存,避免反复查询时反复计算。

对于三角形关系,只需要维护其数量。在增加两个人之间的关系时,对于这个新关系涉及的两个人A和B,和与A有关系并且与B有关系的人C,将构成A-B-C-的三角形关系。增加的三角形关系的数量就是满足条件的C的数量。也就是与A有关系的人和与B有关系的人的交集的大小。恰好,Java中的Set提供了retainAll()这一方便求交集的方法。删除关系的时候是类似的。

4. 性能

三次作业中遇到的性能问题有两个。

第一个问题是queryCoupleSum()。第一次实现时,考虑到JML中采用了两个临时变量ij并且有i < j的循环条件,我便下意识地用了两层for循环处理。实际上一层for循环,判断一个人的bestAcquaintance的bestAcquaintance是不是这个人即可。此处的JML的要求只是不重复计算couple的数量。

第二个问题是getValueSum()。第一次实现时,每次调用该函数时都使用两层for循环进行计算。这在反复查询时效率非常低,应当动态维护。对于在Tag中增加人、删除人时的动态维护比较简单。但是因为一个关系可以在多个属于不同的人的Tag中存在,故使用TagRepo保存所有的Tag的引用。有对关系的增删改时,调用各保存的Tag的引用的更新方法即可。因为Tag的id只保证对于人唯一,不保证在全局唯一,遇到删除指令时,保存的Tag的引用不必耗费大量的时间查找并删除,因为之后的任何指令也不可能查询到这个Tag的信息了。

规格与实现分离,规格更加关注于正确性,性能要求交给实现者。有助于将程序开发的不同任务分给能力不同的人。一方面有助于保证程序实现符合需求规格说明书,一方面有助于提高程序开发的效率,一方面也能很好地指导测试工作。

5. JUnit

规格信息是对于测试工作的很好的指导。利用规格信息实现JUnit测试要关注以下几点:

  1. 如果涉及到执行前的状态(\old),要注意独立地保存先前的状态。一个简单的方法是生成数据时同时生成一份深拷贝(执行每个操作都独立地执行两次)。
  2. 要注意的对于pure的测试。
  3. 有多个normal_behavior时要注意判断,分别测试不同的情况。
  4. 一定要覆盖JML的各项ensures。

当然,想要通过JUnit检验出代码实现与规格不一致还要靠构造的输入数据。一般情况下,随机构造的数据就能有效地检查出绝大多数问题。对于边界的、极端的数据还是要手动构造。

6. 学习体会

契约式编程是一种全新的编程方式,在requires和ensures中,开发者之间的合作更加高效,不同的程序模块之间的合作也更加清晰。使用形式化的语言,也能更为严谨地描述需求,有助于提高程序的正确性。

然而,第三单元给我的最基本的感受就是混乱。在此也给课程组提一点建议:

  1. 明确单元定位:第三单元的标题是面向对象JML系列,期望的教学内容是规格化设计、契约式编程。但是当同学们完成作业超过一半的时间都在思考用什么算法,交上去还在担心性能问题时,或许可以在一定程度说明第三单元的引导结果与课程初衷已有偏差,并且期望的教学内容又没有充分练习。学习规格化设计、学习性能优化都是需要的,明确了定位,相信能取得很好的效果。
  2. 优化指导书:JML的最大优势就是严谨,避免歧义。然而由于其不完善性(甚至其标准中仍余大量TODO),导致在指导书中不得不存在用自然语言表述的内容。然而部分内容却有失严谨性,如“独一无二”、“根据异常名理解”。或许可以贯彻到底都用形式化语言的描述,但至少也要减少意会。例如:在程序运行的任一时刻,对于每个Person,其中的所有Tag的id不存在重复。同时三次作业的JML,都有在作业发布后修正的情况,个别修正甚至影响语义,难免会让同学们觉得JML非常不便甚至不如自然语言了,很多同学都觉得作业发布了不如等等修正。还请在发布作业前仔细验题。
  3. 优化课程组织:前两次作业结束之后,很多同学都有反映对于性能评测的疑惑,并且重测的结果确实修正了错误。性能评测没有明确的评测环境说明,没有可供实验的测试环境,没有实时反馈是同学们反馈的主要问题。性能评测可以作为中测的特殊测试点存在并调高中测的分数,可以提供检验的环境,评测时也可以降低并发数以贴近实验环境。不必所有的单元都板板正正按照同一个评测模式。希望改进之后的性能评测,能让更多同学接受和信任。

相信第三单元的未来会定位更为明确,题面更为清晰,组织更为有序,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值