BUAA OO第三单元博客

发布时间 2023-05-16 22:24:27作者: 柳浩东110111

对本单元测试过程的分析

  • 对黑箱测试、白箱测试的理解

黑箱测试(Black Box Testing)是一种测试方法,它关注测试系统的外部行为,而不考虑内部实现细节。黑箱测试是基于需求和规格说明书进行的,测试人员不需要了解系统的内部结构或代码。测试人员将系统视为一个黑箱,只关注输入和输出之间的关系,通过给定的输入数据,验证系统是否按照预期的方式产生正确的输出。

黑箱测试不要求测试者对代码具体的技术细节有足够的了解,然而,黑箱测试的可信程度依赖于测试样例的编写对系统内部路径的覆盖率,受限于覆盖率,可能无法检查出一些BUG

白箱测试(White Box Testing)是一种测试方法,它基于对系统的内部结构、代码和逻辑进行测试。白箱测试需要测试人员了解系统的内部工作原理,以便设计测试用例和验证程序的正确性。测试人员可以检查代码覆盖率,执行路径分析,进行代码审查等。具体到本单元来说,每一次的作业的OKTest就是一个典型的白箱测试,通过深入的了解方法内部的实现,根据JML的每一个ensures,确定代码的每个部分都在按照预期的情况来工作。

白箱测试的优点是,它可以深入了解系统的内部,验证系统的每个部分是否按照预期工作。它可以发现代码错误、逻辑错误、性能问题等。然而,白箱测试需要测试人员具备技术能力和对系统的深入理解。

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

单元测试:单元测试是对软件中最小的可测试单元进行测试,通常是函数、方法或类。它旨在验证单元的行为是否符合预期,通过隔离测试单元,可以更容易地定位和修复问题。在本单元的作业中,我通过编写main方法和JUNIT测试,对qlm,ap , mr, qcs 这些函数都做了单元测试。也在单元测试中检查出了qcs函数没有除以2的问题。

功能测试:功能测试是测试软件的各个功能是否按照需求规格说明书的要求正常工作。它通过模拟用户的操作和输入数据来验证功能的正确性。本单元的OKtest就是一个功能测试。

集成测试:集成测试是将已经通过单元测试的模块或组件结合起来进行测试,以验证它们在组合后的交互是否正确。集成测试可以发现模块之间的接口问题和集成错误。在本单元的测试中,我在mr函数里使用到了对qcs的维护函数,在使用自编数据集测试的时候,检查出并解决了空指针异常的问题。

压力测试:压力测试是通过模拟高负载、高并发或异常条件来测试系统的性能稳定性和容错能力。它可以验证系统在压力下是否能够正常工作,并确定系统的瓶颈和性能极限。典型例子就是从中测到强测。

回归测试:回归测试是在软件进行修改或更新后重新执行已经通过的测试用例,以确保修改不会破坏原有的功能和引入新的错误。它可以验证系统的稳定性和兼容性。本单元中,我对qcs和qlm的具体实现做了多次优化改进,每次改进后,都用原来的数据集进行了回归测试。

