2024 BUAA OO第三单元总结

刘一鸣-19373454 2024-05-19 15:53:11

测试过程

黑箱测试、白箱测试

黑箱测试

黑盒测试(Black-box testing),软件测试的主要方法之一,也可以称为功能测试、数据驱动测试或基于规格说明的测试。测试者不了解程序的内部情况,不需具备应用程序的代码、内部结构和编程语言的专门知识。只知道程序的输入、输出和系统的功能,这是从用户的角度针对软件界面、功能及外部结构进行测试,而不考虑程序内部逻辑结构。测试案例是依应用系统应该做的功能,照规范、规格或要求等设计。测试者选择有效输入和无效输入来验证是否正确的输出。
此测试方法可适合大部分的软件测试,如集成测试(integration testing)以及系统测试(system testing)。

  • 黑箱测试也被称为功能测试,它是一种不考虑内部结构和实现的测试方法。测试者只关注输入和输出,验证系统功能是否按照需求规格书正确工作。黑箱测试的主要优点是可以从用户的角度测试系统,但缺点是可能会遗漏一些内部错误。常见的黑箱测试方法包括等价类划分、边界值分析、决策表测试等。

白箱测试

白盒测试(white-box testing)又称透明盒测试(glass box testing)、结构测试(structural testing)等,软件测试的主要方法之一,也称结构测试、逻辑驱动测试或基于程序本身的测试。测试应用程序的内部结构或运作,而不是测试应用程序的功能(即黑盒测试)。在白盒测试时,以编程语言的角度来设计测试案例。测试者输入资料验证资料流在程序中的流动路径,并确定适当的输出,类似测试电路中的节点。测试者了解待测试程序的内部结构、算法等信息,这是从程序设计者的角度对程序进行的测试。
白盒测试可以应用于单元测试(unit testing)、集成测试(integration testing)和系统的软件测试流程,可测试在集成过程中每一单元之间的路径,或者主系统跟子系统中的测试。尽管这种测试的方法可以发现许多的错误或问题,它可能无法检测未使用部分的规范。:

  • 白箱测试也被称为结构测试或逻辑驱动测试,它是一种需要了解内部结构和实现的测试方法。测试者需要知道系统的内部逻辑,了解程序的逻辑结构、路径和条件,以便设计测试用例。白箱测试的主要优点是可以发现内部错误,但缺点是测试过程可能会比较复杂。常见的白箱测试方法包括语句覆盖、判定覆盖、条件覆盖、路径覆盖等。

单元测试 & 功能测试 & 集成测试 & 回归测试

  1. 单元测试:单元测试是对软件中的最小可测试单元进行检查和验证。例如,对函数、方法、类、模块等进行测试。单元测试的目标是尽早发现程序中的问题,以便尽快修复。单元测试通常由开发人员自己编写,并且可以使用各种测试框架(如JUnit、PyTest等)来自动运行。

  2. 功能测试:功能测试是基于软件需求规格说明进行的测试,主要是对软件系统的功能进行全面的测试。功能测试的目标是确保软件的每个功能都按照预期工作。功能测试通常由专门的测试人员进行,并且可以使用各种测试工具(如Selenium、Appium等)来自动化测试过程。

  3. 集成测试:集成测试是在所有模块单元测试完成后,将这些被测试单元组合成一个整体后进行的测试。集成测试的目标是发现模块间的接口问题。集成测试可以采用自顶向下、自底向上或沙盒等方法进行。

  4. 压力测试:压力测试是为了测试系统在极限条件下的性能和稳定性,例如在大量用户同时访问或大量数据处理时的表现。压力测试的目标是发现系统的性能瓶颈,并确保系统在高负载下仍能正常工作。压力测试通常使用专门的性能测试工具(如LoadRunner、JMeter等)进行。

  5. 回归测试:回归测试是在修改了旧代码或者增加新代码后,重新对程序进行测试,以确保修改没有引入新的错误或者导致旧的错误复发。回归测试的目标是确保软件的稳定性和可靠性。回归测试可以手动进行,也可以使用自动化测试工具进行。

