OO U3 JML总结——这个世界是一个巨大的/*TODO*/

张栗瑞-22373425 学生 2024-05-16 17:32:42

OO U3 JML总结——这个世界是一个巨大的/*TODO*/

题记:

 public void すみません(TodoList<JML> todo) {
     notifyAll("@all people");
     notifyAll("非常抱歉!");
     notifyAll(todo);
     notifyAll("不影响大家理解");
 }

提纲

  • 分析本单元的测试过程

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

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

    • 数据构造有何策略

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

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

  • 本单元中同学们实现了Junit测试方法,总结分析如何利用规格信息来更好的设计实现Junit测试,以及Junit测试检验代码实现与规格的一致性的效果

  • 本单元学习体会

一、分析本单元的测试过程

我测试你,与你有何相关

  1. 谈谈你对黑箱测试、白箱测试的理解

    我认为黑箱测试和白箱测试最大的不同在于:黑箱测试时代码实现对测试人员透明,白箱测试时代码对测试人员不透明。形象化来说,黑箱测试时,代码外面罩着一层黑色的箱子,从而避免其它人观察内容。

    本次作业中,我们需要对三个不同的方法进行针对jml规格的测试。我认为这种形式算作黑箱测试,因为在测试过程中,测试程序员完全不需要了解方法是如何写作的、做了哪些优化,只需要按照jml的要求调用方法,进行测试。

    典型的白箱测试类似与我们平时的debug,此时我们完全清楚自己代码的实现,并使用各种技术手段试图将bug定位到代码的具体位置。在这个过程中,不了解代码使用了哪些数据结构,不思考代码具体哪行可能有问题,就无法找到问题的解决方案。

    在我看来,白箱测试更像是黑箱测试的下一步,在互测中这种方法更加明显:我会先用大数据点投喂所有房友,观察谁的代码出现错误或者运行速度过慢(黑箱测试),然后找到他们的代码对于某个方法或者某几个方法的具体实现,最终“因材施教”,针对性地构造复杂数据点,将他们hack掉(白箱测试)。

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

    单元测试是验证软件中最小可测试单元的正确性的方法,通常针对单个函数或类的方法进行测试。这种测试的目的是确保每个单元在隔离状态下能够按照预期工作(比如Junit)。其优点在于能够发现并修复小范围的错误,提高代码质量和可维护性,并提供快速反馈,这对于持续集成和持续交付非常有帮助。

    功能测试是一种基于软件功能需求和规格说明的测试方法,主要验证软件系统的各项功能是否按预期工作。功能测试关注软件的输入和输出,不关心其内部实现,常见的类型包括黑箱测试和用户接受测试(UAT)。功能测试的优点是直接验证软件功能,确保其满足业务需求,并且测试人员不需要了解代码实现。然而,这种测试方法难以覆盖所有可能的输入和使用场景,可能无法发现性能问题和内部逻辑错误。

    集成测试则是验证不同模块或组件之间的交互和接口,确保它们能够一起正确工作。这种测试方法通过测试多个单元或模块的组合,提前发现接口错误和集成问题,确保模块之间的兼容性和协同工作。集成测试的复杂性高于单元测试,需要更多的设置和环境准备,且难以隔离错误来源。

    压力测试是一种性能测试方法,旨在评估软件在极端条件下的表现和稳定性,确定其最大负载能力和瓶颈。这种测试方法通过在高负载或极端条件下测试系统的行为,识别系统的最大处理能力和潜在瓶颈,发现性能问题和可能的系统崩溃点。压力测试需要大量的资源和环境设置,可能对系统造成压力,影响正常运行。

    回归测试是一种用于在软件修改后验证现有功能没有被破坏的方法,确保新代码没有引入新的错误。回归测试的范围可以覆盖整个系统或特定模块,特别关注修改或新功能可能影响的区域。其主要优点是确保软件在迭代和维护中的稳定性,自动化回归测试能够提高测试效率,减少人工工作量。然而,回归测试也需要维护大量的测试用例和脚本,可能会遗漏未被覆盖的功能或边缘情况。

    综上所述,单元测试、功能测试、集成测试、压力测试和回归测试各自有其特定的目标和方法,结合使用这些测试方法可以最大限度地保证软件的质量和用户满意度。单元测试确保代码的基本正确性,功能测试验证软件功能是否符合需求,集成测试检查模块间的接口和交互,压力测试评估系统在高负载下的性能,回归测试则确保软件在修改后的稳定性。通过综合运用这些测试方法,可以有效地提高软件的可靠性和质量。

  3. 数据构造有何策略

    在本单元的Junit测试中,因为每次只需要测试单个方法,可以认为除了该方法外,其它方法均实现正确,所以以下所有的数据构造方法均针对单个方法而言。

    1. 大数据 一般而言,我们认为在大数据情况下方法更容易表现出错误的答案。不妨将测试用例的规模扩大3倍或者5倍,来观察是否会出现偏差。但要注意,由于本单元需要测试的错误答案都极其简单而降智,哪怕是5个person简单地过家家都能找到所有错误,所以我认为大数据在本单元是某种意义上的负优化 。

    2. 模块化 这里的模块化特指将“数据投放过程”和“结果判断过程”分开成不同的方法,减少代码复杂度。由于结果判断方法会极大影响数据构造策略,所以我把这点列在这里。 比如,我会将数据投放过程写在测试方法主体部分中,将结果判断过程封装成一个专门的judge方法,每当数据有所改变,就judge一下。

    3. 自动化 自动化包含两部分:数据生成自动化、代码生成自动化

      • 数据生成自动化 也就是大家所说的“随机”,让程序自动实现增删边,并自己写对拍程序,实现自动生成测试样例的效果。 不过根据我和身边一些同学的测试,随机的方法往往很难在小数据量时覆盖所有情况,并且往往需要在随机时手动保证数据覆盖一些情形,而直接手搓这些情形的数据能达到更好的效果,这就显得自动化生成数据“没什么必要”。

      • 代码生成自动化 在Junit中进行测试和我们平时所说的对拍不同,Junit需要将所有输入按方法的形式写作,虽然也可以通过输入重新向+重写解析方法以达到自动化解析数据的效果,但非常麻烦。为了方便我导入数据进行评测,我用python自己写了几份生成代码的代码,以减轻手写的压力。

    通过以上三个方法,我每次Junit测试基本可以花费较少的时间达到测试效果,且大部分时间用来专心写judge(点名批评Hw11)

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

