OO第三单元总结

OO第三单元总结

1 测试过程

1.1 黑箱测试

黑盒测试:也称功能测试或数据驱动测试,它是已知产品所应具有的功能,通过测试来检测每个功能是否都能正常使用。

黑盒测试一般遵循以下原则:

  • 根据相应的、正确的需求设计测试用例。配置项测试依据需求规格说明,系统测试依据软件研制任务书,验收测试依据软件研制任务书或合同/协议。
  • 正确地定义等价类。等价类方法是黑盒测试的主要方法,设计测试用例时应根据输入的数据范围,正确地划分有效等价类和无效等价类。
  • 覆盖所有的功能需求。 根据测试风险来确定测试重点和优先级,确保软件的常用功能和重要功能得到充分的测试。
  • 加强接口测试。
  • 站在用户角度进行测试。尽量模拟用户的使用环境,那些对用户有价值的功能要优先、充分地测试。

1.2 白箱测试

白盒测试:又称结构测试、透明盒测试、逻辑驱动测试或基于代码的测试。(是一种动态分析法)

白盒测试方法应该遵循的原则:

  • 保证一个模块中的所有独立路径至少被测试一次。
  • 所有逻辑值均需测试真 (true) 和假 (false) 两种情况。
  • 检查程序的内部数据结构,保证其结构的有效性。
  • 在上下边界及可操作范围内运行所有循环。

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

  • 单元测试以模块为单元,以验证模块正确性和稳定性为目的,通过预先设计设计的单元测试,可以使程序员完成程序后由工具进行自动化测试,从而保证迭代后代码的正确性和稳定性。
  • 功能测试是一种黑箱测试,它针对需求编写测试用例,测试软件功能能否按照需求正确完成。这种测试一般需要测试者根据功能需求主动构造测试用例并完成测试。
  • 集成测试是功能测试的上级测试,意在测试各个单元集成后交互是否正确、协同工作是否正常。有些时候,单元测试均能正常工作时连接起来后不能正常工作,特别是多线程等条件下的集成,尤为有这种特点。
  • 压力测试指的是测试在大负载下的系统表现。这种测试主要针对代码的复杂度、服务的吞吐能力、多线程的设计正确性等方面进行测试。
  • 回归测试指的是在对程序进行迭代开发后,对其不应影响的原有功能进行测试,目的是确保修改后仍然能正常完成修改前的功能,从而保证迭代开发的正确性,防止迭代破坏原有的功能。

1.4 数据构造

我的数据构造策略主要有以下几种:
1、要避免过多的抛出异常。过多的抛异常意味着过多的无用指令,即使有一万条指令,抛了9000条异常,不如只编写2000条不抛异常指令的强度高,因为抛异常的只能测极小一部分的正确性,即异常类,甚至都不涉及性能方面的问题,所以抛异常有即可,测试全面即可,不需要多。这里可能需要在数据生成器中降低这种指令生成的概率,换个角度,即提高无异常指令的概率。
2、增加图的复杂度。这里就需要在上一点的基础上多给图添加边和节点,即ap和ar的指令多一点,同时要保证ar指令生成的概率更大。因为只有这样才能在此基础上去更好地测试其他查询指令的正确性和性能,如qbs,qci,mr等。
3、进行某一指令的压力测试。首先需要构造一个复杂度较高的图,然后一直执行某一特定的指令。压力测试那些性能要求高的指令,如qts等。
4、对规格中不易被注意到的点进行测试,如tag中的人数限制1111。·

2 架构设计

2.1 图构建策略

首先我使用HashMap<Integer, Person> 来存储相应的节点,然后我把图分成若干个连通块,使用HashMap<Integer,Integer> 来指示每个节点属于哪个块,然后用HashMap<Integer,HashSet<Person>>来表示每个连通块中的节点。对于Tag,我采取HashMap<Integer, Tag> 在每个Person中存储,同时在network中我对每个人所在的TagHashMap<Integer,HashSet<Person>>进行了存储,便于维护。
我使用的并不是并查集,而是一种连通块的思想,把可达的两个节点放在一个块中,这种写法可能会在加边的时候会有性能损失一点,当两个大小相似的块需要合并时,并查集的做法只需要修改父节点即可,而我的由于存储结构的选择,需要修改对应连通块里面的节点。但是性能损失也不会太多。

