OO_UNIT3 - JML

测试过程

  • 黑箱测试 - 黑箱测试是测试人员在不了解程序内部结构和内部特性的情况下,仅依据程序的需求规格说明书,检查程序的功能是否按照需求规格说明书的规定正常使用。换句话说,黑盒测试主要是从用户的角度出发,关注软件外部结构和软件功能,通过输入数据并观察输出数据,以此来检测程序是否能正确地接收输入数据并产生正确的输出信息。在本单元作业中网站的评测就是一种黑箱测试。

  • 白箱测试 - 白箱测试是测试应用程序的内部结构或运作,而不是测试应用程序的功能(即[黑盒测试])。在白盒测试时,以编程语言的角度来设计测试案例。测试者输入资料验证资料流在程序中的流动路径,并确定适当的输出,类似测试电路中的节点。测试者了解待测试[程序]的内部结构、[算法]等[信息],这是从程序设计者的角度对程序进行的测试。在本单元中类似于我们展开的 JUNIT 单元测试。

单元测试 是一个代码块,用于验证较小、孤立的应用程序代码块(通常是函数或方法)的准确性。 单元测试旨在根据代码块背后的开发人员理论逻辑检查其是否按预期运行。 单元测试只能通过输入和捕获的断言(true 或false)输出与代码块进行交互。 单个代码块也可以有一组单元测试,称为测试用例。

功能测试 着重于检查软件是否能够正常实现功能并检查功能是否符合规格要求,确保软件输出与预期一致,能够正常实现功能,抛出异常,是否含有所有功能并达到一定性能要求。

集成测试 在单元测试之后,验证不同模块或服务之间交互的正确性。重点检查接口兼容性、数据传递及错误处理,确保整体系统协同工作无误。

压力测试 通过模拟高负载或极端操作条件来评估系统的稳定性和性能极限,如高并发访问、大数据量处理和长时间处理以及异常情况处理。

回归测试 指修改了旧代码后,重新进行测试以确认修改没有引入新的错误或导致其他代码产生错误。 自动回归测试将大幅降低系统测试、维护升级等阶段的成本。 回归测试作为软件生命周期的一个组成部分,在整个软件测试过程中占有很大的工作量比重,软件开发的各个阶段都会进行多次回归测试。

数据构造 数据构造首先要满足基本需求,然后再考虑边界情况,应用随机数据生成,在特殊情况构造特殊数据,并且要保证数据面能够覆盖所有情况,同时兼顾广度和深度。

架构设计、模型构建和维护策略

总体架构

模型构建

在第一次作业中,为了检查联通块信息,我需要用到并查集算法来代替 dfs,然后为了降低耦合性,我单独建立了 dsu 类来统筹管理并查集中的信息,在该类中用 HashMap 来存储节点的父子关系,用 find,merge 等方法封装并查集的相关操作,同时也对并查集作了路径压缩和按秩合并两种优化操作。

在第二次作业中,由于有了查询两点间最短路径的操作,我在 dsu 类中新建了一个名叫 graph 的 HashMap,来存储网络关系图的信息,graph 图中有 Network 需要维护的关系网信息,于是只需要在 graph 中进行 bfs 即可得到两点间的最短路径。

维护策略

动态维护

hw1 的 blockSum 和 tripleSum 分别代表联通块数量和三元环数量,如果使用遍历的方法,分别是 O(n^2) 和 O(n^3) 的复杂度,但是可以通过 dsu 将联通块信息动态更新,使其修改复杂度 O(log(n)) ,查询复杂度 O(1),而 tripleSum 相关可以在每次修改人与人之间的关系时动态维护每个人相关三元环数量,使其修改复杂度 O(n),查询复杂度 O(1);

hw2 中在 Tag 类中有查询 valueSum 和 ageVar 两个问题,对于方差相关,也就是计算类函数,只需要设置一个 agePowSum 变量表示年龄平方和,也是每次在加人的时候维护,这样在调用 getAgeVar() 函数时,我们只需要将 ageSum 和 agePowSum 代入即可,同样可以保证计算复杂度为 𝑂(1),而对于 valueSum,我的选择是在 MyNetwork 类中加入容器统计所有的 Tag,在每次人物关系更新时,遍历所有的 Tag,如果有包含相关人物,就将其中的 valueSum 进行更新,这样就可以做到修改复杂度 O(n),查询复杂度 O(1)。

遍历查询

第二次作业的 coupleSum 需要统计互为最佳相识的人的个数,我们只需要在 MyPerson 中对于其所有的 acquaintance 按照 value 通过比较器排序统计即可,每次更新的时候就更新自己的相识的人的队列,保证最佳相识的人一定在 TreeMap 的 firstKey 上,这样在查询 coupleSum 时就可以直接 O(n) 循环直接遍历所有人判断其是否时其最佳相识的人的最佳相识。这样的遍历操作将查询的复杂度均摊到了修改每个人的最佳相识的复杂度上,可以大大提升程序的效率。

规格和实现分离的理解

JML 规格本身的规定只考虑能够方便规格自身的描述,而不会去考虑具体实现难度或者是时间复杂度和空间复杂度,实际上是只考虑了问题本身相关最直接的相关要求,是规格具有极佳的通用性。

但是在具体实现过程中,我们则需要统筹规划、综合考虑,无论是具体实现算法,容器的选择,动态维护或是直接查询,都是给了开发者一定的自由度,让开发者去自由实现需要修改和维护的数据结构,只需要保证对外提供的接口能够正常工作即可,即减小了模块与模块间的耦合度,也使得要实现的功能可以被充分高度的优化。

JUNIT 测试

JUNIT 本身和规格要求是密切相关的,对照 JML,我们可以分析检测方法的期望功能,针对性构造数据进行检测。

在 JML 规格信息中,要确保 assignable, ensures, exception 的规格均符合要求,针对所有操作前后的上述规格进行 assert 断言检查,确保没有 assignable 发生不应该发生的变化,ensures 的所有要求得到满足,没有抛出错误的 exception,检测程序在输入数据满足前置条件的情况下完成相应方法后是否仍满足后置条件。

具体实现中我分别构建了 originNetwork 和 shadowNetwork 来避免浅拷贝带来的数据冲突问题,保证测试的正确性。

学习体会

本单元通过 JML 规格化设计结合图论等算法背景,帮助我们深入理解了 JML 规格语言和契约式编程的相关内容,既巩固了相关算法知识,也让我们意识到了形式化方法的重要性和未来应用前景,能够帮助团队建立起更加健壮和可靠的软件系统。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值