北航OO第三单元总结

测试过程

黑箱测试与白箱测试

黑箱测试,又称功能测试或行为测试。测试者只关注软件的输入和输出,而不考虑内部实现细节。测试者把软件视为一个黑箱,只需要了解它的功能规范和接口。测试方法包括等价类划分、边界值分析、错误猜测等。黑箱测试关注于验证软件是否满足需求和规格说明。

白箱测试,又称结构测试或glass box testing。测试者需要了解软件的内部结构和实现逻辑。测试时会考虑代码的控制流、数据流和逻辑结构等。测试方法包括语句覆盖、分支覆盖、条件覆盖等。白箱测试关注于验证软件的内部结构和实现是否正确。

两种方法的区别在于黑箱测试关注功能,白箱测试关注结构。黑箱测试不需要了解内部实现,白箱测试需要了解。黑箱测试更关注软件的外部行为,白箱测试更关注内部逻辑。

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

  1. 单元测试:针对软件中最小的可测试单元(如函数、类等)进行测试,目的是验证每个单元是否按照预期正确工作。测试由开发人员编写,可在开发过程的早期进行,有助于及早发现和修复代码缺陷。
  2. 功能测试:基于软件需求和规格说明进行测试,目的是测试软件的各种功能是否满足用户需求,包括输入验证、业务逻辑、输出检查等。可以使用黑箱测试方法,不需要了解内部实现。
  3. 集成测试:测试多个软件单元或模块之间的接口和交互,目的是检查各个模块能否正确集成在一起工作,可采用自底向上或自顶向下的方式进行。关注不同模块之间的数据传递和流程控制。
  4. 压力测试:在高负载或极限条件下测试软件的性能,目的是验证软件在峰值使用下的稳定性。可模拟大量并发用户、大数据量输入等,有助于发现软件的性能瓶颈和容错能力。
  5. 回归测试:在软件变更后重新执行之前通过的测试用例,确保变更没有破坏原有的功能和行为。回归测试可自动化执行,有助于提高测试效率,是持续集成和持续交付过程的重要组成部分。

数据构造策略

我在构造数据时,一条数据只会测试一个指令。我会先设置很多ap和ar指令(之所以不设置有关modify和delete的指令,是因为只用ar和ap就可以构造出任何我们想要的图,没有必要把简单的问题复杂化),如果需要at,att,am,sm等指令,也要预先加好。

一切准备工作都完成后,我就会加入待测试的指令,期间仍然会修改图的结构。我会有意识地构造不同种类的图,如只含有一个孤立点的图,所有点都连成一条线的图,放射状的图,完全图等。

不过大部分时候我并不会自己构建数据,而是使用同学搭建的评测机生成的随机数据,这样效率更高,也能找到不少问题。

架构设计

根据课程组提供的接口,我实现了八个类和十二种Exception。除此之外,我还实现了一个EmojiContainer类,用于实现和Emoji有关的updateUsed、storeEmojiId、queryPopularity、deleteColdEmoji方法。主要是为了分担一部分MyNetwork类的功能,否则实在没办法把它的行数控制在500行以下。

性能问题

性能问题大概是本次作业的重中之重了。由于课程组提供了JML,设计架构的问题就几乎不用考虑了,但若是完全按照JML,不动脑子直接翻译,肯定会超时的。为了避免超时,我认为可以从以下三个角度优化。

动态维护

第一次作业中的qbs和qts,如果完全按照JML写,每一次都需要重新统计,时间复杂度分别是O(n^2)和O(n^3),数据规模稍微大一点就会超时。经观察,我们发现qbs和qts只和relation有关,那么就可以将二者的统计值设置为类的属性,在addRelation和modifyRelation时修改统计值,在遇到qbs和qts指令时直接返回统计值。这样性能会提升很多。不过我最开始没有考虑到这个问题,强测错了一半。

第二次作业中的qtav和qtvs也可以用动态维护。这种时候就需要我们对复杂度进行合理的预估了,qtvs的复杂度是O(n^2),我原以为这样的复杂度不算高,加上这条指令动态维护时比较复杂,害怕出错,就没有使用动态维护。然而事实上,当人很多并且图比较稠密时,每次都重新遍历还是要花费很长时间的,最终该改还是要改,果然人不能怀有侥幸心理啊。

数据结构

使用合适的数据结构可以很好降低时间复杂度。首先,在id唯一时,我们没有必要像JML那样使用List存储数据,这样每次寻找都要遍历。我们可以使用HashMap,将时间复杂度从O(n)降到O(1)(当然,我觉得这个大家都能想到)

第三次作业中,由于经常需要对message进行插入和删除,相比于ArrayList,LinkedList显然是更好的选择。ArrayList的插入和删除操作需要移动其他元素,时间复杂度为O(n),LinkedList的插入和删除操作只需要修改前后节点的指针,时间复杂度为O(1)。

我设置了acquaintanceSet和emojiSet两个SortedSet。SortedSet会自动将元素按一定的顺序排列,由于它是利用二叉树实现的,每加入一个元素的时间复杂度是O(logn)。排好序后,寻找和删除就不用遍历了,可以直接找到对应的值。

算法

使用一些算法也可以很好地提升性能。例如isCircle可以使用并查集,queryShortestPath可以使用bfs或双向bfs。

Junit测试

在本单元作业中,我们需要完成Junit测试,测试课程组提供的未知bug。我觉得,我们不一定要构造出很大量的数据,但数据的覆盖性一定要强。我们要思考如何才能覆盖大多数情况。首先,我们要考虑稠密图,稀疏图,完全图等不同图对应的不同情况。其次,我们还要考虑各种临界情况,比如只有一个孤立点的情况,涉及到最后一个点的情况,接近最大值或最小值的限制等情况。

关于检测前后状态是否不变的问题,我使用的是“影子数据”方法。例如在第三次作业中,构造两个network并对它们进行完全相同的操作。这是一种在思维上偷懒的办法,可以避免麻烦的深拷贝问题。

心得体会

都说第三个单元比前两个单元简单很多,然而我并不这么认为。我反而是这个单元出错比前两个单元多。在这之中,性能问题占据大多数。这主要还是怪我自己,第一次作业,我一看这单元没有性能分,就以为不需要考虑性能问题了,就没有动脑子地完全按照JML写了,强测自然错了很多。后来想想,觉得自己挺愚蠢的。第二次作业,我决心要吸取教训,把我认为可能会超时的地方都进行了优化,可是千算万算,没有算到qtvs的用时会那么长。到了第三次作业,好不容易不超时了,又发现又出现了一些奇奇怪怪的问题,比如sendMessage没有考虑除0这些,而且第二次作业的qtvs居然还有问题,我也真是服了。

此外,我还感觉到这个单元的中测真的特别弱,以往的作业,中测能过,强测也能过大部分数据点。而现在,我感觉这中测有和没有差不多。之前和学长交流时,他建议我多用评测机测一测。可是我感觉评测机的数据覆盖也不怎么完全,而且难以测出tle的问题。写完oo作业前,我担心作业会写不完,写完后,我担心会有潜在的bug测不出来,一星期几乎都在惶惶不可终日中度过。而且这样的焦虑毫无意义,它并不能使bug减少。唉,有点难受,也不知道是大家都这样还是只有我最蠢。我又想了想,可能我在写代码时就应该尽量考虑的周全些,而不是把希望寄托在评测机上?

往好的方面想,我又撑过了一个单元,这个学期也过完了四分之三,胜利的曙光就在前方。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值