数据构造策略

      数据构造策略是测试中的一个重要部分,它可以帮助我们有效地选择测试数据,以尽可能多地覆盖可能的情况。以下是一些常见的数据构造策略:

  1. 边界值分析:这种策略是基于一个观察,即错误往往出现在输入或输出的边界上。因此,我们应该选择在边界上的值,以及刚刚超过边界的值进行测试。

  2. 等价类划分:这种策略是将输入数据划分为几个等价类,然后从每个等价类中选择一些代表性的值进行测试。等价类可以是有效的(即预期的输入),也可以是无效的(即预期之外的输入)。

  3. 错误推测:这种策略是基于测试人员的经验和对系统的理解,推测可能出现错误的地方,然后针对这些地方进行测试。

  4. 正交表测试:这种策略是使用正交表来选择测试数据,以保证在尽可能少的测试用例中覆盖所有的参数组合。

  5. 因果图测试:这种策略是使用因果图来表示输入和输出之间的关系,然后根据因果图来选择测试数据。

架构设计

因为有JML规格的存在,大家作业的整体框架大差不差(都是按照课程组给定的规格架构写的),只是在某些特定方法上有差异。但由于我的第三次作业MyNetwork过长,于是我将query的所有具体实现方法合并为一个新类,其余完全按照JML规格完成。

并查集优化

关于qbs和qci查询指令,可以采用并查集进行优化。

用Hashmap<Person,Person>存储people,key对应当前person,value对应当前person的祖先节点。

  • 在加人的时候增加节点,将该节点的祖先设为自己,同时增加一个连通块
  • 在加关系的时候,如果两个人的祖先不同,则合并,同时减少一个连通块
  • 在删关系的时候,先广搜第一个人,把所有搜到的人的祖宗设为这个人,如果没有搜到第二个人则说明两个人不联通,连通块数少一个,广搜第二个人,再把所有搜到的人的祖宗设为这个人
  • 查询两个人是否联通,即判断这两个人的祖先节点是否相同

图模型维护

采用并查集维护图中点以及Tag的各类信息,每次点或边变化时更新,查询时直接输出结果。

性能问题

在这三次作业中没有出现TLE的bug。第二次作业的强测5一测时CTLE,二测后通过。

规格与实现的分离

在软件开发中,规格实现是两个关键的概念,它们之间的分离是非常重要的。

实现主要关注的是程序的编写,它涉及到“数据结构 + 算法”的组合。开发者可以根据需要自由地设置数据结构和算法来完成代码的实现。

规格则是一种设计层面的语言,它主要关注的是系统的完备性。规格通过定义各种条件(这些条件通常是互补的)来约束方法的前置和后置条件,从而确保程序的正确性。值得注意的是,规格并不需要考虑实际实现的性能问题,因为规格语言无法直接转化为代码。

通过Junit测试,我们可以检测代码的实现是否严格遵循了每一项规格。这样,我们就可以确保代码的正确性,同时也可以提高代码的可维护性和可读性。

Junit

  1. 理解规格:首先,需要充分理解规格的内容和要求。这包括了解预期的输入、输出和行为。

  2. 设计测试用例:基于规格设计测试用例。数据生成采用随机方式 ,测试用例应覆盖所有可能的场景,规格的前置条件,副作用范围,后置条件都要进行针对性的测试。

  3. 编写测试代码:使用JUnit框架编写测试代码。每个测试方法通常对应一个测试用例。使用断言(assertions)来验证代码的行为是否符合预期。

  4. 运行测试并解析结果:运行测试并查看结果。如果所有测试都通过,那么代码实现可能与规格一致。如果有测试失败,则需要检查代码并找出问题所在。

学习体会

这一单元的主题是规格化设计,要求我们理解JML规格化语言,并且能基于规格编写代码。对于规格的理解,规格仅仅是一种约定,针对规格的代码实现可能会有许多种方法,因此在实现代码的时候就需要特别注意代码的效率。JML看似给出了实现方法,但是具体的实现方式还需要自己斟酌考虑,以达到更高的效率。此外在代码实现之后,我们还需要回到规格中去,根据规格的要求构造测试数据对我们的代码正确性和性能进行进一步的检测。

总而言之,经过这一单元的学习,我对一个基于JML规格的项目的开发流程基本熟悉,学会了阅读和书写较为严谨的JML规格,同时也掌握了阅读规格实现代码并且进行正确性验证的能力,最重要的是掌握了规格和实现分离的关键思想,这些对我以后的学习工作都将有重要的作用。

...全文
149 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

301

社区成员

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

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