BUAA-2024春-OO-Unit3总结

1 测试过程

1.1 黑箱测试与白箱测试

黑箱测试

基于功能需求,不关心内部实现逻辑的测试方式。它通常对功能模块的输入输出进行测试,无需了解代码细节,贴近用户视角,但可能难以分析内部逻辑缺陷。例如评测机。

白箱测试

基于内部逻辑结构,分析程序代码的测试方法。它需要了解被测试软件的内部结构和工作原理,通过检查内部的逻辑、循环、分支等来设计测试,并覆盖各种可能,从而深入检测代码逻辑的缺陷,但测试成本较高。在 J u n i t Junit Junit中我们可以进行白箱测试。

1.2 主要测试类型

单元测试

验证单个功能模块或最小可测试单元的测试。通常由开发人员完成,用于发现编码和详细设计缺陷。一般是白盒测试,“代码走读”就属于单元测试。

功能测试

验证软件系统功能是否符合需求的测试。

集成测试

基于单元测试,验证模块之间或子系统之间接口和交互的测试。通常包含非渐增测试(定位错误较困难)和渐增测试。

压力测试

在负载超出正常范围的条件下进行的性能和稳定性测试。强测与互测中对于 q s p qsp qsp, q c s qcs qcs等大量连续的使用就属于此类测试。

回归测试

在修改或修复软件后验证新增和修改前的功能是否正常的测试,课程中主要体现在 b u g bug bug修复环节。

1.3 数据构造

先对 n e t w o r k network network加入一定数量的 P e r s o n Person Person,然后随机添加 P e r s o n Person Person之间的 r e l a t i o n relation relation,从而得到社交图。在 h w 11 hw11 hw11中,还需要添加 e m o j i I d emojiId emojiId后再进行会更改 e m o j i H e a t emojiHeat emojiHeat的操作。

构造一些边界值,比如tag的size为0等情况

增大数据规模,在上述思路中主要是增加 P e r s o n Person Person的数量和增加添改 r e l a t i o n relation relation的次数。

2 架构

参考往届博客和讨论区,添加了 D i s j o i n t S e t DisjointSet DisjointSet​类

  • q c i qci qci 使用 D i s j o i n t S e t DisjointSet DisjointSet中并查集的 f i n d find find
  • q b s qbs qbs D i s j o i n t S e t DisjointSet DisjointSet类中缓存维护,当 m e r g e merge merge时加1,当 m r mr mr需要重构时减1
  • q t s qts qts D i s j o i n t S e t DisjointSet DisjointSet类中缓存维护,当 a r ar ar时遍历添加 i d 1 id_1 id1 i d 2 id_2 id2的共友个数, m r mr mr时删除
  • q t v s , q t a v qtvs,qtav qtvs,qtav M y T a g MyTag MyTag类中缓存维护,方差根据公式 ∑ k = 1 n x 2 − 2 ⋅ n ⋅ E ( x ) + n ⋅ E 2 ( x ) n \frac{\sum_{k=1}^n x^2 - 2\cdot n\cdot E(x) + n\cdot E^2(x)}{n} nk=1nx22nE(x)+nE2(x)计算,每当 a t t att att d f t dft dft时进行改变(由于取整精度,若使用 D ( x ) = E ( x 2 ) − E 2 ( x ) D(x) = E(x^2) - E^2(x) D(x)=E(x2)E2(x),数据规模大时与标准答案会有1的误差)
  • q b a , q c s qba,qcs qba,qcs M y P e r s o n MyPerson MyPerson类中维护 b e s t I d bestId bestId变量,计算组合数时检查每个 A A A b e s t I d bestId bestId,其对应的 B B B是否属于 P e r s o n s Persons Persons b e s t I d bestId bestId是否对应 A A A,最后除以2即为所求
  • q s p qsp qsp D i s j o i n t S e t DisjointSet DisjointSet类中维护了 g r a p h graph graph,使用 b f s bfs bfs算法求出最短路。其中 g r a p h graph graph采用了 H a s h M a p HashMap HashMap结构, k e y key key D i s j o i n t S e t DisjointSet DisjointSet中的每个点, v a l u e value value采用 H a s h S e t HashSet HashSet,表达 k e y key key的点 i s L i n k e d isLinked isLinked的点的集合

3 性能

h w 9 hw9 hw9 写错了 d f s dfs dfs算法,使其只遍历了一层就结束,从而 w a wa wa

