北航面向对象设计与构造第三单元规格化设计总结

本单元的测试过程

本单元的主题是规格化设计,有了规格的要求我们可以干很多事情,虽然有很多规格方面的限制,但是对于程序的测试因为规格的存在而变得更加方便了。接下来我就将谈一谈我对于规格测试相关过程经历的理解。

谈谈我对黑箱测试、白箱测试的理解

黑箱测试和白箱测试是两种不同的测试方法,虽然有很多不同点,但是总目标是增强程序的质量,提高程序软件的鲁棒性,保证程序的正确性。

黑箱测试

黑箱测试主要是根据不同的输入来检测输出是否正确。但是面对多样的复杂的输入模式和输入条件,黑箱测试毕竟难以覆盖到所有的情况 。所以,黑箱测试只能证明你的程序存在着什么问题,但是并不能说明你的程序一定就是正确的。这确实是一个只能证伪但不能证明的问题。

但是,在本单元的前两次作业当中,输入的模式较为简单明确,并且排列组合所有的情况总数较少,通过了黑箱测试就可以保证我的程序是没问题的。可是到了第三次作业时,由于多种情况的加入,测试情况呈指数级增长,因此一定会出现测不全的方法。我身边的同学就出现了经过黑箱测试没问题了,就没管交上去了,然后胡测被测出来的情况。

白箱测试

白箱测试是指直接检查代码和上下文的逻辑,看每一步和每一个模块是否功能正确。在本单元当中,由于规格的存在,我们可以根据jml规格来一条一条检查我们的代码。但是这种方法也存在缺陷,就是当程序的规模过大时,对人的精力的消耗也是呈指数级上升的。

好在有一些方法的规格就两三行,对着规格写程序和检查程序也算方便。对于复杂度方法,就可以考虑白箱测试和黑箱测试相结合来进行检测了。

将两者结合起来

这两者的关系就像辩证原理中的两方一样,若顾此失彼都不会达到最好的测试效果。因方法而异猜是考虑问题的正确之道。简单的方法用白箱测试,复杂度高的方法白箱黑箱搭配着来方为良计。

诚然,在生活的其他方面,我们不仅不能只关注问题的一个方面,有效的方法可以都试试。

对单元测试、功能测试、集成测试、压力测试、回归测试的理解

除了黑箱测试和白箱测试,还有许多中别的方法的测试,包括本文即将要讨论的单元测试、功能测试、集成测试、压力测试以及回归测试。

单元测试

单元测试是指转本针对某一个设计单元进行测试,比如我就对第三次作业中的sendMessage方法进行测试,专门构造关于这个方法的测试点,并且将黑箱测试与白箱测试相结合,综合检测这个模块单元的正确性。最终应用这样的方法,在规格和执行结果的双重正确保障之下,我顺利的通过了第三次作业的强测。

功能测试

功能测试就如其字面意义一样,需要我们保证每个函数的功能是正确的。要达到功能正确,第一点要做到的就是在编写函数时就要有很强的质量意识,我需要保证我的函数结构每一行的代码都完全正确。但即使如此,在最后测试的时候仍然会不可避免的出现一些不可粗心的地方。这也正是我们进行功能测试的重要性。

功能是一个函数的基本中的基本,抛开正确谈性能从来就是空中楼阁。

集成测试

将所有的单元测试的情况都集成在一起,就变成了集成测试。

集成测试的主要关注点就是一个综合性。对于集成测试而言,我的策略就是随机生成各种数据,但是在生成数据点的时候要保证数据点的有效性,尽量少的出现异常,而且要保证数据的强度。保证数据的全面性。尽量做到覆盖全部的方面。

压力测试

在本次的强测当中,除了集成测试,更关注的一个方面就是压力测试。在强测中的数据有一大半都涉及到了压力测试。压力测试是指对于时间复杂度比较高的函数进行同一时间多次调用的操作,以验证函数在极端压力情况下的正确性和性能。

在本次作业当中,尤其是前两次的作业,对于性能的要求比较高,每一个指令执行的复杂度都要控制在O(n)以内,否则将无法通过压力测试。