梳理本单元的架构设计,分析图模型构建和维护策略

  本单元是根据JML来实现代码,虽然说从整体上看实现的都大同小异,但是要提高效率,避免TLE,最最有效的方法就是把一切能够维护的数据都采用动态维护,查询的时候只是简单的返回,从而避免在强测一万条中有几千条反复查询指令带来的TLE。具体来说,我把所有原先使用arraylist的JML表述尽量都换成了Hashmap表示,为queryCoupleSum函数维护了一个自建BestAcquaintaince变量,为queryTripleSum也维护了int变量。可以说是能存的都存了。

  模型构建和维护方面,我使用了并查集来维护Hashmap<Integer,Person> People。使用并查集有以下几个优势:

  1. 使用并查集,在添加人的时候十分方便,只要加入一个节点,并把它的根节点设置为自身即可。

  2. 使用并查集,在处理人与人之间添加关系的时候十分的方便,只要将两个人对应的节点的根节点设置为其中任意一个人即可。

  3. 使用并查集,在处理人与人之间是否认识的时候十分方便,只要判断两个人对应的节点的根节点是否相同即可。

  4. 使用并查集,可以在构建的过程中就维护qbs和qts所需的值,这样这两个函数就不用再重新算了。

  然而,并查集模式在处理第二次作业的mr的时候遇到了困难,在由于并查集的存储方式实际上已经破坏了原来的图的结构,因此在进行删边的时候就不能只是简单的删去,而要是每一次删去边后都要按照全新的方式来再次构建并查集,时间上就会TLE。后来我采用了折中的方法,在并查集对应的结构体UnionFind中,维护了一个Pair数组,该数组存储了所有的并查集之间的合并记录,相当于再次构建并查集的时候的一份指导书,删边后,只要在指导书里删掉对应的合并记录,然后根据指导书来一步步构建并查集即可。这样就省去了再次遍历每个Person的acquaintance数组的步骤,复杂度也随之下降。

分析作业中出现的性能问题及其修复情况,对规格与实现分离的理解

  在第二次的作业中,有一个点出现了TLE的情况,检查后发现是对qcs的压力测试,原本我是严格根据JML,在qcs使用的时候计算出对应的值,结果导致了TLE。后来我使用自建BestAcquaintance类来动态维护qcs,实现在mr的时候更新,在qcs的时候仅查询。这样就避免了TLE。其实这样的问题可以用一句话总结,就是大部分的系统里查询的指令数量是远远大于修改的指令的数量的,对需要查询的某些参数的修改和维护最好都要放在修改指令内部实现里。

  规格与实现分离:在规格与实现分离的理念下,规格指的是对系统功能、需求和行为的描述,可以是需求文档、规格说明书等。规格描述了系统应该做什么、具有哪些特性以及用户的期望。实现则是指将规格转化为实际的软件代码或系统的具体实现。包括了算法、数据结构、编程语言、框架和库等技术细节。举例来说,假设我们要设计一个购物网站,对规格的描述可能就是:

  • 用户能够将商品添加到购物车。
  • 用户能够从购物车中删除商品。
  • 用户能够查看购物车中的商品列表。
  • 用户能够进行结算并完成订单。

而具体如何实现,用何种语言实现,用何种数据结构,何种算法实现,规格都不应该对实现做出要求。购物车可以是一个arraylist,也可以是一个hashmap,对某一商品id的查询可以是使用遍历查询,也可以先排序再使用二分查询。这些都是实现的一部分。换句话说,只要满足了规格的要求的实现都是有效的实现。有效的实现中,可扩展性高,性能高的就是优秀的实现。

OK测试对于检验代码实现与规格的一致性的作用,有何改进何建议

  OK测试包含了测试者希望的几个方面,从某种角度来说,只要通过了测试者提供的Ok测试,就可以说编写的函数满足了测试者的要求,是一个和规格一致的函数。

  改进建议,在第二次的规格Ok测试中,仅仅提供BeforeData和AfterData的数据,对于JML中的ensure 13, ensure 14是一定满足的,换句话说,是无法测试的。而且测试用例的编写也要求覆盖每个测试点,如果有覆盖不完整的问题,则可能是一次无效的Ok测试。

本单元学习体会

  本次单元的学习中,我深刻体会到了规格和实现之间的不同,也认识到了优秀程序员和普通程序员之间的差别真正在哪。这个单元相当于模拟了一次项目的开发,从阅读项目要求文档,到具体实现;再到各个函数的单元测试,JUNIT,JML语言的学习使用,根据客户要求来实现的一点点的扩展;最后再为实现的方法编写Oktest测试,不断改进性能。我切实感觉到了自己综合水平的提升。对于并查集,最短路径算法的学习,动态维护的意识强化也给我带来了很大的帮助。