301
社区成员
发帖
与我相关
我的任务
分享黑箱测试:要求测试人员站在用户的角度进行测试,给出数据输入,只要代码的输出合理即可,不需要关注内部的细节与实现。这种方法通常用于功能测试与用户角度的测试。我们平常debug的方法就是这种,我们的公测与互测其实也是黑盒测试。
白箱测试:需要测试人员去检查代码内部的结构有与逻辑,通过代码分析,来保证自己的数据覆盖全部情况,无逻辑错误。主要用于单元测试与集成测试。
本单元中我们两种方式都有使用,黑箱测试我们一直在使用,对拍等,在编写junit测试时,对着JML的要求与逻辑,对每个情况进行测试便是白箱测试。

因为本次基本都是官方的架构,所以无需改变,这里不再赘述,主要是对于该网络结构进行一个解释
这次整个单元的要求其实就是维护一个网络结构,人是每个网络的节点,边就是人们之间的关系,只有有联系的人们之间才有边。
网络构建:
维护策略
本单元的难度除了读JML外,还有就是对于整个网络的维护,由于时间限制的存在,我们尽可能免去不必要的操作,我主要实现了以下几个维护方式:
并查集修改:因为需要查找连通性,但每次查找都去重新计算,深度较高的网络会有很大的负担,因此我们需要动态的去维护,由于连通只要存在路径即可,因此中间的过程不需要在意,只要存下来是否有联系,我们可以选择一个连通分量的一个点为中间联系点,只要和这个点有联系的点都是联通的,我采用了以下的方式:
public Person findFather(Person p) {
Person father = p;
while (personNet.get(father) != null) {
father = personNet.get(father);
}
if (!father.equals(p)) {
personNet.put(p,father);
}
return father;
}
这个函数函数会返回联系点,同时重新构建。因为我们涉及到删除边的操作,但删除边,无非是一个连通分量变成两个或者仍是一个,只要针对删的节点进行局部重建即可。
三角形查询:我采用的是动态维护,因为查询时遍历找三角形十分复杂,我会在增加边或者删除边时动态更新三角形的个数,只用查找边的两个节点之间是否存在连接点即可。
qtvs指令:我采用的仍是动态查询,设计了标志位,只有在删除了边或者增加了边时才会对vs进行重新计算,这样可以避免重复的计算。且因为我束缚于JML的实现,使用了近乎n^3的复杂度,其实转换一种查询方式,可以只有n^2,即优先遍历tag每个人的邻居是否在tag中,这样即使不动态维护也能满足课程组要求。
综上不难发现,我们基本采用的是动态维护策略,这种策略的核心思想其实将这条指令所承担的代价分散给其他指令,达到一种均衡的效果,或者有的方法将其分散计算比一起起算的代价要更小。
我主要是第二次作业的强测中有一个点时间性能爆炸了,因为当时并未对qtvs进行动态维护,且由于个人实现问题,出现了n^3的复杂度。我后面实现了动态维护,主要是在加边和删边以及更改value时进行局部更新,同时不更新时返回以前的值,这样可以避免大量无意义计算。
对着JML写代码,这个我觉得有点像黑箱测试,就是我们满足了JML对于前提和结果的约束,但中间的过程我们可以自己实现。这也是我们一直强调的规格与实现分离。
比如在类的属性时,使用数组表示,我们可以改成容器,甚至可以用不同的存储内容,在满足规格的基础上,要便于我们实现。
在撰写方法时,我一开始容易按照JML一条一条写,因为这可以保证我们的正确性,但这大大提高了了代码的冗杂度,以及降低可读性,后面我会先根据JML了解哪些实现,使用自己的方法来实现,而且有些地方我们的性能有一定要求,所以规格与实现分离是必要的,JML的规格往往会比较冗长。
相较于编写代码,JML规格对于Junit测试的作用我个人感觉更大,因为JML会给出相应的变量改变以及返回值要求,我们只要在junit对于JML每条ensure进行检查即可,有一个需要注意的点就是pure!
在造数据时,我并不是用随机化,感觉过于冗杂,采用的是白箱测试,注重于逻辑使用,因为我们的方法其实结果是可数的,针对每种情况构造即可,每次构造出的图其实也没有怎么复杂,一般几个点就可以。那最后一次作业举例,他要保证message不被改变,但message里不止一种message,也不止一个属性,为了防止他们其中一种被改变,我们必须构造出所有的消息类型。
我们的JML中会把所有需要检测的点告诉我们,我们的junit是为了保证方法的正确实现,所以我们只要保证了JML的ensure均被实现即可,也就是在我们的Junit中实现,是规格与实现的一致性。
这个单元总体难度较为简单,根据JML实现代码的过程比较复杂,因为JML不是自己写的,所以相当于读一份冗长的代码,又要自己写一份。
不过这个单元也是学到了一些新的性能处理方法,比如动态维护与并查集等,本来以为只要简单的抄写JML就行,其实还是有很多细节在里面。
最后是我个人的一些想法,Junit与JML很消磨时间,而且JML也一直受诟病,对于JML的作用,在写Junit的时候体现的比较好,但对于实际的项目,还是没有体会到优势,觉得课程组可以对这方面进行一定改革。