[BUAA2024OOU3] 勾 挨慕 挨要

测试过程

黑箱测试与白箱测试

黑箱测试是一种在只知道产品功能而不了解内部结构的基础上进行的功能检测。黑箱测试不关心程序的内部实现,只关心程序的外部规格,程序能否根据输入得到满足限制的输出。白箱测试则相反,白箱测试更着重于程序内部的工作过程,通过测试来检测产品内部的动作是否按照原定的意图进行,而并不着重关心程序的目的。

两种测试的方法各有优劣。黑箱测试更加抽象,把程序由输入输出抽取出抽象借口,无论程序由何种方法实现,只要能达到目的即可,但是程序的可能输入无法穷尽,可能会出现难以探查的错误。白箱测试更加具体,测试程序内部的每个动作每个分支,但是这样的测试有失整体性。

在本单元的测试中,JML由于其描述特性,更像是一种黑箱测试。在完成作业时,由于代码也由我们自己编写,我们了解代码的实现。我们可以结合黑箱测试和白箱测试,达到更好的测试效果。

单元测试、功能测试、集成测试、压力测试、回归测试

单元测试

单元测试是针对代码的最小单位进行的测试,可以更细致地探查代码的可靠性。

功能测试

功能测试正如其名着重于功能,使用各种样例测试各个模块的功能是否达到要求。

集成测试

将各个模块一起进行测试,验证耦合后模块之间是否能正常交互。

压力测试

测试程序在高压力高负载下能否正确并以可接受的性能运行

回归测试

在迭代变更之后,重新测试之前测试过的功能,以确保迭代不会影响已经完成的部分。

各类测试的结合

我们的作业中的Junit要求是一种功能测试。我们的作业中,单元测试可用于发现bug后的调试;集成测试由于作业代码的耦合性不高,可以不着重考虑;压力测试由于性能要求比较高,许多同学的时限都卡的比较紧,有必要充分压力测试;为了防止迭代修改原有功能,回归测试也有必要进行。

数据构造策略

通过本单元的三次Junit测试单元书写中,我总结了以下一些经验。

  • 根据代码涉及到的各个部分各个限制编写测试数据,有目的性的数据比随机数据远更有用

  • 需要一定的规模。手动构造的小数据测试出所有bug的可能性自然不如大数据

  • 需要足够多的样例数目。5个样例的强度自然远不如300个样例

迭代、架构与性能

hw9

需求

本次作业主要需要实现图加删边点,查询连通性,连通块数量,三元环数量。

实现与优化

为了方便查询,图中的点和点中的边都适用id向点映射的HashMap存储。

本次作业主要的选择在于如何实现动态删加边并查询连通性。一般有两种方法:要么删加边点直接处理,查询的时候进行搜索;要么用并查集维护,删除重新建立并查集,查询直接回答。我注意到有删边操作,认为这是课题组不希望我们使用并查集的暗示,所以采用了搜索。后续测试时,我发现性能不佳,压力测试大概要跑10s左右。因此我使用了一种并查集和搜索结合的方案:bfs时记录一棵生成树,当且仅当删除到了树边才重新搜索,其余情况都快速维护。这样效果很好,本地测试最高不超过1s,实际强测最慢2.2s。最后对于询问三元环数量,可以在每次加边时枚举所有人,检查新增的三元环,这样回答可以立即回答。

上述过程中还可以进行很多小优化。包括:

  • 尽可能的记忆化答案,当不得不重新计算时invalidate这些预计算值

  • 一旦有类似枚举两个集合的交集(例如求加边求新增三元环数量)这样的操作时,for循环枚举使用更小的那个集合

  • bfs使用反图bfs技巧,bfs过程中维护没有被bfs到的点,点从队头取出并更新时使用边集和未bfs到的集合中较小的那个枚举

hw10

需求

新增需求主要是给每个人头顶放上了tag,tag可以维护这个人相连的人的子集。需要实现有关tag的一些询问,如查询tag内年龄均值方差、内部边权和等。还新增了bestAcquaintance概念,每个人编号最小的边权最大者是他的bestAcquaintance,需要实现询问有多少对人互为对方的bestAcquaintance。

实现与优化

与hw9类似,tag和tag中的人都用HashMap存储,便于高效增删查。tag中的查询可以通过预计算快速实现:年龄的均值方差可以用数学方法展开简单维护快速回答,内部边权和可以加入新人的时候更新。需要注意的是,修改边权的时候需要枚举可能涉及的所有tag更新。对于bestAcquaintance,仍是根据以上尽可能记忆化的原则,加入人时更新,删除人是如果必要重新枚举计算。也可以使用TreeMap或者堆维护tag中的人,但没必要。询问有多少对人互为bestAcquaintance时候,可以枚举所有人,记录bestAcquaintance,然后扫一遍回答。通过以上方法,所有操作的复杂度不涉及边的枚举,与hw9中的搜索相比不会成为复杂度瓶颈。

hw11

需求

新加入了几种message,并需要简单的维护。

实现与优化

hw11的强度是三次作业中最小的。新加入的内容几乎没有任何复杂度问题,只需要简单按照题意实现即可。难点可能在与JML比较长难以阅读。要克服这一点,我认为重点在于理解每个ensure的目的在何。这样自己的理解与JML快速互相验证,对理解很有帮助。实际上,很多很长的JML写出代码来很短。

规格与实现分离

根据前人的博客,规格与实现分离是指在软件开发过程中,将软件的需求规格和实现代码分开处理,使得两者的修改互相独立,从而提高软件的可维护性和可重用性。

根据我的理解,这就是说JML标明软件要做什么,他不关心我们怎么实现。事实上,使用我们写的代码的上层程序员也不关心我们要做什么。这有点像计算机架构中,各个部件各司其职,只互相关心别人能不能完成他们该做的,他们内部的电路结构并不重要。这种分立的架构不仅方便测试,可以直接检验规格是否被满足;可作为一种通用的耦合协议,供所有使用这份代码,包括调用者和编写者沟通交流;可方便优化,上层优化上层,内部优化内部,互不干扰。

Junit

按照我三次作业的经验,Junit编写原则只有两句话:

  • 显式ensure直接检查满足

  • not_assigned类手动全部复制并前后比对

只要做到这两点,测试部分就绝对不会出问题。只需要在数据生成上下功夫就行了。

心得体会

感觉这个单元只有第二单元的二分之一甚至三分之一,算是小小的放了个假然而隔壁OS强度又起来了所以还是红温

JML一直被吐槽为没啥用,不如白话文一根,然而我觉的助教的JML手册中说的很对,总有自然语言说不清的东西。在高要求的一些场景之下,JML就有其独特的必要性。JML以描述性判断为主的特点带来了很多好处,个人认为最大的优点就是抽象。就像很多行业的分工一样,不需要在意下层是如何实现的,只需要关心他能干什么。这是当项目规模变大之后不可或缺的。

整个作业做下来感觉还是不错,没有遇到什么挑战,三次强测三次互测也是以0rejected0hacked收尾,还是比较满意的。希望最后的第四单元也能如此顺利。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值