本单元我基本没有使用高级的数据结构或算法,搜索使用的是优化后的双向bfs,该动态维护的时候就手动维护一下,可以说是再普通不过,但依然侥幸以相对比较快的速度通过所有强测。这也充分说明了U3对算法的要求并不高。

在本单元项目中,我实现了一个基于社交网络的图模型,该模型允许管理和操作网络中的各种元素,如用户(Person)、关系(Relation)、消息(Message)等。

架构设计概述

整个项目的核心类是 MyNetwork,它实现了 Network 接口,并维护了多个关键数据结构以管理网络中的各种元素。主要的数据结构包括:

  • HashMap<Integer, Person> persons:用于存储所有用户。

  • HashMap<Integer, Message> messages:用于存储所有消息。

  • HashMap<Integer, Integer> emojiList:用于存储所有表情及其热度。

  • HashMap<Integer, ArrayList<Message>> emojiId2messages:用于存储每个表情对应的消息列表。

通过这些数据结构,我们可以高效地进行用户管理、关系管理、消息管理以及表情管理。

图模型的构建

MyNetwork 类中,每个用户(Person)被视为图中的一个节点,而用户之间的关系(Relation)则被视为节点之间的边。为了更好地描述和管理这些关系,我们为每个用户维护了一个 HashMap<Integer, Person> 类型的字段,用于存储该用户的所有熟人关系。这样设计的好处在于可以快速查找和更新用户之间的关系。

添加用户

addPerson(Person person) 方法中,我们首先检查用户是否已存在于网络中,如果存在则抛出异常,否则将用户添加到 persons 哈希表中。这个操作的时间复杂度为 O(1)。

添加关系

addRelation(int id1, int id2, int value) 方法中,我们首先检查两个用户是否存在且未建立关系。如果条件满足,我们在两个用户的熟人列表中互相添加对方,并更新三人组数量(tripleSum)和最佳熟人对数量(coupleSum)。这个操作的时间复杂度取决于用户的熟人数量,一般情况下接近 O(1)。

图模型的维护策略

为了确保网络状态的一致性和正确性,我们在进行关系修改和消息发送时,采取了一系列维护措施。

关系修改

modifyRelation(int id1, int id2, int value) 方法中,我们首先检查用户是否存在、关系是否存在以及两个用户是否相同。接着,我们更新关系值,并根据新旧关系值调整三人组数量和最佳熟人对数量。特别地,当关系值减少到零或以下时,我们需要删除该关系,并更新相关联的标签信息。这部分的复杂度与关系修改的频繁程度和标签数量有关。

消息发送

sendMessage(int id) 方法中,我们根据消息的类型(私信或群发)分别处理。对于私信,我们检查发送者和接收者之间是否存在关系,若存在则更新双方的社交值和金额,并处理红包消息和表情消息的特定逻辑。对于群发消息,我们检查发送者是否包含消息标签,并更新所有接收者的社交值和金额。这个过程包括从消息列表中删除消息,并更新表情热度信息。