2.2 图维护策略

  • ar指令。加边的时候,我采取的策略是当两个人在两个连通块中时,将两个连通块合并,同时将其中需要修改的连通块中的所有人的指向的块号指向另一个。在这里,我将人数少的块合并到人数多的块。还要维护的是tag中的valueSum值。除此之外,还要维护的是每个人的BestAcq,只需要进行简单的判断即可。还有qbsqts两个指令相应的维护,对于qbs,需要对相应的block减少,而对于qts则需要求两个加边的人的Acq的交集,加在原有的TripleSum上。
  • mr指令。当不涉及删边的时候,只需要修改value即可。设计删边的时候,我首先判断两个节点是否还连通,如果不连通,就重新建一个块,存储相应的节点。在判断连通时,我已经把所需的节点取出来了,只需要在对应的旧块中删除和新块中添加即可。同时还要注意维护第二次作业中BestAcqtagvalueSum值。不涉及删边时,只需要对BestAcq进行简单的判断和修改valueSum值即可,如果要是删边的话,也需要对BestAcq进行简单的判断,还可能存在将改人从tag中移除,同时维护valueSum值。同时,若需要删边,qbsblock可能会增加,而qts则需要求两个加边的人的Acq的交集,在原有的TripleSum减去。

还有就是qci指令,在我视角里就是判断两个人所对应的连通块号是否相等。

对于coupleSum我并没有选择进行维护,因为维护与否都不会影响qcs的具体实现方法,也就是不会影响时间复杂度,甚至如果进行维护的话,但是没有一条qcs,那你相当于是白执行了qcs,会影响最后的性能。
以上就是我所具体的图维护的策略,主要就是涉及导armr两条对图的有影响的两条指令。

3 性能问题、规格与实现分离

3.1性能问题

三次作业中,我没有出现性能问题。但我还是分析以下性能优化的方面。
主要的性能就涉及几条指令:qciqtsqspqtvs
对于qci,如果不加优化的话,就是需要在图中进行搜索,bfs或者dfs,但是在armr过程中维护之后时间复杂度变成了O(1)。
对于qts,如果不加优化的话,会是O( n 3 n^{3} n3)的复杂度,但是在ar和mr过程中维护变成了O(1)的时间复杂度。
对于qsp,原来的话我想的是通过digkstra实现,但是性能貌似有点低,主要是不是带权边,所以bfs是最优解,我只用了单向bfs,并没有实现双向bfs,单向bfs的性能其实够用了,甚至来说,digkstra的性能也可以,虽然我没试过。
对于qtvs原来的时间复杂度会是O( n 2 n^{2} n2),如果在armr的过程中相应的维护,时间复杂度变成了O(1),但是相应的维护成本变到了O(n).

3.2 规格与实现分离

规格是一种契约化编程,它避免了自然语言描述存在二义性的问题,使得编程遵循一种规范化的过程。规格侧重于描述功能,其会引入一些中间变量和\forall和\exists等进行描述,其更重要的是将功能尽可能严谨全面地描述清楚,在编写规格时,我们往往会忽略问题的具体细节,而是将问题抽象出来,用JML语言描述。
规格并没有限制用什么样的数据结构去实现该函数,甚至说整个类,所以我们只需要在相应的规格条件下去实现函数和类,符合相应的约束条件,有合理的输出即可,不需要说严格按照规格所提供的方式去写整个函数,这样的话可能会导致性能不太高。
规格是一种约束,但是只是指引了一个方向,并没有说限制你过程中如何去做,给了程序员一个足够高的自由度,可以利用所学尽可能地去更好地实现所要求的功能。完全自由的编程是不可能的,一定是为了实现某个功能。

4 Junit测试

规格中的很多信息给出了对于函数的限制,比如pure、ensure等,我们需要对这些描述的函数的约束和所要实现的功能进行相应地测试,如对pure来说,我们要保证该函数不会对任何数据进行修改,除了局部变量,而ensure则保证了函数内部所要实现的功能,包含可能对数据进行修改,同时还有输出返回值等,我们就是要编写相应的测试代码测试这些约束和功能,同时还要编写数据生成器,使数据尽可能地覆盖全面,不留死角。测试即是将函数从高度自由化转变为一种自由与约束平衡的状态。
第一次编写junit测试其实还是非常不适应的,因为规格理解并没有那么深刻,同时数据生成也不是很全面,在经过第一次的洗礼之后,后两次编写junit测试就得心应手起来了,不论怎么改,严格按照规格所描述的一条一条验证即可。

学习体会

这个单元给我最大的教训是要注意细节,同时在官方包修改后如果自己正好写完了相应的部分一定要严格检查,否则会出大麻烦。
在这个单元的学习中,我感觉还是比较轻松的,基本上不需要特别多的思考,很多函数很快便可以实现,只有少数几个函数需要实现一定的算法,以保证性能的要求。
本单元让我了解到JML的规格化编程,前置条件、后置条件和类的不变式等,以及其带来的好处——可以避免自然语言所带来的二义性。同时严格规范了函数的功能,保证了程序的正确性。
在本单元中也对一些算法进行了学习,拓展了自己的算法的储备,也算是对以前所学算法的复习,比如并查集等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值