301
社区成员
发帖
与我相关
我的任务
分享黑箱测试:从使用者的角度测试,检验程序能否满足指定的接口、功能
白箱测试:在已知内部结构的前提下进行测试,检查程序内部实现是否满足要求,如在知道某个方法的内部实现是三重遍历后检查其是否满足时间需求。
举个互测的通俗例子来讲,将房友的程序打包成 jar 跑一遍评测机的随机数据就是黑箱测试,阅读房友的代码之后根据其实现构造针对性的测试用例便是白箱测试。
单元测试:对内部的一个“单元”进行测试,比如对复杂方法 deleteCodeEmoji 进行测试。在 Java 中可以采用 JUnit 的测试方法,在
功能测试:也是一种黑箱测试,测试软件能否满足文档的功能说明
集成测试:对软件的不同模块一并进行测试
压力测试:在极端情况下测试软件的功能,又能分为大量数据造成高负载带来的压力和极端数据带来的压力两种。后者典型的例子是非正 id
回归测试:对软件进行更改之后,确保已经实现的功能仍然有效。在我们的作业中可以理解为使用前一次作业的数据对后一次作业的程序进行测试,同时,在 Bug 修复环节,需要通过之前所有的测试点才能提交修复也是一种回归测试。
本单元的输出具有唯一性文本的特征,故主要的测试策略分为多人对拍和采用暴力方法实现满足规格的评测机两种。
数据构造的策略主要是对单条指令的压力测试和大规模集中测试,类似强测的实现策略。
具体而言,我在实践中采用了如下三个步骤:
构建评测机
手动构造数据以提高图的稠密程度或增加对某个操作的压力
增大总的数据规模,如比课程组的限制条数更多以增加测试强度
在图模型设计方面,Network 视为以 Person 为结点,Person 间关系为边权值的图。需要注意的是,2024 年的作业中,Tag 是附属于 Person 的属性,故图模型仅有一层。对于图模型的构建和维护,采取 addPerson 增加结点,addRelation 增加边,而 modifyRelation 修改边权值或删边。单纯图模型的构建和维护较易理解,但为保证程序的运行效率,需要进行后续优化,如修改数据结构、增加字段动态维护变量值等。
事实上,存储熟人的设计是邻接表存储图
将所有按 id 查询而不强制要求次序的存储容器都改为 HashMap 实现,如 persons、tags、emojiHeat 等
用并查集维护连通块,删边时重建并查集或采用可撤销并查集数据结构
计算 ageMean、ageVar、valueSum 时,动态维护变量 ageSum、ageSquareSum 和 valueSum
用双向 BFS 查找最短路径所经过的点数
在需要查询时才重建并查集,采取一种 lazy 的策略
第二次作业中未实现 queryValueSum 方法中对 valueSum 的动态维护,喜提 CTLE。 ()
于是我在 modifyRelation 时,对两人共同熟人的所有 Tag 遍历修改维护 valueSum,解决了此性能问题。
此外还有未动态维护三元环计数的潜在性能问题。
本单元中规格与实现分离的体现在于:规格描述一种确定的方法,相当于描述了一种性能最差但是保证正确的实现方式。而我们的实现相当于优化这种最基础的实现方式,并保证这种优化不会带来副作用(即违背前置条件、后置条件,或改变对象内容等)。如将所有的次序无关的容器都改写为 HashMap ,将 EmojiList 和 EmojiHeatList合并为一个 HashMap。或者可以理解为甲方提出规格,给出相应的要求;我们作为乙方的实现者,只需让程序满足甲方提出的接口即可,具体的实现可以根据性能和实现难易程度做出优化。
事实上,JML 可以理解为一种对接口的约束而非推荐实现方式,编程者需要阅读规格理解需求,并采取优化策略提升程序的性能。
经过第三单元”规格指导的层次化设计“学习后,我对”规格是用于规范关键方法的实现“这一理论有了更加深刻的认识,
在实际的软件开发中,可能并不需要对每个方法都大费周章,设计如此详细繁杂的规格,但对于关键方法,需要严格满足规格的要求,以保证软件的质量。