特殊功能实现

  1. 三人组数量(tripleSum)和最佳熟人对数量(coupleSum):这两个指标是通过在添加和修改关系时动态维护的。当两个用户建立或修改关系时,我们会检查他们与共同熟人的关系情况,及时更新这两个指标。

  2. 标签管理:标签与用户之间的关联关系也被动态维护。在添加或删除标签时,我们需要确保标签的唯一性,并在删除关系时同步更新标签信息,保证数据一致性。

  3. 最短路径查询:为了计算两个用户之间的最短路径,我们实现了基于广度优先搜索(BFS)的 bfs(int id1, int id2) 方法。在调用 queryShortestPath(int id1, int id2) 方法时,我们首先检查用户是否存在,然后调用 BFS 算法查找最短路径,并返回路径长度。

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

性能方面,我的实现速度较快,在历次测试中非常幸运地没出现TLE情况

规格与实现分离是软件开发中的关键设计原则,通过明确定义系统的功能规格和接口约定,使得系统的功能与具体实现分开。这种分离带来的优势包括降低模块之间的耦合性,提高系统的可维护性和可扩展性,为软件开发的高效进行提供了基础。

首先,规格与实现分离降低了系统内部各个模块之间的耦合性。通过规格定义明确的接口和约束条件,不同模块之间可以通过这些接口进行通信和交互,而不需要了解彼此的具体实现细节。这种低耦合性使得系统更易于维护、修改和扩展,提高了代码的可读性。

其次,规格与实现分离有助于提高团队协作效率。规格文档作为沟通的桥梁,可以明确定义每个模块的责任和功能,降低了团队成员之间的沟通成本和误解风险。不同开发人员可以根据规格文档独立完成任务,而不会相互干扰或产生冲突。

另外,规格与实现分离还增强了系统的可扩展性和灵活性。系统的规格定义了系统的功能边界和行为要求,新的功能模块或组件可以根据规格进行开发,而不会影响已有模块的稳定性。这种设计风格使得系统更易于应对需求变更、功能扩展和业务需求的变化,保持系统的健壮性和可靠性。

四、本单元学习体会

有少数同学对本单元的设计颇有微词,总结下来无外乎两点:

考规格,但类自然语言

我想,本学期的助教团队也许已经对原始的JML感到些许失望,因此设计了safe这个新的关键字。

safe关键字的含义是什么呢?提到要改的改,没提到的不改…很像自然语言的思路,对吧。

其实JML里充斥着这种矛盾,一方面需要用一堆循环套循环巨细无遗地规定方法的规格,一方面需要用另一套“善意准则”期待同学们正确理解jml的规则,而两者都并不讨好。

这样的话,与其考jml,反而不如给出少数几个方法的Junit代码,要求同学们只要通过这些方法的测试即可,反而更能考察同学的设计能力和算法能力,同时也不会造成歧义。

考性能,但只考一点点

本单元的一个乱象是:在Hw9时,大量同学死磕并查集,并且没有使用lazy-tag等手段进行优化,导致强测TLE。纵观全局,并查集带来的优化在于可以将isCircle的复杂度降低到理论O(1),但对其它方法基本没有好处,并且有重建O(n^2)的隐患,似乎并不能算一个非常的正优化。

我认为产生这种现象的原因是:OO考验同学们方法设计和数据结构两方面的能力,但JML已经把同学们设计规格这条路完全堵死了。6系的同学是倾向于多花些功夫的,为了让自己心安,便一起研究起了并查集等算法,归根结底还是U3和U2的节奏截然不同导致的。我想,如果课程组愿意有一个单元考察大家学习算法、应用算法的能力,便应该在这方面多下功夫,而不是目前这个几乎任何高级数据结构都无法应用的“熟人网络”(至少改成树状结构,也许优化方向会多得多w)。如果课程组仅仅想考察大家写作JML的能力,那又何必在性能上有所限制,弄得愿意卷的同学和只想着完成的同学都不痛快。

我建议明年的OO助教可以考虑以下两种不同的方向进行优化:

  1. 既然想要考察规格,就贯彻到底喽~(bushi 抛开性能,只考方法,至少这样就不会有人骂TLE了(确信)

  2. 你要战,便来战! 设置15分性能分,痛痛快快地让同学们卷算法(前提是修好评测机)

...全文
105 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
魏新明22373300 2024-05-17
  • 打赏
  • 举报
回复

哥哥哥哥,我的代码重跑一遍强测分怎么多了15分啊

张栗瑞-22373425 学生 2024-05-17
  • 举报
回复
@魏新明22373300 godlikeGu:建议优化一下性能

301

社区成员

发帖
与我相关
我的任务
社区描述
2023年北航面向对象设计与构造
学习 高校
社区管理员
  • YannaZhang
  • CajZella
  • C_ecelia
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