在构造压力测试数据点时,由于本地的时间与评测机时间的不一样,我们对于时间是敏感度最好从算法的实现方面检测,也就是白箱测试。构造测试数据时也可以同时生成很多条一样的、高复杂度的数据指令,进行压力测试。

回归测试

在进行产品的迭代之后,我们常常将目光着眼于新添加的功能,可能忽视了传统功能的正确性和性能。回归测试就是来解决这个问题的。回归测试的含义就是对过去的功能进行再测试,以保证不引进新的错误,能够有效增加迭代开发的鲁棒性 

在每一次面向对象的作业当中,都有回归测试的身影。在bug修复阶段,我们不仅仅会对没有通过的强测点和胡测点进行检测,也会对已经通过的强测点进行检测,目的就是为了保证修改bug之后不引进新的bug。

因此,回归测试的数据构造策略就是选择上一次迭代作业的评测数据再次进行检测,若没问题则基本认为没有问题。

数据构造的策略

在本单元中,除了正常完成作业以外,我们也被要求完成JUnit单元测试的模块。

这部分就是构造测试数据对官方给出的错误/正确代码进行检测,检测的数据点需要有一定强度。于是我们在生成数据的时候既需要有稠密图的东西,又需要有稀疏图的方面,考差了数据生成的全面性。

但是单元测试确实与全局测试不同,更精,因此针对某个方法考虑的数据构造起来也就更简单。最后也是顺利的通过了中测中的JUnit测试部分。

本单元的设计架构,图形建模和维护策略

在本单元中,我们的主要任务是维护一个社交网络,在这个人与人构成的网络当中,每个人都有自己的好好友,他们彼此连接,形成了一个大的社交网络。在这个网络之下的个人,他们之间会有不同的亲密度,他们也会对自己的好友进行分组,也会对自己的好友发送普通消息、红包消息和表情包,改变着每个人的社交活跃度。

这是我第三次迭代之后的类图:

但是对于一些复杂的查询操作,我们不可能对其进行一遍又一遍的遍历社交网络,而是需要从头开始维护一些关键的数据,在查询的时候结合中间的维护变量进行处理。

为此我维护了许多变量,对于querytriplesum的方法维护了triplesum的变量便于直接返回函数的值,维护了每个人的最好的朋友方便找到最好的朋友,维护了含有这条emoji的消息方便删除等等。

性能问题及其修复,浅谈规格与实现分离的理解

对于性能的考虑,我们有些方法的实现并不能按照规格朴素的方法来进行编写,否则会出现大量的TLE。所以我们考虑用空间换时间,将需要的变量存到数组当中去,维护好一些变量,在更新的时候同样做好维护的工作,就可以优雅的解决时间长的痛点。

如何利用规格来更好实现JUnit的测试,以及JUnit测试检验代码与规格的一致性的效果

关于根据规格的检测,我小有体会。若这个方法是查询方法,那一般都是pure的方法,对于这一类方法的检测,只需分别调用一遍待检测的方法和根据规格而实现的方法,然后比对两个结果是否相同即可,这是为了检测后置条件是否满足规格。同时也记得检查不变式的正确性。

若这个方法是一个更新操作,那么在检测的时候就需要先对调用之前的数据进行备份,然后调用这个方法,对调用方法后的更新的数据检查,检查的依据就是看更新后的数据是否满足后置条件,若满足,则没问题。很多同学在此处会陷入一个误区,觉得是不是我可以将备份的数据进行相关的操作,然后与调用方法后数据进行对比,若这些数据都一样,那么我可以认为这个方法是正确的。其实这种检测的方式是错误的,因为如果你方法的实现就是错误的话,在检测的时候的方法也一定是错误的,用错误的方法检测错误的方法,这是绝度不能接受的,因为检测的结果没有任何意义。

学习体会

本单元确实是有史以来最简单的单元了,但是在一开始上手的时候仍然会感觉有些许吃力,原因不是在于规格难以理解,而是对于图的一些算法没有理解。但是在学习了两个周之后就感觉jml特别容易好上手,三次作业的强测也是没有任何问题,户厕也没有出现任何bug,这很好。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值