h w 10 hw10 hw10 b f s bfs bfs的使用较为低效致使 c t l e ctle ctle。初始选择了 A r r a y L i s t ArrayList ArrayList作为 q u e u e queue queue,使用 j a v a java java自带的 a d d add add r e m o v e remove remove操作代替 q u e u e queue queue a d d add add p o l l poll poll,这也使时间复杂度从 O ( 1 ) O(1) O(1)变为 O ( n 2 ) O(n^2) O(n2)(在最坏情况下);此外,在实现 t a g tag tag v a l u e S u m valueSum valueSum,由于认为查询次数较少而没有进行维护,只是在每次查询时进行计算,并且采用朴素的双重循环操作,从而也致使了 c t l e ctle ctle​的产生

规格与实现分离,在通读规格理解需求后,就主要体现在数据结构和算法层面。

  • j m l jml jml规格中,通常采用 i n t [ ] int[] int[]型等数组类型,而在本单元作业中,对应 i d id id的查找操作较为频繁,故基于时间考量,对该存储类型基本采用 H a s h M a p HashMap HashMap H a s h S e t HashSet HashSet。这次作业 b u g bug bug频出有一部分原因就是没有理解 A r r a y L i s t ArrayList ArrayList的实现机制,它的 r e m o v e ( ) remove() remove()操作的复杂度为 O ( n ) O(n) O(n),在删除指定变量后,会将后续变量前移,耗费的时间复杂度是较高的,在限制时间的情况下需要谨慎使用。也因此在 h w 11 hw11 hw11中将 M y P e r s o n MyPerson MyPerson中本来使用的 A r r a y L i s t ArrayList ArrayList< M e s s a g e Message Message>换为了 L i n k e d L i s t LinkedList LinkedList,在此过程中还学习到了 r e m o v e I f removeIf removeIf以简化代码。

  • j m l jml jml规格中对于 v a l u e S u m valueSum valueSum等的查询用到了多层循环结构,如果不做其他处理,面对多次查询相关值的数据,必定将导致 t l e tle tle。对于这些指令,一部分可以通过改进算法来改善,例如上一节提及的 q s p qsp qsp;一部分则需要通过缓存以实现,及新增实例变量,每当遇到修改条件时及时修正,从而使得不必在连续查询时反复重新计算。

4 J u n i t Junit Junit

构造测试数据时,需要完整覆盖 j m l jml jml的情况,对于各种异常和表现均需要测试到。

在检查 p u r e pure pure等类似需求时,可以在创建对象之处就建立一个副本,测试方法以外的操作完全相同,但同时在 M y N e t w o r k MyNetwork MyNetwork传入 M y P e r s o n MyPerson MyPerson时,需要注意传入副本的需要是 M y P e r s o n MyPerson MyPerson的副本。

在测试过程中,检验 e n s u r e s ensures ensures要求的正确性时不考虑优化,完全按照规格的方法实现。

在实际使用过程中,由于是基于 j m l jml jml规格进行测试,因此在写 J u n i t Junit Junit时实现逻辑是对 j m l jml jml的复现,与被测试代码不同,从而发现了一系列笔误,更正了自动补全时误写的变量和异常。

5 学习体会

在完成作业时,更多的收获是了解 j a v a java java A r r a y L i s t ArrayList ArrayList等容器的具体实现以及图数据结构的复习,领悟到缓存等有关降低时间复杂度的操作。对于 j m l jml jml规格的感受更多体现在 J u n i t Junit Junit的编写测试中,完全按照规格的实现进行测试更有利于查找代码中的错误。

j m l jml jml的编写操作则是在讨论课中进一步体会,(题目为编写“将 w o r d 1 word1 word1转换为 w o r d 2 word2 word2所使用的最少操作数” j m l jml jml规格),即使经过了组内讨论,有成员已经提出了很好的思路(仿照 h w 10 hw10 hw10中的最小路径编写),我在自己实现时针对插入、查找、删除操作分别编写函数,然后苦恼于如何组合和传参,但当看到其他组员编写的即为简练的 j m l jml jml规格时,我意识到自己仍困于具体的实现和方法的优化,而事实上, j m l jml jml只是一份使用逻辑语言的需求书,它需要做到的是逻辑严密,需求覆盖完备,但并不需要实现,就像最短路径规格中并没有涵盖具体的从A到B的方法,它只是设定了路径各点 i s L i n k e d isLinked isLinked的需求,从这个意义上,相较于其他单元, j m l jml jml是一份不会引起歧义的指导书。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值