BUAA OO 2023 第三单元总结
一、测试
1.黑箱测试、白箱测试
黑箱测试
黑箱测试将被测试的软件系统视为一个黑盒子,只关注系统的输入和输出,而不考虑内部的实现细节。黑箱测试的目的是验证系统是否按照规格说明书或需求文档的要求正常工作,不需要了解系统的内部结构和算法。测试人员通常不知道被测系统的具体实现方式,他们根据功能需求设计测试用例,输入不同的数据或操作,然后检查系统的输出是否符合预期。
白箱测试
白箱测试关注软件系统的内部结构和实现细节。测试人员需要了解系统的源代码、设计文档等内部信息,以便设计测试用例并评估系统的覆盖率和质量。白箱测试的目的是发现系统中的逻辑错误、代码缺陷和性能问题,以及验证系统在不同的执行路径下的行为。
综合而言,黑箱测试和白箱测试是互补的测试方法。黑箱测试关注系统的功能和用户视角,验证系统是否按照预期工作;而白箱测试关注系统的内部结构和实现细节,帮助发现系统中的问题。
2.单元测试、功能测试、集成测试、压力测试、回归测试
单元测试
单元测试:是一种针对软件系统中最小可测试单元的测试方法。它主要关注对独立的代码模块(通常是函数、方法或类)进行测试,以验证其在给定输入下的预期行为。
功能测试
功能测试:用于验证软件系统的功能是否符合规格说明书或需求文档中的规定。它关注系统在各个功能模块或模块间的交互上的正确性。
集成测试
集成测试:是将多个独立单元或模块组合在一起进行测试的方法。它的目的是验证不同组件之间的接口和交互是否正常,确保各个模块在集成后能够正确地协同工作。
压力测试
压力测试:用于评估系统在负载较大、资源受限或异常情况下的性能表现的一种测试方法。压力测试通过模拟大量用户并施加较大的负载压力,检测系统的响应时间、资源利用率、稳定性和可扩展性等方面的表现。它的目的是找出系统在极限条件下的性能瓶颈,为系统的优化和调优提供指导。
回归测试
回归测试:是在对软件进行更改或修复后执行的测试,以确保已有功能仍然正常工作,不受新更改的影响。回归测试主要关注已经通过的测试用例,以验证软件的修改没有引入新的错误或破坏已有的功能。回归测试可以使用自动化测试工具来重复执行之前通过的测试用例,节省时间和人力成本。
3.测试工具的使用
使用了其他同学写好的测评机进行对拍,但发现仍然无法全部通过强测,说明测评机构造数据时没有构造更加复杂的数据进行测试。
4.数据构造的策略
可构造大数据来增加测试压力,如对一个复杂度较高的方法,可以增加很多个人,然后不断调用该方法,来判断是否存在超时的可能。
5.对规格与实现分离的理解
在规格与实现分离的理念中,功能规格指的是对系统的功能需求和行为进行描述的部分,它关注的是"是什么",而不关注"如何实现"。而实现是指将规格转化为可执行的代码或软件系统的具体实现细节。实现关注的是"如何实现",即通过编写代码、设计算法和选择合适的数据结构等方式,将规格中描述的功能转化为实际可运行的代码。
6.OK测试
OKTest是一个用于验证JML规格的工具。在OKTest中,我们需要检查JML规格中的各个部分,例如requires、ensures、assignable和pure。在编写OKTest时,必须严格按照JML的格式来编写代码,不能出于性能考虑而使用某些算法,只有这样才能实现对JML规格的全面覆盖。
二、第一次作业
1.架构分析与实现
并查集
采用并查集,将两个具有relation的Person放入同一个集合中。
public int find(int x) {
int root = x; // 寻找x祖先节点保存到root中
while(f.get(root) != root) {
// System.out.println( root + " " + x);
root = f.get(root);
}
while(x != root){ // 路径压缩,把x到root上所有节点都挂到root下面
int original_father = f.get(x); // 保存原来的父节点
f.put(x, root); // 当前节点挂到根节点下面
x = original_father; // x赋值为原来的父节点继续执行刚刚的操作
}
return root;
}
动态维护的策略
(1)queryBlockSum()
记录一个CntFinalNode作为并查集中不同集合的个数。每次addPerson时,将其数值加一;同时addRelation时,如果Person1和Person2原本属于两个不同的集合,添加关系后集合数便会减一,因此将其数值减一。
(2)queryTripleSum()
记录一个CntTri,每次addRelation时,遍历Person1的Friends,每有一个和Person2有关系,就给CntTri加一。
2.bug分析
最开始并没有采用动态维护的方法,也没有使用测评机进行对拍,导致出现了很多离谱的复杂度,最终超时。同时使用的并查集也并未进行路径压缩。
3.总结
本次作业对JML规格有了最初一步的了解,但由于算法选择出现了一些问题,强测和互测得分不佳。同时对JML的一些繁琐的描述较难理解。
三、第二次作业
1.架构分析与实现
对并查集的维护
并查集是该单元的一个比较重要的结构,因此对它的维护也很重要。该次作业需要对person之间的关系进行删除操作,这种操作破坏了并查集原有的结构。这里我采用的方法是每次删边的时候dfs搜索Person1,退出dfs的时候如果Person2没有被搜索到,那么新建里一个集合,并在搜索Person2的时候将所有Person放入该集合之中。
动态维护的策略
(1) queryBestAcquaintance()
给每个Person记录一个MaxvalueId,每次给这个Person 增加朋友时对其进行更新,同时给这个Person减少朋友时,重新便利一遍这个人的朋友集合,来更新MaxvalueId。
(2) queryCoupleSum()
采用O(n)的算法,遍历people集合,记录一个ans,如果 people.get( NowPerson.MaxValueId ).MaxValueId == NowPerson.getId(),就给这个ans加上1。最终返回ans / 2即为答案。
(3) queryGroupValueSum()
对每个group维护AgeSum,每次给这个group增加或减少人的时候,相应的改变AgeSum的值
(4) queryGroupAgeVar()
并未采用动态维护的策略。遍厉这个group的每个person,计算出AgeVar。
2.bug分析
本次作业的一个严重 bug 就是 Person 的 ValueSum 没有在 delPerson 的时候合理的维护,导致引发一系列问题。
3.总结
本次作业出现了严重的bug,严重影响强测分数。同时对JML规格的理解有所提升,对于复杂的描述也可以清晰地分析。
四、第三次作业
1.架构分析与实现
魔改版dijkstra
这是本次作业的一个重要的算法,是实现 queryLeastMoments()的关键。queryLeastMoments函数,翻译一下就是找到包含该Person的一个三元以上的环,返回这个环中所有Person的value。这里我采用的是讨论区中的算法,即记录每个点的最短路、次短路以及该路的出点,并且用当前点的最短路和次短路不断更新其他点的最短路和次短路。
public void update(MyPerson PrePerson, int u, int s, int dist, int origin) {
for (int v : PrePerson.Friends.keySet()) {
Path NowPath = Nodes.get(v);
MyPerson NowPerson = people.get(v);
if (NowPath.Vis) continue;
if (dist + PrePerson.queryValue(NowPerson) < NowPath.d1) {
if (u == s) {
NowPath.d1 = dist + PrePerson.queryValue(NowPerson);
NowPath.origin1 = v;
}
else {
if (origin != NowPath.origin1) {
NowPath.origin2 = NowPath.origin1;
NowPath.d2 = NowPath.d1;
}
NowPath.d1 = dist + PrePerson.queryValue(NowPerson);
NowPath.origin1 = origin;
}
} else if (dist + PrePerson.queryValue(NowPerson) < NowPath.d2) {
if (origin != NowPath.origin1) {
NowPath.origin2 = origin;
NowPath.d2 = dist + PrePerson.queryValue(NowPerson);
}
}
}
}
update(PrePerson, u, s, PrePath.d1, PrePath.origin1);
if(PrePath.d2 < (1 << 30) )
update(PrePerson, u, s, PrePath.d2, PrePath.origin2);
2.bug分析
本次强测中出现了超时的问题,这是由于我的dijkstra算法并没有用堆优化,导致产生了n^2的复杂度,面对大数据的时候便会超时。
3.总结
本次作业对图论的理解有所提高,同时使用了魔改版的dijkstra算法。但由于没有使用堆优化,是本次作业的一大失误。