301
社区成员
发帖
与我相关
我的任务
分享
单元测试是针对软件的最小功能模块进行测试的方法。在这种测试中,开发人员会编写针对每个函数或方法的测试用例,以验证其在各种输入条件下的正确性。单元测试的目的是尽早发现和解决代码中的错误和缺陷,以确保软件的各个功能模块能够独立地正常工作。
功能测试是对整个软件系统的功能进行测试的方法。在功能测试中,测试人员会根据需求规格说明书编写测试用例,并通过输入不同的数据或操作软件的不同功能来验证软件是否满足设计要求。功能测试的目的是确保软件能够按照用户需求的要求正常运行,并能够正确地处理各种情况。
集成测试是在单元测试之后,将各个功能模块组装在一起进行测试的方法。在集成测试中,测试人员会验证各个模块之间的接口和交互是否正常,并且整个系统能够正常协作。集成测试的目的是确保各个模块之间的集成能够正常工作,不会产生冲突和错误。
压力测试是对软件系统在高负载和大并发情况下进行测试的方法。在压力测试中,测试人员会模拟大量用户同时访问系统,并且增加系统负载,以评估系统的性能和稳定性。压力测试的目的是找出系统的瓶颈和性能问题,并且确定系统在高负载情况下的性能指标。
回归测试是在软件系统进行修改或升级后,重新运行之前的测试用例以验证修改是否引入新的错误或导致原有功能出现问题的方法。回归测试的目的是确保在对软件进行修改或升级后,原有的功能和性能没有受到影响。回归测试一般会在每次修改或升级后进
以稠密图为基础,尽量覆盖jml描述里的每一个分支,举个简单的例子,对于ap指令,可以设置异常概率为0.2,使得random到概率区间时,add网络中已经存在的人。同时适当提高查询指令的比例。
def add_relation(self, designated1, designated2):
seed = random.random()
id1 = 0
id2 = 0
value = random.randint(-3, 3)
if(designated1!=None and designated2!=None):
# 指定
id1 = designated1
id2 = designated2
elif(self.cur_person_index == 0):
id1 = self.persons[random.randint(0, command_limit + 30)]
id2 = self.persons[random.randint(0, command_limit + 30)]
elif(seed < ar_id1_exc_prob):
# person1 异常
id1 = self.persons[random.randint(self.cur_person_index, command_limit + 30)]
if(random.random() < 0.5) :
id2 = self.persons[random.randint(0, self.cur_person_index - 1)]
else :
id2 = self.persons[random.randint(self.cur_person_index, command_limit + 30)]
elif(seed < ar_id2_exc_prob):
# person2 异常
if(random.random() < 0.5) :
id1 = self.persons[random.randint(0, self.cur_person_index - 1)]
else :
id1 = self.persons[random.randint(self.cur_person_index, command_limit + 30)]
id2 = self.persons[random.randint(self.cur_person_index, command_limit + 30)]
else:
id1 = self.persons[random.randint(0, self.cur_person_index - 1)]
if(random.random() < 0.1):
id2 = id1
else :
if(random.random() < 0.5 and len(self.relation_dict) != 0):
keys = random.sample(list(self.relation_dict.keys()), 1)
id1_1 = keys[0][0]
id1_2 = keys[0][1]
if(len(self.double_edges_dict.get(id1_1).keys() & self.double_edges_dict.get(id1_2).keys())==0 and self.add_relation_dirty==0):
# 增加三元组概率
self.add_relation_dirty = 1
self.inputs.append(self.add_relation(id1_1, self.persons[random.randrange(0, self.cur_person_index)]))
self.inputs.append(self.add_relation(id1_2, self.persons[random.randrange(0, self.cur_person_index)]))
self.add_relation_dirty = 0
id2 = self.persons[random.randint(0, self.cur_person_index - 1)]
if(id1 != id2):
edge = tuple((min(id1, id2), max(id1, id2)))
if(edge not in self.relation_dict):
self.add_edge(edge, value, id1, id2)
else :
id2 = id1 + 1
return f'add_relation {id1} {id2} {value}'
针对每次作业中实现复杂度可能较高的方法,手捏测试点。比如对valueSum的处理,也许有的同学处理得不好,可以在大量投放queryValueSum指令。
架构设计如下:

总体架构已经由JML给出,因此接下来描述架构实现细节和图的策略。
对连通块:使用并查集维护,通过按秩合并和路径压缩提升效率。删边时,采用用时重建+dfs染色的方法,局部重建并查集。用时重建意味着用空间换取时间,需要注意增删边之间的关系,在重建的时候采用visited数组记录下已经完成的点,避免无脑反复重建。
对三元组:在关系变化的时候,进行动态维护。
对最短路径,使用BFS方法。图是无权图,所以不必使用Dijkstra算法。
对ValueSum,可以采用动态维护的方法。在MyPerson中增加成员变量includedTags,代表着该成员所在的Tag(不包括成员掌控的Tag),在关系变动的时候,在通知includedTags中的所有Tag进行ValueSum的维护。
对BestAccquaince,采用动态维护的方法,在MyNetwork中维护HashMap: bestIds,在关系变动时,记录下双方此时的BestId。
使用ArrayList的Contains方法,却没有意识到它和HashMap的ContainsKey方法的不同。只需更换数据结构就能解决这个问题,但这也提醒了我在使用方法之前要先查看源码,确认时间复杂度。除此之外,还有偷懒导致的ValueSum维护问题,上文已提及修复方法。
如果按照JML规格实现,可能会出现多重循环等复杂度极高的算法。事实上,为了规格的清晰性和准确性,其表述往往采用朴素的方法,实现可行性极低。
因此实现时要做的是,理解规格,找到高效的同义替换方法。
逐行比对规格进行测试,不能遗漏任何一个分支或变化或者不变。
具体表现在:
由于Junit直接面向规格编写测试,在测试数据有一定的强度的背景下,个人认为Junit检验代码实现与规格的一致性的效果是不错的。
面向JML编程时,满目是规格表述细节,这时需要特别注意形成自己的设计总览(CO精髓。必须足够细心并且考虑全面,不能忘记自己增加的部分。
在Junit测试时,用户代码完全不可见使得我的多疑心加重,导致在检查成员变量不变性时束手束脚。第一次接触黑箱测试的体验不甚顺利,确实引发了我对规格与实现之间的思考。