BUAA-OO 第三单元总结

测试

写好了代码,当然要检查代码的正确性了,这就是代码测试的必要性。可以说,写程序就两件事:写代码和写测试代码。

黑箱测试

黑箱测试中,我们不关心程序的代码、结构或实现细节,只专注于代码整体的正确性。具体来说,我们生成测试数据并喂给程序,检查输出是否符合预期。如果输出结果与预期结果一样,说明代码没问题;如果不一样,则表明代码有 BUG,同时我们不关心具体的 BUG。这也是我们在测试中最常用的手段。

程序的最终检测手段也是黑箱测试,用户的使用相当于黑箱测试。

黑箱测试的好处在于其数据生成不以人的意志为转移,不会被开发者的“偏见”影响测试强度,因此基本上代码里很细节的错误都要通过黑箱测试检查出来。

要我说,黑箱测试基本就足够了,不能从输出定位 BUG 的程序员不是好程序员

功能测试

功能测试核心是验证我们的代码能否正确执行需求说明书中所定义的功能。这种测试是可以通过简单的黑箱测试完成的,也就是把有限的功能输入全部跑一遍看看它的输出是否正确。

压力测试

压力测试是检查我们代码的效率是否满足要求,考察代码的时间复杂度。我们通常使用大规模的数据来进行测试。(喜欢哥哥的大数据吗.jpg)

白箱测试

与黑箱测试相反,白箱测试要求我们对代码逻辑、代码结构和工作原理有深入的了解。我们需要检查软件的内部操作,确认所有的代码和逻辑分支的正确性。在白箱测试中,我们要考虑测试的覆盖率,这一点在黑箱测试中是做不到的。因此这种测试通常由开发者执行,因为他们对自己代码和结构具有深入的了解。

白箱测试是一种开发者利用自己对代码的掌握进行的黑箱测试。白箱测试的数据还是基于开发者对自己代码的理解构造的,并不是完全随机的,所以覆盖率不能作为唯一的评判标准,毕竟一行代码被执行了不代表被检测了。

单元测试

说到白箱测试就不得不提单元测试了。单元测试测试的是每一个方法的执行效果,是一种粒度更细的测试方法。单元测试的逻辑是一种逼近的思想,也就是对搭建起城堡的一个个砖块进行考察,如果每个砖块都没问题,但城堡却塌了,说明问题出在组合的过程中,否则至少这个砖块有问题。

通过这种方法,我们可以在编写代码的过程中就完成对代码正确性的初步检测,而不用每次都对着一个超大的数据从头看起,不知所措。可以说,单元测试是一种自下而上的测试方法。

集成测试

集成测试通常在单元测试之后进行的,主要目的是发现模块间接口的缺陷。测试的目的是检查模块之间的交互是否正常。事实上,集成测试可以被看成是对 main 方法的单元测试。

回归测试

在回归测试中,我们要保证迭代过程中加入的新代码没有导致既有功能产生错误,通常会重复之前进行过的测试,用相同的数据进行测试。

数据构造策略

在本单元中,我依旧采取了随机数据测试代码正确性、特定数据测试代码效率的方法构造测试数据。

架构分析

本单元的需求和架构都比较简单,再加上有 JML 的辅助,开发难度不大,每个人的实现也大同小异。我的具体实现架构如下:

其中,Graph 可以看成是一个“影子 Network”,保存着所有人的关系,Person 类只是为了实现接口的,Graph 里面的实现是纯抽象的,也就是把人际网络直接抽象一张图,图的点是 Person 的 id,边权是 relationValue。Tag 和 Message 与图无关,不多赘述。

构建就无非是加点、加边,维护就是删边,每次请求遍历一遍图即可。这是数据结构的内容。

性能分析

本单元作业没有出现性能问题。对于大小不大于 10000 10000 10000 的测试数据,只需要保证单次请求的复杂度不大于 O ( n ) O(n) O(n) 即可。这是不难的。

规格与实现

我认为规格是指软件系统所要达到的功能和性能的详细描述,是对需求的一种抽象表达。它定义了软件的行为和设计的期望。简单来说,规格就是告诉你“应该做出什么”,而不是指导“如何去做”。与之相对的,实现则是指根据规格来构建的实际软件,包括编写代码、建立架构、设计数据结构和算法等技术细节。实现关注的是“如何去做”。

规格与实现分离的理念带来了几个好处:

  • 易开发性:通过提供一个清晰的规格,我们可以明确自己的目标,而不用纠结于无关实现的细节,比如这个对象能不能改变。
  • 可维护性:当实现需要改变时,清晰的规格文档可以告诉我们子模块的预期行为,从而避免子模块代码的实现导致父模块出现预期外的错误。
  • 可测试性:有了清晰的规格,我们可以编写测试用例来验证代码,而不用针对不同的代码阅读后再验证正确性。

学习体会

模型语言是一个很好的业务规范化工具:相对于自然语言,它对需求的描述更细致、更精确和更完整,在体现需求的同时也给我们留下了实现的自由空间。同时,模型语言形式化表述的特征也使它天然适用于代码的编写和测试。合理地运用模型语言和自然语言,可以很大程度上加快开发的速度并编写测试代码从而减少出现错误的可能性。同时,有一个统一的、规范的表述语言,也使得后续的迭代过程更方便。

但是,模型语言也有其不足,那就是对撰写模型语言句子的人和读者的水平都有较高的要求;模型语言不能代替人类思考(充其量只是把思考的压力分摊到写模型语言和实现模型语言的两拨人身上);模型语言在很大程度上需要和工具结合才能发挥其作用。

具体到 JML 和本单元的实践上,可以发现如下问题:

  • 撰写模型语言者对模型语言和需求的理解不到位。据不完全统计,本单元一共出现 14 次更正,其中 3 次为评测机错误, 4 次为 JML 代码的非合并修复,与前两单元相比可谓是遥遥领先。从这些修改上可以看出,撰写者本身能力的不足会让模型语言的严谨性等相对自然语言的优点成为拖累开发的因素。
  • 模型语言的实践需要摆脱自然语言,直接用模型语言描述需求。从一些修改(比如群发红包的数值问题)可以发现,撰写者并没有摆脱对自然语言的依赖,如果模型语言只是一种对自然语言的翻译,那还不如直接用自然语言进行描述,拙劣的模型语言翻译反而不如自然语言。
  • 模型语言和自然语言的配合应该避免模糊表述。模型语言的特点是精确、无二意性,如果为了方便使用模糊的表述(如“独一无二”,到底是任意时刻独一无二还是在时间片上独一无二呢?),向这个追求精确的系统里引入了不确定性,反而得不偿失。
  • 模型语言应该配合工具使用。模型语言的一大优点就是贴近代码,因此更容易开发相应的语言检查工具和自动化测试工具。事实上,JML 是有相关的工具的,但是由于我们使用的是魔改版的 JML,这些工具并不适用。这也是课程组容易出现错误的原因之一。
  • 模型语言应该有完整的说明文档。阅读 JML 的说明文档,会发现最后的更新日期是 2022 年,同时文档内充斥着 TODO 标识,在网络上也找不到相应的说明,显然这对撰写和阅读模型语言的人而言是致命的。

总之,我相信模型语言是一个很好的工具,也赞同课程组的教学方向;但不可否认的是,目前本单元的实践教学依然有着很大的进步空间,相信课程组将会在未来改进相关方面。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值